Program Listing for File Plan.h

Return to documentation for file (src/VALfiles/Plan.h)

/************************************************************************
 * Copyright 2008, Strathclyde Planning Group,
 * Department of Computer and Information Sciences,
 * University of Strathclyde, Glasgow, UK
 * http://planning.cis.strath.ac.uk/
 *
 * Maria Fox, Richard Howey and Derek Long - VAL
 * Stephen Cresswell - PDDL Parser
 *
 * This file is part of VAL, the PDDL validator.
 *
 * VAL is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * VAL is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with VAL.  If not, see <http://www.gnu.org/licenses/>.
 *
 ************************************************************************/

/*-----------------------------------------------------------------------------
  VAL - The Automatic Plan Validator for PDDL+

  $Date: 2010-07-15 15:13:44 $
  $Revision: 1.4 $

  Maria Fox, Richard Howey and Derek Long - PDDL+ and VAL
  Stephen Cresswell - PDDL Parser

  maria.fox@cis.strath.ac.uk
  derek.long@cis.strath.ac.uk
  stephen.cresswell@cis.strath.ac.uk
  richard.howey@cis.strath.ac.uk

  By releasing this code we imply no warranty as to its reliability
  and its use is entirely at your own risk.

  Strathclyde Planning Group
  http://planning.cis.strath.ac.uk
 ----------------------------------------------------------------------------*/
#include <vector>
#include <functional>
#include <algorithm>
#include <map>
#include <iostream>
#include "ptree.h"
#include "Exceptions.h"
#include "main.h"
#include "Ownership.h"
#include "Polynomial.h"
#include "State.h"

#ifndef __PLAN
#define __PLAN

// Use the following switch if your compiler/STL doesn't use std.
// #define NO_STD_NAMESPACE

//#define vector std::vector

namespace VAL {

class State;
class Proposition;
class FuncExp;
class FuncExpFactory;
class Action;
class InvariantAction;
class CtsEffectAction;
class CondCommunicationAction;
class ExecutionContext;


class Update {
private:
    const FuncExp * fe;
    assign_op aop;
    FEScalar value;
public:
    Update(const FuncExp * f,assign_op ao,FEScalar v) :
        fe(f), aop(ao), value(v)
    {};

    void update(State * s) const;
   void updateChange(State * s) const;
};

class EffectsRecord {
private:
    vector<const SimpleProposition *> adds;
    vector<const SimpleProposition *> dels;

    vector<Update> updates;

public:
    void pushAdd(const SimpleProposition * p)
    {
        adds.push_back(p);
    };
    void pushDel(const SimpleProposition * p)
    {
        dels.push_back(p);
    };
    void addFEffect(const FuncExp * fe,assign_op aop,FEScalar value)
    {
        updates.push_back(Update(fe,aop,value));

    };

    void enact(State * s) const;
};

class Happening {
private:
    Validator * vld;

    double time;
    vector<const Action*> actions;

    Happening(Validator * v) :
        vld(v), time(0.0), actions(), eventHappening(false),realHappening(false), afterPlan(false)
    {};

   bool eventHappening;
    bool realHappening;
    bool afterPlan;

public:
    friend class ExecutionContext;
    friend class ActiveCtsEffects;

private:
    template<typename X> struct select2nd {
      typename X::second_type operator()(X p){return p.second;};
    };


public:
    Happening(Validator * v,const vector<pair<double,Action*> > & as,double timeEndPlan);
    Happening(Validator * v,double timeToExecute,const vector<pair<double,Action*> > & as);

  Happening(Validator * v,vector<const Action*>  acts,bool event = false);   //for creating event happenings
  Happening(Validator * v, vector<const Action*> acts,double t,bool event =false);
    ~Happening();

    void adjustContext(ExecutionContext &) const;
    void adjustContextInvariants(ExecutionContext &) const; //invariant interval is ( , ] or ( , ) ?
    void adjustActiveCtsEffects(ActiveCtsEffects &) const;

    double getTime() const {return time;};
    int getNoActions() const {return actions.size();};
    const vector<const Action*> * getActions() const {return &actions;};

