- Main Page
- Namespaces
- Classes
- Files
- Related Pages

# /Users/fpy/titan-1-5-MBARI/Mers/Executives/DeductiveController/Observation/DiscreteObservationConverter.cpp

    00001
    00002 //
    00003 // Copyright (c) 2004           Model-based Embedded and Robotic Systems Group
    00004 // All Rights Reserved          Massachusetts Institute of Technology
    00005 //
    00006 // This software is provided as is. Model-based Embedded and Robotic Systems
    00007 // (MERS) group does not assume any responsibility.
    00008 //
    00010
    00011 #include "DiscreteObservationConverter.h"
    00012
    00013 #include <iostream>
    00014 #include "ConversionNodes.h"
    00015 #include <Mers/Utils/Exceptions/UnsupportedOperationException.h>
    00016 #include <Mers/Interfaces/ContinuousVariable.h>
    00017 #include <Mers/Interfaces/DiscreteVariable.h>
    00018 #include <Mers/Interfaces/DiscreteValue.h>
    00019
    00021 #include <stdio.h> //for sprintf.  change to String class and remove this...
    00022 #include <string.h>
    00023 #define FAKE_VARIABLE_UID 1
    00024 #define FAKE_VALUE_UID 0
    00025
    00027
    00028 using namespace Mers::Executives::DeductiveController::Observation;
    00029 using Mers::Executives::DeductiveController::DCInterface;
    00030 using Mers::Utils::Lang::String;
    00031 using Mers::Utils::Exceptions::UnsupportedOperationException;
    00032 using Mers::Interfaces::ContinuousVariable;
    00033 using Mers::Interfaces::DiscreteVariable;
    00034 using Mers::Interfaces::DiscreteValue;
    00035 using std::map;
    00036 using std::set;
    00037 using std::vector;
    00038 using std::ifstream;
    00039 using std::ostream;
    00040 using std::cout;
    00041 using std::cerr;
    00042 using std::endl;
    00043
    00045 // Constructors & Destructors
    00047
    00048 DiscreteObservationConverter::DiscreteObservationConverter(
    00049         const char * fileName)
    00050   : ObservationTransformationInterface(), m_CurrentLine(0)
    00051 {
    00052   //debug
    00053         /*m_SensorClasses[0] = "BatteryVoltage";
    00054   m_SensorClasses[1] = "Laser";
    00055   m_AvailableSensorInstances[0] = 1;
    00056   m_AvailableSensorInstances[1] = 180;*/
    00057
    00058         int maxLength = sizeof(m_ConfigFileName) / sizeof(m_ConfigFileName[0]);
    00059   strncpy(m_ConfigFileName, fileName, maxLength);
    00060         m_ConfigFileName[maxLength - 1] = '\0';
    00061 }
    00062
    00064
    00065 DiscreteObservationConverter::~DiscreteObservationConverter()
    00066 {
    00067         t_CVarDiscMap::iterator itDMap;
    00068         for(itDMap = m_DiscritizationMap.begin();
    00069                 itDMap != m_DiscritizationMap.end(); ++itDMap) {
    00070                 VariableLookupNode * vNode = (*itDMap).second;
    00071                 delete vNode;
    00072         }
    00073         m_DiscritizationMap.clear();
    00074 }
    00075
    00077 // ObservationUpdateListener interfaces.
    00079
    00080 void DiscreteObservationConverter::update(ValueIdentifier value)
    00081 {
    00082         throw new UnsupportedOperationException("This class does not yet support update()",
    00083                 __FILE__, __LINE__);
    00084 }
    00085
    00087
    00088 void DiscreteObservationConverter::update(ContinuousVariableIdentifier varID,
    00089         double value)
    00090 {
    00091         throw new UnsupportedOperationException("This class does not yet support update()",
    00092                 __FILE__, __LINE__);
    00093 }
    00094
    00096 // ObservationInterface interfaces.
    00098
    00099 DiscreteObservationConverter::ValueIdentifier
    00100 DiscreteObservationConverter::getCurrentState(DiscreteVariableIdentifier varID)
    00101 {
    00102         throw new UnsupportedOperationException("This class does not yet support getCurrentState()",
    00103                 __FILE__, __LINE__);
    00104 }
    00105
    00107
    00108 double DiscreteObservationConverter::getCurrentState(
    00109         ContinuousVariableIdentifier varID)
    00110 {
    00111         throw new UnsupportedOperationException("This class does not yet support getCurrentState()",
    00112                 __FILE__, __LINE__);
    00113 }
    00114
    00116 // Other functions.
    00118
    00119 void DiscreteObservationConverter::addObservationInterface(
    00120         ObservationInterface * obsInterface)
    00121 {
    00122         throw new UnsupportedOperationException("This class does not yet support addObservationInterface()",
    00123                 __FILE__, __LINE__);
    00124 }
    00125
    00127
    00128 void DiscreteObservationConverter::connectTitanInterface(
    00129         ObservationUpdateListener * pTitan )
    00130 {
    00131         addUpdateListener(pTitan);
    00132 }
    00133
    00135
    00136 void DiscreteObservationConverter::observe(
    00137         ContinuousVariableIdentifier observationID, double observationValue)
    00138 {
    00139         // First update our current state.
    00140
    00141         // Find our current state.
    00142         t_CVarStateMap::iterator itState = m_CurrentStateMap.find(observationID);
    00143
    00144         // If this wasn't found, we don't know anything about this variable.
    00145         if(itState == m_CurrentStateMap.end()) {
    00146                 return;
    00147         }
    00148
    00149         // Update our current state.
    00150         (*itState).second = observationValue;
    00151
    00152         // Update any continuous variable listeners.
    00153         updateListeners(observationID, observationValue);
    00154
    00155         // Now see what we can do about updating any discrete state.
    00156
    00157         // See if we have a discrete version of this variable.
    00158         t_CVarDiscMap::iterator itDisc = m_DiscritizationMap.find(observationID);
    00159
    00160         // If this wasn't found, then we don't know how to discritize this
    00161         // variable.
    00162         if(itDisc == m_DiscritizationMap.end()) {
    00163                 return;
    00164         }
    00165
    00166         // Get the domain that is used for conversion.
    00167         DomainLookupNode * domConv = (*itDisc).second->pDomainList;
    00168
    00169         // Loop until we find what we are looking for or run out of options.
    00170         while(domConv != NULL) {
    00171                 // If our value is in the bounds of this node, use this node.
    00172                 if( (domConv->rangeLowBound <= observationValue) &&
    00173                                 (domConv->rangeHighBound > observationValue))
    00174                 {
    00175                         // We found it - update our listeners and exit.
    00176                         updateListeners(domConv->m_dVal);
    00177
    00178                         // Debug: Indicate the conversion we made.
    00179                         cout << "Queued observation: var = " << observationID->getName() <<
    00180                                 " val = " << domConv->m_dVal->getName() <<
    00181                                 " Sensor reading = " << observationValue << endl;
    00182
    00183                         // All done.
    00184                         return;
    00185                 }
    00186
    00187                 // Didn't find what we were looking for.  Check the next node.
    00188                 domConv = domConv->pNext;
    00189         }
    00190
    00191         // If we made it this far, there exists a mapping but we could not
    00192         cerr << "WARNING: Value " << observationValue << " of sensor " <<
    00193                 observationID->getName() << " does not have a discritization." <<endl;
    00194 }
    00195
    00197
    00198 DiscreteObservationConverter::ContinuousVariableIdentifier
    00199 DiscreteObservationConverter::getObservationUID(char * observationName,
    00200         int observationIndex)
    00201 {
    00202         // See if we can find this name.
    00203         t_SensorMap::iterator itSensor =
    00204                 m_SensorMap.find(t_SensorData(observationName, observationIndex));
    00205
    00206         // If we found it, return it, otherwise return the invalid identifier.
    00207         if(itSensor != m_SensorMap.end())
    00208                 return (*itSensor).second;
    00209
    00210         // Didn't find it - return NULL - the invalid ID.
    00211         return NULL;
    00212 }
    00213
    00215
    00216 int DiscreteObservationConverter::initialize(char * robotSensorClasses[],
    00217         int *robotAvailInst, int numRobotClasses)
    00218 {
    00219         // For each sensor, create a continuous variable.
    00220         for(int i = 0; i < numRobotClasses; ++i) {
    00221                 int numInstances = robotAvailInst[i];
    00222                 char * instancePrefix = robotSensorClasses[i];
    00223
    00224                 // Make sure we have at least one instance.
    00225                 if(numInstances <= 0) {
    00226                         cerr << "The sensor class '"  << instancePrefix << "' had no instances."
    00227                                 << endl;
    00228                         return -1;
    00229                 }
    00230
    00231                 // For each instance, load a continuous variable.
    00232                 for(int j = 0; j < numInstances; ++j) {
    00233                         // The name of our continuous variable.
    00234                         String cVarName;
    00235
    00236                         if(numInstances == 1) {
    00237                                 // If we have exactly one instance, our continuous variable name
    00238                                 // will not have an index number.
    00239                                 cVarName = instancePrefix;
    00240                         } else {
    00241                                 // Otherwise, add the instance number.
    00242                                 cVarName = instancePrefix;
    00243                                 char buf[32];
    00244                                 sprintf(buf, "%d", j);
    00245                                 cVarName += buf;
    00246                         }
    00247
    00248                         // First, make sure that we don't already have this variable.
    00249                         ContinuousVariableIdentifier cVarID =
    00250                                 getContinuousVariable(cVarName.c_str());
    00251
    00252                         // See if we found it.
    00253                         if(isValid(cVarID)) {
    00254                                 cerr << "Error: variable '" << cVarName << "' is already defined." <<
    00255                                         endl;
    00256                                 return -1;
    00257                         }
    00258
    00259                         // Create our new continuous variable.
    00260                         ContinuousVariable * cVar = new ContinuousVariable(cVarName.c_str());
    00261
    00262                         // Add our new continuous variable to the list.
    00263                         addContinuousVariable(cVar);
    00264
    00265                         // Add a state for this variable.
    00266                         m_CurrentStateMap.insert(t_CVarStateMap::value_type(cVar, 0));
    00267
    00268                         // Add a mapping from sensor data to this state.
    00269                         m_SensorMap.insert(t_SensorMap::value_type(
    00270                                 t_SensorData(instancePrefix, j), cVar));
    00271                 }
    00272         }
    00273
    00274         // Open the config file that was specified now that we know what
    00275         // we're converting from.
    00276   ifstream f(m_ConfigFileName);
    00277         // Load the config file.
    00278   return useConfigFile(f);
    00279 }
    00280
    00282
    00283 void DiscreteObservationConverter::print(ostream & out)
    00284 {
    00285         out << "Continuous Variables (" << mContinuousVars.size() << ')' << endl;
    00286         set<ContinuousVariable *>::iterator itCVars;
    00287         for(itCVars = mContinuousVars.begin(); itCVars != mContinuousVars.end();
    00288                 ++itCVars) {
    00289                 out << (*itCVars)->getName() << endl;
    00290         }
    00291
    00292         out << "Discrete Variables (" << mDiscreteVars.size() << ')' << endl;
    00293         set<Mers::Interfaces::DiscreteVariable *>::iterator itDVars;
    00294         for(itDVars = mDiscreteVars.begin(); itDVars != mDiscreteVars.end();
    00295                 ++itDVars) {
    00296                 out << (*itDVars)->getName() << endl;
    00297         }
    00298 }
    00299
    00301
    00302 bool DiscreteObservationConverter::SensorDataComparator::operator()(
    00303         t_SensorData p1, t_SensorData p2) const
    00304 {
    00305         int ret = strcmp(p1.first, p2.first);
    00306         if(ret < 0)
    00307                 return true;
    00308         else if(ret > 0)
    00309                 return false;
    00310         return p1.second < p2.second;
    00311 }
    00312
    00314
    00315 int DiscreteObservationConverter::useConfigFile(ifstream &configStream)
    00316 {
    00317
    00318   char word[512];
    00319   char c;
    00320
    00321         // We cannot replace our existing configuraiton with a new one when
    00322         // loading a config file because we cannot un-register discrete
    00323         // variables at the moment.  If we're asked to do so, warn that the
    00324         // data is being appended.
    00325         if(!m_DiscritizationMap.empty()) {
    00326                 cerr << "Warning: Appending config file data to existing converter data."
    00327                         << endl;
    00328         }
    00329
    00330         // Keep reading until we get a failure (Such as invalid file or end
    00331         // of file).
    00332   while (configStream)
    00333         {
    00334                 // Skip any spaces.
    00335                 c = skip(configStream);
    00336                 // See if we've found an '!'
    00337                 if(c == '!')
    00338                 {
    00339                         // If so, we're all done.
    00340                         cout << "Processed config file.\n" << endl;
    00341                         return 0;
    00342                 }
    00343
    00344                 // Otherwise, we should see '$'
    00345                 if(c != '$')
    00346                 {
    00347                         displaySyntaxError("\'$\'");
    00348                         return -1;
    00349                 }
    00350
    00351                 // Get the next word (token)
    00352                 c = getWord(configStream, word);
    00353
    00354                 // See if there is some white space to skip.
    00355                 if(isWhiteSpace(c))
    00356                         c = skip(configStream);
    00357
    00358                 // Make sure that the token is followed by a color ':'
    00359                 if (c != ':')
    00360                 {
    00361                         displaySyntaxError("\':\'");
    00362                         return -1;
    00363                 }
    00364
    00365                 // Skip any spaces that may remain.
    00366                 c = skip(configStream);
    00367
    00368                 // A '{' character indicates that this variable has multiple
    00369                 // instances.
    00370                 if(c == '{')
    00371                 {
    00372                         // Compound variable.
    00373                         configStream.putback(c);
    00374                         if(processCompoundPlantVar(configStream, word) == -1)
    00375                                 return -1;
    00376                 }
    00377                 else
    00378                 {
    00379                         // Simple variable.
    00380                         configStream.putback(c);
    00381                         if(processSimplePlantVar(configStream, word) == -1)
    00382                                 return -1;
    00383                 }
    00384
    00385         }
    00386   cout << "Processed config file..\n" << endl;
    00387   return 0;
    00388 }
    00389
    00391
    00393
    00394 bool DiscreteObservationConverter::isDigit(char c)
    00395 {
    00396         // True if this is a digit.
    00397         return ((c >= '0') && (c <= '9')) || (c =='-') || (c == '.');
    00398 }
    00399
    00401
    00402 bool DiscreteObservationConverter::isWhiteSpace( char c)
    00403 {
    00404         // True if this is whitespace.
    00405         return (c == ' ' || c == '\t' || c == '\n');
    00406 }
    00407
    00409
    00410 char DiscreteObservationConverter::skip(ifstream & input)
    00411 //skips white space.  returns first non-ws
    00412 {
    00413         char c;
    00414         // Read a character
    00415         input.get(c);
    00416
    00417         // Keep reading as long as we're reading white space.
    00418         while(isWhiteSpace(c) && input)
    00419         {
    00420                 // If we found an end of the line, make sure we keep count.
    00421                 if(c == '\n')
    00422                         ++m_CurrentLine;
    00423
    00424                 // Get the next character.
    00425                 input.get(c);
    00426         }
    00427         return c;
    00428 }
    00429
    00431
    00432 char DiscreteObservationConverter::getWord(ifstream & input, char * storage)
    00433 //stores a string literal.  returns first non letter
    00434 {
    00435         char c;
    00436
    00437         // Skip any spaces.
    00438         c = skip(input);
    00439
    00440         // Run so long as we still read word characters (Alpha-numeric, plus
    00441         // '_').  We should probably also include a maximum string-length
    00442         // with storage.
    00443
    00444         // alpha
    00445         while((('a' <= c) && (c <= 'z')) || (('A' <= c) && (c <= 'Z')) ||
    00446                 // numeric
    00447                 (('0' <= c) && (c <= '9')) ||
    00448                 // and '_', '-', and '.'
    00449                 (c == '_') || (c =='.') || (c=='-'))
    00450         {
    00451                 // Store the letter and the move to the next spot.
    00452                 *(storage++) = c;
    00453                 // Get the next letter.
    00454                 input.get(c);
    00455         }
    00456
    00457         // Null-terminate the string.
    00458         *storage = '\0';
    00459         // See if we read an end-of-line character so we can keep count.
    00460         if(c == '\n')
    00461                 ++m_CurrentLine;
    00462         // Return the last character.
    00463         return c;
    00464 }
    00465
    00467
    00468 void DiscreteObservationConverter::displaySyntaxError(const char *expected)
    00469 {
    00470         // Prints a string indicating there was a syntax error and the line
    00471         // on which it occurred.
    00472         cerr << "Syntax error near line " << m_CurrentLine << ": "
    00473                                 << "Expected " << expected <<endl;
    00474 }
    00475
    00477
    00478 int
    00479 DiscreteObservationConverter::processSimplePlantVar( ifstream &configStream,
    00480         char* word )
    00481 {
    00482         // Process a simple variable declaration.
    00483         char c;
    00484
    00485         // Find the continuous variable we have for (word, 0)
    00486         t_SensorMap::iterator itSensor = m_SensorMap.find(t_SensorData(word, 0));
    00487
    00488         // See if we found it.
    00489         if(itSensor == m_SensorMap.end()) {
    00490                 // We didn't find it - we don't know anything about this sensor.
    00491                 cerr << "Error: The sensor '" << word << "'[0] does not exist.  "
    00492                         "Referenced at line " << m_CurrentLine << endl;
    00493                 return -1;
    00494         }
    00495
    00496         // Get the continuous variable of interest to us.
    00497         ContinuousVariableIdentifier cVarID = (*itSensor).second;
    00498
    00499         // Load the next token (mapped discrete variable name).
    00500         c = getWord(configStream, word);
    00501
    00502         // Skip any white space to get the next real letter.
    00503         if(isWhiteSpace(c))
    00504                 c = skip(configStream);
    00505
    00506         // Make sure we find a '{'
    00507         if(c != '{')
    00508         {
    00509                 displaySyntaxError("\'{\'");
    00510                 return -1;
    00511         }
    00512
    00513         // See if we already have this variable.  Each discrete variable can
    00514         // only be mapped to once.
    00515         DiscreteVariableIdentifier dVarID = getDiscreteVariable(word);
    00516
    00517         // See if we found this variable.
    00518         if(isValid(dVarID)) {
    00519                 cerr << "Error: multiple plant variables mapped to the same discrete "
    00520                         "variable " << word << " see line " << m_CurrentLine << endl;
    00521                 return -1;
    00522         }
    00523
    00524         // Create a new Discrete Variable.
    00525         Mers::Interfaces::DiscreteVariable * dVar =
    00526                 new Mers::Interfaces::DiscreteVariable(word);
    00527
    00528         // Add this variable to our list.
    00529         addDiscreteVariable(dVar);
    00530
    00531         // Create a new domain.
    00532         DomainLookupNodeData * current = new DomainLookupNodeData();
    00533
    00534         // Load the domain mapping information
    00535         if(processRangeBlock(configStream, current) == -1)
    00536                 return -1;
    00537
    00538         // Create our variable lookup node.
    00539         VariableLookupNode * varNode = new VariableLookupNode(dVar);
    00540
    00541         // Instantiate this data
    00542         instantiateDomainData(*varNode, current);
    00543
    00544         // Add a lookup between this continuous variable and the new
    00545         // discrete variable.
    00546         m_DiscritizationMap.insert(t_CVarDiscMap::value_type(cVarID, varNode));
    00547
    00548         // Debug: Print out completion of this routine.
    00549         cout << "Processed simple plant var." << endl;
    00550         return 0;
    00551 }
    00552
    00554
    00555 int DiscreteObservationConverter::processCompoundPlantVar( ifstream &configStream, char *word)
    00556 {
    00557         char c;
    00558
    00559         // Loading a compound variable - multiple sensor entries are available here.
    00560
    00561         // Skip any white space.
    00562         c = skip(configStream);
    00563
    00564         // Make sure we find a '{'
    00565         if (c != '{')
    00566         {
    00567                 displaySyntaxError("\'{\'");
    00568                 return -1;
    00569         }
    00570
    00571         // We will store all the VariableLookupNodes that we load during
    00572         // this thread into this vector so we can assign them all the same
    00573         // lookup table.
    00574         vector<VariableLookupNode *> varList;
    00575
    00576         // Process mappings block.
    00577         bool done = false;
    00578         while(!done)
    00579         {
    00580                 // Skip any white space.
    00581                 c = skip(configStream);
    00582
    00583                 // We expect a number (index) now.
    00584                 if(!isDigit(c))
    00585                 {
    00586                         displaySyntaxError("a plant variable index (integer)");
    00587                         return -1;
    00588                 }
    00589
    00590                 // Put our number back on the stream.
    00591                 configStream.putback(c);
    00592
    00593                 // Read in our low index
    00594                 int lowIndex, highIndex;
    00595                 configStream >> lowIndex;
    00596
    00597                 // Skip any spaces that follow the number.
    00598                 c = skip(configStream);
    00599
    00600                 // We expect a '-' or ':' after the first index.
    00601                 if (c == '-')
    00602                 {
    00603                         // Skip any white space.
    00604                         c = skip(configStream);
    00605
    00606                         // We expect another number (index).
    00607                         if(!isDigit(c))
    00608                         {
    00609                                 displaySyntaxError("a plant variable index (integer)");
    00610                                 return -1;
    00611                         }
    00612
    00613                         // Put back the number we read on the stream.
    00614                         configStream.putback(c);
    00615                         // Read in our high index.
    00616                         configStream >> highIndex;
    00617                         // Make sure the low index is in fact smaller than the high
    00618                         // index and that the low index is positive.
    00619                         if( (lowIndex >= highIndex) || lowIndex < 0)
    00620                         {
    00621                                 cerr << "Error: invalid domain in mapping near line " <<
    00622                                         m_CurrentLine << endl;
    00623                                 return -1;
    00624                         }
    00625
    00626                         // Skip over any white space.
    00627                         c = skip(configStream);
    00628
    00629                         // We expect a ':' now.
    00630                         if (c != ':')
    00631                         {
    00632                                 displaySyntaxError("\':\'");
    00633                                 return -1;
    00634                         }
    00635
    00636                         // Load our domain.
    00637                         int status =
    00638                                 loadCompoundDomain(configStream, word, lowIndex, highIndex, varList);
    00639
    00640                         // Check the status of the domain load.
    00641                         if (status == -1)
    00642                                 // An error occurred.
    00643                                 return -1;
    00644                         // Indicates that we found the '}' at the end.
    00645                         done = (status == 1);
    00646
    00647                 } else if (c == ':') {
    00648
    00649                         // This is a single variable index.  Check that it is non-negative.
    00650                         if(lowIndex < 0)
    00651                         {
    00652                                 cerr << "Error: invalid domain in mapping near line " <<
    00653                                         m_CurrentLine << endl;
    00654                                 return -1;
    00655                         }
    00656
    00657                         // Load our domain.
    00658                         int status =
    00659                                 loadCompoundDomain(configStream, word, lowIndex, lowIndex, varList);
    00660
    00661                         // Check the status of the domain load.
    00662                         if (status == -1)
    00663                                 // An error occurred.
    00664                                 return -1;
    00665                         // Indicates that we found the '}' at the end.
    00666                         done = (status == 1);
    00667
    00668                 } else {
    00669
    00670                         // Invalid character.
    00671                         displaySyntaxError("\'-\' or \':\'");
    00672                         return -1;
    00673                 }
    00674         }
    00675
    00676         // Now get the domain mappings. Any valid variable UID will do.
    00677
    00678         // Skip any spaces.
    00679         c = skip(configStream);
    00680         // Make sure we find a '{'
    00681         if (c != '{')
    00682         {
    00683                 displaySyntaxError("\'{\'");
    00684                 return -1;
    00685         }
    00686
    00687         // Create a new node to store the data.
    00688         DomainLookupNodeData * domainDataHead = new DomainLookupNodeData;
    00689
    00690         // Process the range block
    00691         if(processRangeBlock(configStream, domainDataHead) == -1)
    00692         {
    00693                 // We encountered an error - cleanup after ourselves.
    00694                 if(domainDataHead != NULL)
    00695                         delete domainDataHead;
    00696                 return -1;
    00697         }
    00698
    00699         // For each mapped variable, create a domain for the variable and
    00700         // record its domain data.
    00701         for (size_t i = 0; i < varList.size(); ++i) {
    00702                 // Get our updated variable.
    00703                 VariableLookupNode * varNode = varList[i];
    00704
    00705                 instantiateDomainData(*varNode, domainDataHead);
    00706         }
    00707
    00708         // All done.
    00709         return 0;
    00710 }
    00711
    00713
    00714 int DiscreteObservationConverter::processRangeBlock( ifstream &configStream,
    00715         DomainLookupNodeData * current)
    00716 {
    00717         char word[512];
    00718         DomainLookupNodeData *start;
    00719         bool done = false;
    00720         double rangeStart, rangeFin;
    00721         char c;
    00722
    00723         // Record the node at which we started our domain.
    00724         start = current;
    00725
    00726         // Loop until done.
    00727         while(!done) {
    00728                 // Skip any white space.
    00729                 c = skip(configStream);
    00730
    00731                 // Make sure we find a number or a negative sign.
    00732                 if(!isDigit(c) && c != '-')
    00733                 {
    00734                         displaySyntaxError("a digit.");
    00735                         return -1;
    00736                 }
    00737
    00738                 // Put back our digit.
    00739                 configStream.putback(c);
    00740                 // Read in the start of the range.
    00741                 configStream >> rangeStart;
    00742                 // Skip any white space
    00743                 c = skip(configStream);
    00744                 // We expect a '-' between the ranges.
    00745                 if( c != '-')
    00746                 {
    00747                         displaySyntaxError("\'-\'");
    00748                         return -1;
    00749                 }
    00750
    00751                 // Skip over any white space.
    00752                 c = skip(configStream);
    00753
    00754                 // Make sure our next character is again a number or negative sign.
    00755                 if(!isDigit(c) && c != '-')
    00756                 {
    00757                         displaySyntaxError("a digit.");
    00758                         return -1;
    00759                 }
    00760
    00761                 // Put our digit back on the stream.
    00762                 configStream.putback(c);
    00763                 // Read in the end of the range.
    00764                 configStream >> rangeFin;
    00765
    00766                 // Skip any white space.
    00767                 c = skip(configStream);
    00768
    00769                 // We expect this to end with a ':' character.
    00770                 if( c != ':')
    00771                 {
    00772                         displaySyntaxError("\':\'");
    00773                         return -1;
    00774                 }
    00775
    00776                 // Get the next word.
    00777                 c = getWord(configStream, word);
    00778
    00779                 // If it is followed by any white space, skip the white space.
    00780                 if (isWhiteSpace(c))
    00781                         c = skip(configStream);
    00782
    00783                 // If we are at another digit, put it back.
    00784                 if(isDigit(c))
    00785                         configStream.putback(c);
    00786                 // Otherwise, if we're done, indicate that we're done.
    00787                 else if (c == '}')
    00788                         done = true;
    00789                 // Otherwise print an error message.
    00790                 else {
    00791                         displaySyntaxError("\'}\' or more ranges");
    00792                         return -1;
    00793                 }
    00794
    00795                 // Make sure that our range is in the proper order and non-zero width.
    00796                 if(rangeStart > rangeFin)
    00797                 {
    00798                         cerr << "Error: invalid range.  Ranges must be of the form A - B : "
    00799                                 "<Discrete Value>" << endl << "where B >= A." << " Line #" <<
    00800                                 m_CurrentLine << endl;
    00801                         return -1;
    00802                 }
    00803
    00804                 // Check that our range map only sends a single observation to a
    00805                 // single observation.
    00806                 if(rangeOverlap(rangeStart, rangeFin, *start ))
    00807                 {
    00808                         cerr << "Error: overlapping range: " << rangeStart << '-' << rangeFin <<
    00809                                 " for value " << word << " around line " << m_CurrentLine << endl;
    00810                         return -1;
    00811                 }
    00812
    00813                 // Record the mapping for this continuous variable to a discrete
    00814                 // value.
    00815                 current->rangeLowBound = rangeStart;
    00816                 current->rangeHighBound = rangeFin;
    00817                 current->setName(word);
    00818
    00819                 // Make room for another value, if we're not done.
    00820                 if(!done)
    00821                         current->pNext = new DomainLookupNodeData;
    00822                 else
    00823                         current->pNext = NULL;
    00824
    00825                 // Move to the next value.
    00826                 current = current->pNext;
    00827         }
    00828
    00829         // All done.
    00830         return 0;
    00831 }
    00832
    00834
    00835 bool DiscreteObservationConverter::rangeOverlap(const double rangeStart,
    00836         const double rangeEnd, const DomainLookupNodeData &head )
    00837 {
    00838         //checks all nodes except the last node in the list (the "working" node)
    00839
    00840         // If we reach a node that has no successor, we're done.
    00841         if(head.pNext == NULL)
    00842                 return false;
    00843
    00844         // We overlap if the two ranges overlap.  We don't overlap if one
    00845         // ends before the other starts or the one starts after the other
    00846         // ends.
    00847         bool overlap =
    00848                 !((head.rangeHighBound <= rangeStart) ||
    00849                 (head.rangeLowBound >= rangeEnd));
    00850
    00851         // If we have overlap, return true.
    00852         if(overlap)
    00853                 return true;
    00854
    00855         // Otherwise, keep looking.
    00856         return rangeOverlap(rangeStart, rangeEnd, (*head.pNext));
    00857 }
    00858
    00860
    00861 void DiscreteObservationConverter::instantiateDomainData(
    00862         VariableLookupNode &varNode, const DomainLookupNodeData * domainDataHead)
    00863 {
    00864         // Loop over the values we've loaded an copy the data.
    00865         const DomainLookupNodeData * currentData = domainDataHead;
    00866
    00867         // Previous head node
    00868         DomainLookupNode * domHead = NULL;
    00869
    00870         for( ; currentData != NULL; currentData = currentData->pNext) {
    00871                 // Create a new value for this variable.
    00872                 Mers::Interfaces::DiscreteValue * dVal =
    00873                         new Mers::Interfaces::DiscreteValue(varNode.m_dVar,
    00874                         currentData->valueName);
    00875
    00876                 // Register the value.
    00877                 addDiscreteValue(dVal);
    00878
    00879                 // Create a lookup entry for it.
    00880                 DomainLookupNode * domNode = new DomainLookupNode(
    00881                         currentData->rangeLowBound, currentData->rangeHighBound, dVal);
    00882
    00883                 // If this is the head, assign it to the varNode, otherwise
    00884                 // append it to the previous head.
    00885                 if(domHead == NULL) {
    00886                         varNode.pDomainList = domNode;
    00887                 } else {
    00888                         domHead->pNext = domNode;
    00889                 }
    00890
    00891                 // This is our new head.
    00892                 domHead = domNode;
    00893         }
    00894 }
    00895
    00897
    00898 int DiscreteObservationConverter::loadCompoundDomain(ifstream &configStream,
    00899         char * word, int lowIndex, int highIndex, vector<VariableLookupNode *> &temp)
    00900 {
    00901         char c;
    00902         int status = 0;
    00903         char discVarPrefix[512];
    00904         char discVarName[512];
    00905
    00906         // Get the prefix of the variable.
    00907         c = getWord(configStream, discVarPrefix);
    00908
    00909         // Skip any white space.
    00910         if (isWhiteSpace(c))
    00911                 c = skip(configStream);
    00912
    00913         // If we found another digit, then put it back for the next iteration.
    00914         if(isDigit(c))
    00915                 configStream.putback(c);
    00916         // If we found the end character '}', indicate we'll be done.
    00917         else if (c == '}')
    00918                 // We're done loading domains.
    00919                 status = 1;
    00920         // Otherwise indicate a parse error.
    00921         else
    00922         {
    00923                 displaySyntaxError("\'}\' or more mappings");
    00924                 return -1;
    00925         }
    00926
    00927         // For each index, lookup a corresponding variable.
    00928         unsigned int discVarIndex = 0;
    00929         for(int i = lowIndex; i <= highIndex; ++i, ++discVarIndex)
    00930         {
    00931                 // Lookup our Continuous variable.
    00932                 t_SensorMap::iterator itSensor = m_SensorMap.find(t_SensorData(word, i));
    00933
    00934                 // Make sure we found it
    00935                 if(itSensor == m_SensorMap.end()) {
    00936                         cerr << "Error: no sensor instance available for '" <<
    00937                                 word << "'[" << i << "]" << endl;
    00938                         return -1;
    00939                 }
    00940
    00941                 // Get our continuous variable
    00942                 ContinuousVariableIdentifier cVarID = (*itSensor).second;
    00943
    00944                 // If the low and high index are the same, then we don't append
    00945                 // anything to the variable name.
    00946                 if(lowIndex == highIndex)
    00947                         strcpy(discVarName, discVarPrefix);
    00948                 // Otherwise form the variable name with prefix + index.
    00949                 else
    00950                         sprintf(discVarName,"%s%d", discVarPrefix, discVarIndex);
    00951
    00952                 // See if we already have this variable.  Each discrete variable can
    00953                 // only be mapped to once.
    00954                 DiscreteVariableIdentifier dVarID = getDiscreteVariable(discVarName);
    00955
    00956                 // See if we found this variable.
    00957                 if(isValid(dVarID)) {
    00958                         cerr << "Error: multiple plant variables mapped to the same discrete "
    00959                                 "variable " << discVarName << " see line " << m_CurrentLine << endl;
    00960                         return -1;
    00961                 }
    00962
    00963                 // Create a new Discrete Variable.
    00964                 Mers::Interfaces::DiscreteVariable * dVar =
    00965                         new Mers::Interfaces::DiscreteVariable(discVarName);
    00966
    00967                 // Add this variable to our list.
    00968                 addDiscreteVariable(dVar);
    00969
    00970                 // Create a new variable node.
    00971                 VariableLookupNode * vNode = new VariableLookupNode(dVar);
    00972
    00973                 // Add a lookup between this continuous variable and the new
    00974                 // discrete variable.
    00975                 m_DiscritizationMap.insert(t_CVarDiscMap::value_type(cVarID, vNode));
    00976
    00977                 // Added it to the temporary listing of indices.
    00978                 temp.push_back(vNode);
    00979                 ++(vNode->numReferences);
    00980         }
    00981
    00982         return status;
    00983 }
    00984
    00986