X-Git-Url: https://ruin.nu/git/?p=popboot.git;a=blobdiff_plain;f=planner.cpp;h=02e634220921971f7c9ff3f42bd873585789adac;hp=3e8d5de60af18b35416301943000b20d1768094c;hb=318003cdb8615b39ef71761f55ac2159caabbf47;hpb=b177aeec472c3941b39b874a83883ff87a41919c diff --git a/planner.cpp b/planner.cpp index 3e8d5de..02e6342 100644 --- a/planner.cpp +++ b/planner.cpp @@ -4,39 +4,82 @@ using namespace std; using namespace __gnu_cxx; -Planner::Planner(std::vector actions, literals init, literals goal){ +extern "C" void* executeNode(void* arg); - _start = new Node(Action("",init, literals())); - Node* finish = new Node(Action("",literals(),goal)); +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){ - literals preconds = action->preconditions(); - for (literals::iterator effect = preconds.begin(); effect != preconds.end(); ++effect){ - _actions[*effect] = *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); + 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){ - literals preconds = node->action().preconditions(); + 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{ - for (literals::iterator precond = preconds.begin(); precond != preconds.end(); ++precond){ - hash_map::iterator addedNode = _addedNodes.find(*precond); - if(addedNode != _addedNodes.end()){ + //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 { - hash_map::iterator action = _actions.find(*precond); - if (action != _actions.end()){ + //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{ - cerr << "Action with effect: " << *precond << " not found!"; + //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); } } } @@ -44,9 +87,148 @@ void Planner::makePlan(Node* node){ } void Planner::addNode(Node* node){ - literals effects = node->action().effects(); + 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; + } +} + - for (literals::iterator effect = effects.begin(); effect != effects.end(); ++effect){ - _addedNodes[*effect] = node; +void Planner::execute(){ + 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; + + vector children = node->children(); + + //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); + } + } + + } + cerr << "Number of nodes: " << _addedNodes.size() << endl; + //Clearing the init vector, effects will be added below. + _goal.clear(); + Preconditions goal = _finish->preconditions(); + for (Preconditions::const_iterator precond = goal.begin(); precond != goal.end(); ++precond){ + _goal.push_back(precond->first); } + + 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); + + //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(); + + cout << "Effects achieved so far: " << _init.size() << ": "; + copy(_init.begin(), _init.end(), ostream_iterator(cout, " ")); + cout << endl; + + if (executions <= 1){ + cerr << "Non of the remaining actions could be executed, quiting." << endl; + return; + } + if (_actions.size() == 0){ + //Nothing left to do, quitting. + return; + } + //REPLANNING + cout << "Replanning..." << endl; + + //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); + if (_addedNodes.size() <= 2){ + cerr << "No actions to execute, quiting." << endl; + return; + } + execute(); + +} +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); }