  void clearActions() {actions.clear();};
    bool canHappen(const State * s) const;
    bool applyTo(State * s) const;


    void write(ostream & o) const;

    bool isAfterPlan() const {return afterPlan;};
   bool isRegularHappening() const {return realHappening;};
   void inject(Action * a) {actions.push_back(a);};
};

struct ExecutionContext {
    Happening invariants;   // Also includes the temporal conditional effects monitors.

    ExecutionContext(Validator * v);

    void addInvariant(const InvariantAction * a);
    void removeInvariant(const InvariantAction * a);
    void addCondAction(const CondCommunicationAction * ca);
    bool removeCondAction(const CondCommunicationAction * ca);
    void setTime(double t);
    void setActiveCtsEffects(ActiveCtsEffects * ace);

    const Happening * getInvariants() const {return &invariants;};
    bool hasInvariants() const;
    ~ExecutionContext();

};


typedef pair<pair<const expression *,bool>, const Environment *> ExprnPair; //bool is true if increasing

struct ActiveFE {

    const FuncExp * fe;
    vector<const ActiveFE*> parentFEs;  //an active FE that this FE depends on, there may be 0 or many

    int colour;     //for topological sort

    vector<ExprnPair> exprns;

    const CtsFunction * ctsFtn;                 //cts fn defining FEs values on interval it is changing on

    FEScalar evaluate(double time) const;   //time since start of active interval;
    bool isLinear() const;

    ActiveFE(const FuncExp * f) : fe(f),ctsFtn(0) {};

    void addParentFE(const ActiveFE * a);
    void removeParentFE(const ActiveFE * a);
    void addParentFEs(const ActiveCtsEffects * ace,const expression * e,const Environment * bs);
   bool appearsInEprsn(const ActiveCtsEffects * ace,const expression * e,const Environment * bs) const;
   bool canResolveToExp(const map<const FuncExp*,ActiveFE*> activeFEs,Validator *) const;

    ~ActiveFE();
};


bool isConstLinearChangeExpr(const ExprnPair & exp,const map<const FuncExp *,ActiveFE *> activeFEs,Validator * vld);
bool isConstant(const expression * exp,const Environment * env,const map<const FuncExp *,ActiveFE *> activeFEs,Validator * vld);
const expression* getRateExpression(const expression* aExpression);

//the following class contains all the active cts effects that are to be updated before each regular happening at
//the same point in time
struct ActiveCtsEffects {
    Happening ctsEffects;               // contains all the active cts effects, length of time is given from the last happening
    map<const FuncExp *, ActiveFE*> activeFEs;  // contains all the active FEs and their dependencies on other FEs, also how to update the FEs
    bool ctsEffectsProcessed;
   mutable Happening ctsUpdateHappening;

    Validator * vld;
    double localUpdateTime; //time since last happening
   double eventTime;

    ActiveCtsEffects(Validator * v);

    void addCtsEffect(const CtsEffectAction * a);
    void removeCtsEffect(const CtsEffectAction * a);

    void setTime(double t);
   void setEventTime(double t) {eventTime =t;};
   double getEventTime() const {return eventTime;};
    void setLocalUpdateTime(double ht);
    void addActiveFEs(bool reCalc = false);
    void addActiveFE(assignment * e,const Environment & bs);
    void buildAFECtsFtns();
    void visitActiveFE(ActiveFE * afe,vector<ActiveFE*> & topSAFEs); //for topological sort
    const Polynomial * buildPoly(const ActiveFE * afe);
    const CtsFunction * buildExp(const ActiveFE * afe);
    const CtsFunction * buildNumericalSoln(const ActiveFE * afe);
    const Happening * getCtsEffects() const {return &ctsEffects;};
    const Happening * getCtsEffectUpdate() const;

    bool hasCtsEffects() const;
  void clearCtsEffects();
    bool areCtsEffectsLinear() const;
    bool isFEactive(const FuncExp * fe) const;

    ~ActiveCtsEffects();
};

struct after {
    double time;
    double tolerance;

    after(double t,double tol) : time(t), tolerance(tol) {};



    bool operator()(const pair<double,Action*> p) const
    {
        return p.first > time + tolerance/10;
    };
};

struct sameTime {
    double time;

