>xabsl   The Extensible Agent Behavior Specification Language

XabslEngine Class Library Reference

 

XabslEngine.cpp

Go to the documentation of this file.
00001 /** 
00002 * @file XabslEngine.cpp
00003 *
00004 * Implementation of class Engine
00005 *
00006 * @author <a href="http://www.martin-loetzsch.de">Martin Loetzsch</a>
00007 * @author <a href="http://www.sim.informatik.tu-darmstadt.de/pers/card/risler.html">Max Risler</a>
00008 * @author <a href="http://www.informatik.hu-berlin.de/~juengel">Matthias JŸngel</a>
00009 */
00010 
00011 #include "XabslEngine.h"
00012 
00013 namespace xabsl 
00014 {
00015   
00016 Engine::Engine(ErrorHandler& e,unsigned (*pTimeFunction)())
00017 : Symbols(e), selectedAgent(0),
00018 errorHandler(e), initialized(false), pTimeFunction(pTimeFunction),
00019 agentPriority(0),
00020 synchronizationTicks(0),
00021 timeOfExecutionStart(pTimeFunction())
00022 {
00023 }
00024 
00025 Engine::~Engine()
00026 {
00027   int i;
00028   for (i=0; i< options.getSize(); i++)
00029     if (options[i]!=0) 
00030       delete options[i];
00031   for (i=0; i< agents.getSize(); i++)
00032     if (agents[i]!=0) 
00033       delete agents[i];
00034   for (i=0; i< rootActions.getSize(); i++)
00035     if (rootActions[i]!=0) 
00036       delete rootActions[i];
00037 }
00038 
00039 void Engine::execute()
00040 {
00041   if (!initialized)
00042   {
00043     errorHandler.error("execute(): Call createOptionGraph before first execute.");
00044     return;
00045   }
00046 
00047   timeOfExecutionStart = pTimeFunction();
00048   resetOutputSymbols();
00049 
00050   for (int i=0; i< rootActions.getSize(); i++)
00051     rootActions[i]->execute();
00052 
00053   for (int i=0; i < options.getSize(); i++)
00054   {
00055     options[i]->wasActive = options[i]->isActive;
00056     options[i]->isActive = false;
00057   }
00058 
00059   for (int i=0;i<basicBehaviors.getSize();i++)
00060   {
00061     basicBehaviors[i]->wasActive = basicBehaviors[i]->isActive;
00062     basicBehaviors[i]->isActive = false;
00063   }
00064 }
00065 
00066 void Engine::createOptionGraph(InputSource& input)
00067 {
00068   int i;
00069   char buf1[100],buf2[100];
00070 
00071   errorHandler.errorsOccurred = false;
00072   timeOfExecutionStart = pTimeFunction();
00073 
00074   if (initialized)
00075   {
00076     errorHandler.error("createOptionGraph(): Don't call this function twice");
00077     return;
00078   }
00079   if (!input.open()) 
00080   {
00081     errorHandler.error("createOptionGraph(): Can't open input source");
00082     return;
00083   }
00084 
00085   // create internal enumerations
00086   int numberOfInternalEnumerations = (int)input.readValue();
00087   for (i=0; i < numberOfInternalEnumerations; i++)
00088   {
00089     input.readString(buf1, 99);
00090     int numberOfElements = (int)input.readValue();
00091     for (int j=0; j < numberOfElements; j++)
00092     {
00093       input.readString(buf2, 99);
00094       registerEnumElement(buf1, buf2, j);
00095       if (errorHandler.errorsOccurred)
00096       {
00097         errorHandler.error("XabslEngine::createOptionGraph(): could not register internal enumeration \"%s\"",buf1);
00098         return;
00099       }
00100     }
00101   }
00102 
00103   // create internal symbols
00104   int numberOfInternalSymbols = (int)input.readValue();
00105   for (i=0; i < numberOfInternalSymbols; i++)
00106   {
00107     char c[2];
00108     input.readString(c,1);
00109     switch (c[0])
00110     {
00111       case 'd':
00112         input.readString(buf1,99);
00113         internalDecimalSymbols.append(buf1, 0);
00114         registerDecimalOutputSymbol(buf1, &(internalDecimalSymbols.getElement(internalDecimalSymbols.getSize() - 1)));
00115         if (errorHandler.errorsOccurred)
00116         {
00117           errorHandler.error("XabslEngine::createOptionGraph(): could not register internal decimal symbol \"%s\"",buf1);
00118           return;
00119         }
00120         break;
00121       case 'b':
00122         input.readString(buf1,99);
00123         internalBooleanSymbols.append(buf1, false);
00124         registerBooleanOutputSymbol(buf1, &(internalBooleanSymbols.getElement(internalBooleanSymbols.getSize() - 1)));
00125         if (errorHandler.errorsOccurred)
00126         {
00127           errorHandler.error("XabslEngine::createOptionGraph(): could not register internal boolean symbol \"%s\"",buf1);
00128           return;
00129         }
00130         break;
00131       case 'e':
00132         input.readString(buf1,99);
00133         if (!enumerations.exists(buf1))
00134         {
00135           errorHandler.error("XabslEngine::createOptionGraph(): enumeration \"%s\" was not registered",buf1);
00136           return;
00137         }
00138         const Enumeration* enumeration = enumerations[buf1];
00139         if (enumeration->enumElements.getSize() == 0)
00140         {
00141           errorHandler.error("XabslEngine::createOptionGraph(): no enumeration elements for \"%s\" were registered",buf1);
00142           return;
00143         }
00144         input.readString(buf2,99);
00145         internalEnumeratedSymbols.append(buf2, enumeration->enumElements[0]->v);
00146         registerEnumeratedOutputSymbol(buf2, buf1, &(internalEnumeratedSymbols.getElement(internalEnumeratedSymbols.getSize() - 1)));
00147         if (errorHandler.errorsOccurred)
00148         {
00149           errorHandler.error("XabslEngine::createOptionGraph(): could not register internal enumerated symbol \"%s\"",buf2);
00150           return;
00151         }
00152         break;
00153     }
00154   }
00155 
00156   // the total number of options in the intermediate code
00157   int numberOfOptions = (int)input.readValue(); 
00158   
00159   // create empty options
00160   for (i=0; i< numberOfOptions; i++)
00161   {
00162     input.readString(buf1,99);
00163     options.append(buf1,new Option(buf1,input,errorHandler,*this,timeOfExecutionStart,i));
00164     if (errorHandler.errorsOccurred)
00165     {
00166       errorHandler.error("XabslEngine::createOptionGraph(): could not create option \"%s\"",options[i]->n);
00167       return;
00168     }
00169   }
00170   XABSL_DEBUG_INIT(errorHandler.message("registered %i options",numberOfOptions));
00171 
00172   // create the options and its states
00173   for (i=0; i< numberOfOptions; i++)
00174   {
00175     XABSL_DEBUG_INIT(errorHandler.message("creating option \"%s\"",options[i]->n));
00176     options[i]->create(input,options,basicBehaviors,*this,agentPriority,synchronizationTicks);
00177     if (errorHandler.errorsOccurred)
00178     {
00179       errorHandler.error("XabslEngine::createOptionGraph(): could not create option \"%s\"",options[i]->n);
00180       return;
00181     }
00182   }
00183 
00184   // create the agents
00185   int numberOfAgents = (int)input.readValue();
00186   for (i=0; i< numberOfAgents; i++)
00187   {
00188     input.readString(buf1,99);
00189     input.readString(buf2,99);
00190     agents.append(buf1,new Agent(buf1,options[buf2],errorHandler, i));
00191   }
00192 
00193   // check for loops in the option graph
00194   for (i=0;i<agents.getSize();i++)
00195   {
00196     if (Option* option = dynamic_cast<Option*>(agents[i]->getRootOption()))
00197     {
00198       int size = countActions(option) + 1;
00199       ActionBehavior** currentOptionPath = new ActionBehavior*[size];
00200       
00201       currentOptionPath[0] = dynamic_cast<ActionBehavior*>(Action::create(option, errorHandler, timeOfExecutionStart));
00202 
00203       // call recursively the checkForLoops function
00204       if (checkForLoops(option, currentOptionPath, 1, size)) 
00205       {
00206         errorHandler.error("createOptionGraph(): The created option graph contains loops");
00207       };
00208 
00209       delete currentOptionPath[0];
00210       delete[] currentOptionPath;
00211     }
00212   }
00213 
00214   // create array of cooperating states
00215   for (i=0;i<options.getSize();i++)
00216     for (int j=0;j<options[i]->states.getSize();j++)
00217       if (CoopState* state = dynamic_cast<CoopState*>(options[i]->states[j]))
00218         coopStates.append(state);
00219 
00220   selectedAgent = agents[0];
00221   setRootAction();
00222 
00223   XABSL_DEBUG_INIT(errorHandler.message("selected agent: \"%s\"",selectedAgent->n));
00224   input.close();
00225   initialized = true;
00226 }
00227 
00228 bool Engine::checkForLoops(Option* currentOption, ActionBehavior* currentOptionTree[], int currentLength, int maxSize)
00229 {
00230   int i,j,k,l;
00231 
00232   for (i=0; i<currentOption->states.getSize(); i++)
00233   {
00234     int newLength = currentLength;
00235 
00236     for (j=0; j<currentOption->states[i]->actions.getSize(); j++)
00237     {
00238       if (ActionBehavior* nextAction = dynamic_cast<ActionBehavior*>(currentOption->states[i]->actions[j])) 
00239       {
00240         for(k=0; k<newLength; k++)
00241         {
00242           // check for the subsequent option of each state whether the referenced 
00243           // option is contained in the current option tree
00244           if (nextAction->getBehavior() == currentOptionTree[k]->getBehavior())
00245           {
00246             errorHandler.error("checkForLoops() : state \"%s\" in option \"%s\" references subsequent behavior \"%s\", which is already included in another possible activation tree.",
00247               currentOption->states[i]->n, 
00248               currentOption->n,
00249               nextAction->getBehavior()->n);
00250 
00251             return true;
00252           }
00253         }
00254         
00255         if(newLength>=maxSize)
00256         {
00257           errorHandler.error("checkForLoops() : max size exceeded when processing state \"%s\" in option \"%s\".",
00258             currentOption->states[i]->n, 
00259             currentOption->n);
00260           return true;
00261         }
00262 
00263         currentOptionTree[newLength++] = nextAction;
00264       }
00265     }
00266 
00267     // recursion
00268     for (k = currentLength; k < newLength; k++)
00269     {
00270       int recursionLength = newLength;
00271       for (l = currentLength; l < newLength; l++)
00272       {
00273         if (l != k)
00274         {
00275           addActions(currentOptionTree[l], currentOptionTree, recursionLength, maxSize);
00276         }
00277       }
00278 
00279       if (ActionOption* nextAction = dynamic_cast<ActionOption*>(currentOptionTree[k]))
00280       {
00281         if (checkForLoops(nextAction->option, currentOptionTree, recursionLength, maxSize))
00282         {
00283           return true;
00284         }
00285       }
00286     }
00287   }
00288 
00289   return false;
00290 }
00291 
00292 void Engine::addActions(ActionBehavior* actionToAdd, ActionBehavior* currentOptionTree[], int& currentLength, int maxSize)
00293 {
00294   int i,j;
00295 
00296   if (ActionOption* optionToAdd = dynamic_cast<ActionOption*>(actionToAdd))
00297   {
00298     for (i=0; i<optionToAdd->option->states.getSize(); i++)
00299     {
00300       for (j=0; j<optionToAdd->option->states[i]->actions.getSize(); j++)
00301       {
00302         if (ActionBehavior* nextAction = dynamic_cast<ActionBehavior*>(optionToAdd->option->states[i]->actions[j])) 
00303         {
00304           if(currentLength>=maxSize)
00305           {
00306             errorHandler.error("checkForLoops() : max size exceeded when processing state \"%s\" in option \"%s\".",
00307               optionToAdd->option->states[i]->n, 
00308               optionToAdd->option->n);
00309             return;
00310           }
00311           currentOptionTree[currentLength++] = nextAction;
00312           addActions(nextAction, currentOptionTree, currentLength, maxSize);
00313         }
00314       }
00315     }
00316   }
00317 }
00318 
00319 int Engine::countActions(Option* option)
00320 {
00321   int i,j;
00322   int count = 0;
00323   for (i=0; i<option->states.getSize(); i++)
00324   {
00325     for (j=0; j<option->states[i]->actions.getSize(); j++)
00326     {
00327       if (ActionBehavior* nextAction = dynamic_cast<ActionBehavior*>(option->states[i]->actions[j])) 
00328       {
00329         count++;
00330         if (ActionOption* nextOption = dynamic_cast<ActionOption*>(nextAction))
00331         {
00332           count += countActions(nextOption->option);
00333         }
00334       }
00335     }
00336   }
00337   return count;
00338 }
00339 
00340 void Engine::registerBasicBehavior(BasicBehavior& basicBehavior)
00341 {
00342   XABSL_DEBUG_INIT(errorHandler.message("registering basic behavior \"%s\"",basicBehavior.n));
00343 
00344   if (basicBehaviors.exists(basicBehavior.n))
00345   {
00346     errorHandler.error("registerBasicBehavior(): basic behavior \"%s\" was already registered",basicBehavior.n);
00347     return;
00348   }
00349 
00350   basicBehavior.parameters->registerEnumerations(enumerations);
00351   basicBehavior.registerParameters();
00352 
00353   basicBehavior.index = basicBehaviors.getSize();
00354   basicBehaviors.append(basicBehavior.n,&basicBehavior);
00355 }
00356 
00357 void Engine::clearRootActions()
00358 {
00359   for (int i=0; i< rootActions.getSize(); i++)
00360     if (rootActions[i]!=0) 
00361       delete rootActions[i];
00362   rootActions.clear();
00363 }
00364 
00365 bool Engine::addRootAction(const char* name, bool isOption)
00366 {
00367   if (isOption)
00368   {
00369     // check if the option exists
00370     if (!options.exists(name)) return false;
00371 
00372     // set the current root option to the requested option
00373     addRootAction(options[name]);
00374   }
00375   else
00376   {
00377     // check if the basic behavior exists
00378     if (!basicBehaviors.exists(name)) return false;
00379 
00380     // set the current root option to the requested option
00381     addRootAction(basicBehaviors[name]);
00382   }
00383 
00384   return true;
00385 }
00386 
00387 bool Engine::setRootAction(const char* name, bool isOption)
00388 {
00389   clearRootActions();
00390   return addRootAction(name, isOption);
00391 }
00392 
00393 void Engine::setRootAction()
00394 {
00395   setRootAction(selectedAgent->getRootOption());
00396 }
00397 
00398 void Engine::addRootAction(Behavior* behavior)
00399 {
00400   rootActions.append(Action::create(behavior, errorHandler, timeOfExecutionStart));
00401 }
00402 
00403 void Engine::setRootAction(Behavior* behavior)
00404 {
00405   clearRootActions();
00406   addRootAction(behavior);
00407 }
00408 
00409 bool Engine::addRootActionDecimalOutputSymbol(const char* name, double value)
00410 {
00411   if (!decimalOutputSymbols.exists(name)) return false;
00412 
00413   ActionDecimalOutputSymbol* action = new ActionDecimalOutputSymbol(timeOfExecutionStart);
00414   action->decimalOutputSymbol = decimalOutputSymbols[name];
00415   action->decimalOutputSymbolExpression = new DecimalValue(value);
00416   rootActions.append(action);
00417   return true;
00418 }
00419 
00420 bool Engine::addRootActionBooleanOutputSymbol(const char* name, bool value)
00421 {
00422   if (!booleanOutputSymbols.exists(name)) return false;
00423 
00424   ActionBooleanOutputSymbol* action = new ActionBooleanOutputSymbol(timeOfExecutionStart);
00425   action->booleanOutputSymbol = booleanOutputSymbols[name];
00426   action->booleanOutputSymbolExpression = new BooleanValue(value);
00427   rootActions.append(action);
00428   return true;
00429 }
00430 
00431 bool Engine::addRootActionEnumeratedOutputSymbol(const char* name, const char* value)
00432 {
00433   if (!enumeratedOutputSymbols.exists(name) || !enumeratedOutputSymbols[name]->enumeration->enumElements.exists(value)) 
00434     return false;
00435 
00436   ActionEnumeratedOutputSymbol* action = new ActionEnumeratedOutputSymbol(timeOfExecutionStart);
00437   action->enumeratedOutputSymbol = enumeratedOutputSymbols[name];
00438   action->enumeratedOutputSymbolExpression = new EnumeratedValue(enumeratedOutputSymbols[name]->enumeration, enumeratedOutputSymbols[name]->enumeration->enumElements[value]->v);
00439   rootActions.append(action);
00440   return true;
00441 }
00442 
00443 const Action* Engine::getRootAction(int i) const
00444 {
00445   return rootActions[i];
00446 }
00447 
00448 Action* Engine::getRootAction(int i)
00449 {
00450   return rootActions[i];
00451 }
00452 
00453 const Array<Action*>& Engine::getRootActions() const
00454 {
00455   return rootActions;
00456 }
00457 
00458 Array<Action*>& Engine::getRootActions()
00459 {
00460   return rootActions;
00461 }
00462 
00463 const char* Engine::getSelectedAgentName() const
00464 {
00465   if (selectedAgent)
00466     return selectedAgent->n;
00467   else
00468     return "";
00469 }
00470 
00471 bool Engine::setSelectedAgent(const char* name)
00472 {
00473   if (!agents.exists(name)) 
00474   {
00475     return false;
00476   }
00477 
00478   Agent* newAgent = agents[name];
00479 
00480   if (selectedAgent != newAgent)
00481   {
00482     selectedAgent = newAgent;
00483     setRootAction();
00484   }
00485 
00486   return true;
00487 }
00488 
00489 void Engine::reset()
00490 {
00491   int i;
00492   for (i=0; i< options.getSize(); i++)
00493   {
00494     options[i]->wasActive = false;
00495   }
00496   for (i=0; i< basicBehaviors.getSize(); i++)
00497   {
00498     basicBehaviors[i]->wasActive = false;
00499   }
00500   errorHandler.errorsOccurred = false;
00501 }
00502 
00503 void Engine::prepareIncomingMessages()
00504 {
00505   for (int i=0; i<coopStates.getSize(); i++)
00506   {
00507     coopStates[i]->prepareIncomingMessages();
00508   }
00509 }
00510 
00511 void Engine::processIncomingMessage(const TeamMessage& message)
00512 {
00513   for (int i=0; i<message.coopStatesExecuted.getSize(); i++)
00514     coopStates[message.coopStatesExecuted[i]]->numberOfAgentsExecuting++;
00515   
00516   for (int i=0; i<message.coopStatesEntering.getSize(); i++)
00517   {
00518     if (coopStates[message.coopStatesEntering[i]]->numberOfAgentsEntering == 0 ||
00519         coopStates[message.coopStatesEntering[i]]->highestPriorityOfAgentsEntering < message.agentPriority)
00520       coopStates[message.coopStatesEntering[i]]->highestPriorityOfAgentsEntering = message.agentPriority;
00521     coopStates[message.coopStatesEntering[i]]->numberOfAgentsEntering++;
00522   }
00523 
00524   for (int i=0; i<message.coopStatesOptionExecuted.getSize(); i++)
00525     coopStates[message.coopStatesOptionExecuted[i]]->numberOfAgentsInOption++;
00526 }
00527 
00528 void Engine::generateOutgoingMessage(TeamMessage& message)
00529 {
00530   message.reset();
00531   for (int i=0; i<coopStates.getSize(); i++)
00532   {
00533     // is option currently active?
00534     if (options[coopStates[i]->optionIndex]->wasActive)
00535     {
00536       message.coopStatesOptionExecuted.append(i);
00537       // is state currently active?
00538       if (options[coopStates[i]->optionIndex]->activeState == coopStates[i])
00539       {
00540         message.coopStatesExecuted.append(i);
00541       }
00542       else if (coopStates[i]->entering)
00543       {
00544         message.coopStatesEntering.append(i);
00545       }
00546     }
00547   }
00548   message.agentPriority = agentPriority;
00549 }
00550 
00551 } // namespace
00552 

Up | Main Page | Generated at Wed Aug 19 17:32:28 2009.