X-Git-Url: https://ruin.nu/git/?p=popboot.git;a=blobdiff_plain;f=planner.cpp;h=94d05494e10609181271c371b22895b12eaff4cb;hp=159cb528d68f15e5e0d5667facef30455042867d;hb=c4dac6829d93aade3b0aa271d0157d8a4e06d2c5;hpb=c0744e66fecd39c1606727858e7fa05990e84402 diff --git a/planner.cpp b/planner.cpp index 159cb52..94d0549 100644 --- a/planner.cpp +++ b/planner.cpp @@ -1,3 +1,261 @@ #include "planner.h" +#include "node.h" +#include +#include +using namespace std; +using namespace __gnu_cxx; +extern "C" void* executeNode(void* arg); +struct ExecutionStuff { + sem_t* nodes; + sem_t* list; + Node* node; + queue* execQueue; +}; + +Planner::Planner(std::vector actions, Literals init, Literals goal){ + _init = init; + _goal = goal; + _start = new StartNode(_init); + _finish = new EndNode(_goal); + addNode(_start); + + for(vector::iterator action = actions.begin(); action != actions.end(); ++action){ + Action* act = new Action(*action); + _actions.push_back(act); + const Literals& effects = act->effects(0); + for (Literals::const_iterator effect = effects.begin(); effect != effects.end(); ++effect){ + _actionEffects[*effect] = act; + } + } + makePlan(_finish); +} + +Planner::~Planner(){ + //Iterating over the remaining nodes and deleting them + for (vector::iterator node = _addedNodes.begin(); node != _addedNodes.end(); ++node){ + delete *node; + } + //iterating over the the remaining actions and deleting them + for (vector::iterator action = _actions.begin(); action != _actions.end(); ++action){ + delete *action; + } +} + + +void Planner::makePlan(Node* node){ + addNode(node); + + const Preconditions& preconds = node->action()->preconditions(); + + if (preconds.size() == 0){ + //Add the node as a child to start if there are no preconditions + _start->addChild(node); + }else{ + //iterate over the preconditions + for (Preconditions::const_iterator precond = preconds.begin(); precond != preconds.end(); ++precond){ + //Check if there is a node with this precondition as an effect + hash_map::iterator addedNode = _addedEffects.find(precond->first); + if(addedNode != _addedEffects.end()){ + //Use this node if there is one + //cerr << "Using already added node for effect " << precond->first << ", on node: " << node->action()->name() << endl; + addedNode->second->addChild(node); + }else { + //Check if there is an action which satisfies this effect + hash_map::iterator action = _actionEffects.find(precond->first); + if (action != _actionEffects.end()){ + //Create a new node for the found effect and add the current + //one as a child + Node* newnode = new Node(action->second); + newnode->addChild(node); + makePlan(newnode); + }else if (precond->second){ + //No such action found, and since it was a hard preconition + //we need to stop here. + cerr << "Could not satisfy the effect: " << precond->first << " for: " << node->action()->name() << endl; + return; + }else{ + //No action found, but it was a soft precondition, so we can + //satisfy it and continue. + //cerr << "Could not satisfy the effect: " << precond->first << " for: " << node->action()->name() << endl; + node->satisfyCondition(precond->first); + _start->addChild(node); + } + } + } + } +} + +void Planner::addNode(Node* node){ + const Literals& effects = node->action()->effects(0); + _addedNodes.push_back(node); + + //Iterate over the effects for this node and add them to the map. + for (Literals::const_iterator effect = effects.begin(); effect != effects.end(); ++effect){ + _addedEffects[*effect] = node; + } +} + + +void Planner::execute(){ + executePlan(); + + if (cleanupExecution() <= 1){ + cerr << "Non of the remaining actions could be executed, quiting." << endl; + return; + } + + cout << "Effects achieved so far: " << _init.size() << ": "; + copy(_init.begin(), _init.end(), ostream_iterator(cout, " ")); + cout << endl; + + if (_actions.size() == 0){ + //Nothing left to do, quitting. + return; + } + //REPLANNING + cout << "Replanning..." << endl; + + replan(); + + if (_addedNodes.size() <= 2){ + cerr << "No actions to execute, quiting." << endl; + return; + } + execute(); + +} + +void Planner::executePlan(){ + sem_init(&_nodes, 0, 1); + sem_init(&_list, 0, 1); + + //We've "executed" the start node. + _executedNodes.push(_start); + int executions = 1; + + //As long as there executed nodes in the queue. + while (executions > 0){ + //Wait for a node to be added to the queue + sem_wait(&_nodes); + --executions; + + //Pop the first node from the queue. + sem_wait(&_list); + Node* node = _executedNodes.front(); + _executedNodes.pop(); + sem_post(&_list); + + //We don't need to continue if the end node was executed. + if (node == _finish) + return; + executions += executeChildren(node); + + } +} + + +int Planner::executeChildren(Node* node){ + + vector children = node->children(); + + int executions = 0; + //Iterate over the children for this node + for(vector::iterator child = children.begin(); child != children.end(); ++child){ + //Satisfy the preconditions the current node had as effect. + if ((*child)->satisfyConditions(node->effects())){ + //If all preconditions were satisified we can create a new thread + //and execute this child. + ++executions; + pthread_attr_t tattr; + pthread_t tid; + pthread_attr_init(&tattr); + pthread_attr_setscope(&tattr, PTHREAD_SCOPE_SYSTEM); + //Create a struct object for the thread and add the + //needed members to it. + ExecutionStuff* es = new ExecutionStuff; + es->nodes = &_nodes; + es->list = &_list; + es->node = *child; + es->execQueue = &_executedNodes; + pthread_create(&tid, &tattr, executeNode, es); + } + } + return executions; +} + +int Planner::cleanupExecution(){ + //Clearing the init and goal vectors, new effects will be added below. + _init.clear(); + _goal.clear(); + Preconditions goal = _finish->preconditions(); + for (Preconditions::const_iterator precond = goal.begin(); precond != goal.end(); ++precond){ + _goal.push_back(precond->first); + } + + if (goal.size() == 0) + exit(0); + + cout << "Unsatisfied preconditions so far: " << _goal.size() << ": "; + copy(_goal.begin(), _goal.end(), ostream_iterator(cout, " ")); + cout << endl; + + //iterator for inserting effects at the end of _init + back_insert_iterator ii(_init); + + int executions = 0; + //Iterate throu the nodes, to see what's been done + for (vector::iterator node = _addedNodes.begin(); node != _addedNodes.end(); ++node){ + if ((*node)->executed()){ + //Node was executed, adding the effects to _init. + executions++; + const Literals& effects = (*node)->effects(); + copy(effects.begin(),effects.end(),ii); + + vector::iterator action = find(_actions.begin(), _actions.end(), (*node)->action()); + if (action != _actions.end()){ + //The action can be deleted, since it's already been executed. + delete *action; + _actions.erase(action); + } + } + //The node is not needed anymore + delete *node; + } + //Clearing the vectors and maps, since they are obsolete now. + _addedNodes.clear(); + _addedEffects.clear(); + _actionEffects.clear(); + return executions; +} + +void Planner::replan(){ + + //Adding the effecs for the remaining actions. + for (vector::iterator action = _actions.begin(); action != _actions.end(); ++action){ + const Literals& effects = (*action)->effects(0); + for (Literals::const_iterator effect = effects.begin(); effect != effects.end(); ++effect){ + _actionEffects[*effect] = *action; + } + } + _start = new StartNode(_init); + _finish = new EndNode(_goal); + addNode(_start); + makePlan(_finish); +} +void* executeNode(void* arg){ + ExecutionStuff* es = (ExecutionStuff*)arg; + + es->node->execute(); + + sem_wait(es->list); + //Add this node to the queue with executed nodes + es->execQueue->push(es->node); + sem_post(es->list); + + //Signal that the node is available. + sem_post(es->nodes); + + pthread_exit((void*)0); +}