    sameTime(double t) : time(t) {};

    bool operator()(const pair<double,Action*> p) const
    {
        return p.first > time;
    };
};

class Plan {
public:
    typedef vector<pair<double,Action*> > timedActionSeq;
// Using a list allows us to add Happenings to the end of the plan without
// invalidating the iterators.
    typedef list<Happening *> HappeningSeq;

private:
    HappeningSeq happenings;
    Validator * vld;
    double timeToProduce;

    struct planBuilder {
        Validator * vld;

        timedActionSeq & tas;
        const operator_list * ops;
        double defaultTime;
        timedActionSeq extras;

        planBuilder(Validator * v,timedActionSeq & ps,
                        const operator_list * os) :
            vld(v), tas(ps), ops(os), defaultTime(1), extras() {};

        void handleDurativeAction(const durative_action *,const const_symbol_list *,double,double,const plan_step * ps);
        void operator()(const plan_step * ps);

    };

public:
    Validator* getValidator() const {return vld;};
    HappeningSeq::const_iterator getFirstHappening() const {return happenings.begin();};
    HappeningSeq::const_iterator getEndHappening() const {return happenings.end();};

    Plan(Validator* v,const operator_list * ops,const plan * p);
    ~Plan()
    {
        for(HappeningSeq::const_iterator i = happenings.begin();
                i != happenings.end();++i)
        {
            delete (*i);
        };

    };

    Happening * lastHappening() const
    {
        if(happenings.size()==0) return 0;

        return happenings.back();

    };


    class const_iterator;


    friend class const_iterator;

    class const_iterator : public
#ifndef OLDCOMPILER
        std::iterator
#endif
#ifdef OLDCOMPILER
        std::forward_iterator
#endif
                <std::input_iterator_tag,const Happening *>
    {
    private:
        int pos;
        const Plan * myPlan;
        double currenttime;     // currenttime will always be the time of the state prevailing.
                                //(Last distinct time! May be different type of happening happenings with same time)

        ExecutionContext ec;    // Records invariant checks.
        ActiveCtsEffects ace;   //Records all the active cts effects

        enum HappeningType {INVARIANT, CTS, REGULAR, END }; //The different types of happening to be executed in that order
                                                    //at each regular happening timestamp if invariants and cts effects exist

        HappeningType executeHappening;

        HappeningSeq::const_iterator i;
                                // The iterator always points at the next happening to be considered
                                // (if there is one), ignoring possible invariant checks.

    public:
        const_iterator(const Plan * p) : pos(0),
            myPlan(p), currenttime(0.0), ec(p->getValidator()), ace(p->getValidator()), executeHappening(REGULAR), i(p->getFirstHappening())
        {
            if(i != p->getEndHappening())
            {
                (*i)->adjustContext(ec);
                (*i)->adjustActiveCtsEffects(ace);

            };
        };

    int operator-(const const_iterator & x)
    {
        return pos - x.pos;
    };

        double getTime()
        {
            if(executeHappening == REGULAR)
                return (*i)->getTime();

            else
            {
                HappeningSeq::const_iterator j = i;
                ++j;
                return (*j)->getTime();
            };


        };


       void deleteActiveFEs()

       {
           for(map<const FuncExp *, ActiveFE*>::iterator j = ace.activeFEs.begin(); j != ace.activeFEs.end(); ++j)
            {    //cout << " deleting"<< *(j->second->fe) <<"\n";
                delete j->second;
            };


              ace.activeFEs.clear();
       };

        bool isRegular() const
        {
            return (executeHappening == REGULAR);
        };

      ActiveCtsEffects * getActiveCtsEffects() {return &ace;};
      ExecutionContext * getExecutionContext() {return &ec;};
      const ActiveCtsEffects * getActiveCtsEffects() const {return &ace;};
      const ExecutionContext * getExecutionContext() const {return &ec;};

        bool isInvariant() const
        {
            return (executeHappening == INVARIANT);
        };

        void toEnd()
        {
            i = myPlan->getEndHappening();
            currenttime = 0;
            executeHappening = END;

        };




        bool operator ==(const const_iterator & c) const
        {
            return currenttime == c.currenttime && executeHappening == c.executeHappening;

        };



        bool operator !=(const const_iterator & c) const
        {
            return !(operator==(c));
        };

        const Happening * operator*() const
        {

            switch(executeHappening) {
              case INVARIANT:

                return ec.getInvariants();
                break;
              case CTS:
                return ace.getCtsEffectUpdate();
                break;
              case REGULAR:
                if(i != myPlan->getEndHappening())
                return *i;
              default:
                break;
             }

          return 0;
        };

        const_iterator & operator++()
        {

            HappeningSeq::const_iterator j = i;
            ++j;
            if((j) == myPlan->getEndHappening())
                {
                    ++i;
                    ++pos;
                    currenttime = 0;
                    executeHappening = END; //set value so we know the plan has finished
                    return *this;
                };

            currenttime = (*(j))->getTime();//

            //value of executeHappening represents the last type of happening to be executed
             switch(executeHappening) {
                 case INVARIANT:


                    if(ace.hasCtsEffects())
                    {
                        handleCtsHappening();
                        return *this;
                    };

                    executeHappening = REGULAR;

                    break;

                 case CTS:

                    executeHappening = REGULAR;

                    break;

                 case REGULAR:

                    if(ec.hasInvariants())
                    {
                        handleInvHappening();
                        (*i)->adjustContextInvariants(ec);
                        (*(j))->adjustContextInvariants(ec);
                        return *this;
                    }
                    else if(ace.hasCtsEffects())
                    {
                        handleCtsHappening();
                        return *this;
                    };


                 default:

                    break;

               };//end of happening type switch

                //deal with regular happenings here
                ++i;

                (*i)->adjustContext(ec);
                (*i)->adjustActiveCtsEffects(ace);

                return *this;

        };

        void handleInvHappening()
        {
             executeHappening = INVARIANT;
             ec.setActiveCtsEffects(&ace); //cout << "inv current time = "<<currenttime<<"\n";
             ec.setTime(currenttime); //same time as next regular happening
       if(ace.getEventTime() > (*i)->getTime()) ace.setLocalUpdateTime(currenttime - ace.getEventTime());
       else ace.setLocalUpdateTime(currenttime - (*i)->getTime());

        };

        void handleCtsHappening()
        {

             executeHappening = CTS;
             ace.setTime(currenttime); //same time as next regular happening
             ace.setLocalUpdateTime(currenttime - (*i)->getTime());  //set value of LocalUpdateTime - time since last regular happening
         if(ace.getEventTime() > (*i)->getTime()) ace.setLocalUpdateTime(currenttime - ace.getEventTime());
         else ace.setLocalUpdateTime(currenttime - (*i)->getTime());  //set value of LocalUpdateTime - time since last regular happening


        };



        const_iterator operator++(int)
        {
            const_iterator ii = *this;
            ++(*this);
            return ii;
        };

    };

    const_iterator begin() const
    {
        return const_iterator(this);
    };


    const_iterator end() const
    {
        const_iterator c(this);
        c.toEnd();
        return c;
    };

    void display() const;
    int length() const;
    double getTime() const {return timeToProduce;};
    double timeOf(const Action * a) const;
    void show(ostream & o) const;
    void addHappening(Happening * h);
};

ostream & operator <<(ostream & o,const Plan & p);
ostream & operator <<(ostream & o,const Happening * h);
inline ostream & operator <<(ostream & o,const Happening & h)
{
    h.write(o);
    return o;
};

void insert_effects(effect_lists * el,effect_lists * more);
Polynomial getPoly(const expression * e,const ActiveCtsEffects * ace,const Environment & bs,CoScalar endInt = 0);
Polynomial getPoly(const expression * e,const ActiveCtsEffects * ace,const Environment * bs,CoScalar endInt = 0);
Polynomial getPoly(const expression * e,bool inc,const ActiveCtsEffects * ace,const Environment & bs,CoScalar endInt = 0);
Polynomial getPoly(const expression * e,bool inc,const ActiveCtsEffects * ace,const Environment * bs,CoScalar endInt = 0);

};

#endif