Program Listing for File TimSupport.h

Return to documentation for file (src/VALfiles/TimSupport.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/>.
 *
 ************************************************************************/

#ifndef __TIMSUPPORT
#define __TIMSUPPORT

#include <algorithm>
#include <iostream>
#include <set>
#include <memory>
#include <iterator>
#include <string.h>

#include "TIMUtilities.h"
#include "TypedAnalyser.h"

#define OUTPUT if(getenv("TIMOUT"))
#define OUTPUT1 if(getenv("TIMOUT") && !strcmp(getenv("TIMOUT"),"Hi"))

using std::multiset;
using std::make_pair;
using std::max;
using std::min;
using std::for_each;
using std::bind2nd;
using std::not1;
using std::mem_fun;


namespace TIM {

class PropertySpace;
class TIMobjectSymbol;
class TIMAnalyser;

class Property {
private:
    VAL::pred_symbol * predicate;
    int posn;

    vector<PropertySpace*> belongTo;
    vector<TIMobjectSymbol*> exhibitors;

    bool isSV;
    bool isReq;

public:
    Property() : predicate(0), isSV(false), isReq(false) {};

    Property(VAL::pred_symbol * p,int a) : predicate(p), posn(a), isSV(false), isReq(false) {};
    void setSV(bool sv,bool rq)
    {
        isSV = sv;
        isReq = rq;
    };
    bool isSingleValued() const {return isSV;};
    bool isRequired() const {return isReq;};
    void write(ostream & o) const
    {
        o << predicate->getName() << "_" << posn;

/*
        o << "[";

        for(vector<pddl_type *>::iterator i = EPS(predicate)->tBegin();
            i != EPS(predicate)->tEnd();++i)
        {
            o << (*i)->getName() << " ";
        };
        o << "]";
*/
    };

    void addIn(PropertySpace * p)
    {
        belongTo.push_back(p);
    };

    typedef vector<PropertySpace *>::iterator SpaceIt;
    SpaceIt begin() {return belongTo.begin();};
    SpaceIt end() {return belongTo.end();};

    void add(TIMobjectSymbol * t)
    {
        exhibitors.push_back(t);
    };

    typedef vector<TIMobjectSymbol *>::iterator ObjectIt;
    ObjectIt oBegin() {return exhibitors.begin();};
    ObjectIt oEnd() {return exhibitors.end();};

    Property * getBaseProperty(const VAL::pddl_type * pt) const;
    vector<Property *> matchers();
    bool matches(const VAL::extended_pred_symbol * prop,VAL::pddl_type * pt);

    bool applicableTo(VAL::TypeChecker & tc,const VAL::pddl_type * tp) const;
    int familySize() const {return EPS(predicate)->arity();};
    int aPosn() const {return posn;};
    const VAL::extended_pred_symbol * root() const {return EPS(predicate);};
    bool equivalent(const Property * p) const;
};

ostream & operator<<(ostream & o, const Property & p);

struct setUpProps {
    unsigned int a;
    VAL::pred_symbol * pred;

    setUpProps(VAL::pred_symbol * p) :
        a(0), pred(p) {};

    void operator()(Property & p)
    {
        p = Property(pred,a);
        ++a;
    };
};

class TIMpredSymbol : public VAL::extended_pred_symbol {
private:
    vector<Property> props;
    typedef map<TIMpredSymbol *,vector<pair<int,int> > > MutexRecords;
    MutexRecords mutexes;

public:
    TIMpredSymbol(VAL::pred_symbol * p,VAL::proposition * q) :
        extended_pred_symbol(p,q), props(q->args->size())
    {
        for_each(props.begin(),props.end(),setUpProps(this));
    };
    template<class TI>
    TIMpredSymbol(pred_symbol * p,TI s,TI e) :
        extended_pred_symbol(p,s,e), props(e-s)
    {
        for_each(props.begin(),props.end(),setUpProps(this));
        EPS(p)->getParent()->add(this);
    };
    Property * property(int a) {return &(props[a]);};
    void setMutex(int p1,TIMpredSymbol * tps,int p2)
    {
        mutexes[tps].push_back(make_pair(p1,p2));
    };
    template<typename TI>
    bool checkMutex(TI sa,TI ea,TIMpredSymbol * pb,TI sb,TI eb)
    {
        MutexRecords::iterator i = mutexes.find(pb);
        if(i == mutexes.end()) return false;
        if(pb == this)
        {
            for(vector<pair<int,int> >::const_iterator p = i->second.begin();
                    p != i->second.end();++p)
            {
                OUTPUT cout << "Examining " << p->first << " " << p->second << "\n";
                if(*(sa+p->first) == *(sb+p->second))
                {
                    // Same object has two copies of the same property.
                    // Now check whether they are identical propositions.
                    for(;sa != ea;++sa,++sb)
                    {
                        if(*sa != *sb) return true;
                    };
                };
            };
        }
        else
        {
            for(vector<pair<int,int> >::const_iterator p = i->second.begin();
                    p != i->second.end();++p)
            {
                OUTPUT cout << "Examining " << p->first << " " << p->second << "\n";
            // Same value has two mutex properties...
                if(*(sa+p->first) == *(sb+p->second)) return true;
            };
        };
        return false;
    };
};

#define TPS(x) static_cast<TIMpredSymbol*>(x)
#define cTPS(x) const_cast<TIMpredSymbol *>(static_cast<const TIMpredSymbol*>(x))

class TIMobjectSymbol : public VAL::const_symbol {
private:
    vector<Property*> initial;
    vector<VAL::proposition *> initialps;
    vector<Property*> final;
    vector<PropertySpace *> spaces;

public:
    TIMobjectSymbol(const string & s) : const_symbol(s) {};
    void addInitial(Property*p,VAL::proposition * prp)
    {
        initial.push_back(p);
        initialps.push_back(prp);
    };
    void addFinal(Property*p) {final.push_back(p);};
    void addIn(PropertySpace * p) {spaces.push_back(p);};
    void distributeStates(TIMAnalyser * tan);
    void write(ostream & o) const
    {
        o << getName();
    };

    const vector<VAL::proposition*> & getInits() const {return initialps;};
    VAL::proposition * find(const Property * p) const
    {
        for(vector<Property*>::const_iterator i = initial.begin();i != initial.end();++i)
        {
            if(p && p->equivalent(*i))
            {
                return initialps[i-initial.begin()];
            };
        };
        return 0;
/*
        vector<Property*>::const_iterator i = std::find(initial.begin(),initial.end(),p);
        if(i == initial.end())
        {
            for(vector<Property*>::const_iterator ii = initial.begin();ii != initial.end();++ii)
            {
                vector<Property*> ps = (*ii)->matchers();
                vector<Property*>::const_iterator j = std::find(ps.begin(),ps.end(),p);
                if(j != ps.end())
                {
                    return initialps[ii-initial.begin()];
                };
            };
            return 0;
        };
        return initialps[i-initial.begin()];
*/
    };
};

ostream & operator <<(ostream & o,const TIMobjectSymbol & t);

#define TOB(x) static_cast<TIM::TIMobjectSymbol*>(x)

class PropertyState {
private:
    typedef multiset<Property *> Properties;
    typedef CascadeMap<Property *,PropertyState> PMap;
    static PMap pmap;

    TIMAnalyser * tan;

    Properties properties;

    template<class TI>
    PropertyState(TIMAnalyser * t,TI s,TI e) : tan(t), properties(s,e) {};

    template<class TI>
    static PropertyState * retrieve(TIMAnalyser * tan,TI s,TI e)
    {
        PropertyState * & ps = pmap.forceGet(s,e);
        if(ps==0)
        {
            ps = new PropertyState(tan,s,e);
        };
        return ps;
    };

public:
    template<class TI>
    static PropertyState * getPS(TIMAnalyser * tan,const VAL::pddl_type * pt,TI s,TI e)
    {
        vector<Property *> props;
        transform(s,e,inserter(props,props.begin()),
                    bind2nd(mem_fun(&Property::getBaseProperty),pt));
        return retrieve(tan,props.begin(),props.end());
    };

    void write(ostream & o) const
    {
        o << "{";
        for_each(properties.begin(),properties.end(),
                    ptrwriter<Property>(o," "));
        o << "}";
    };
    int count(Property * p) const
    {
        return std::count(properties.begin(),properties.end(),p);
    };

    bool contains(Property * p) const
    {
        return std::find(properties.begin(),properties.end(),p) != properties.end();
    };

    bool empty() const
    {
        return properties.empty();
    };

    size_t size() const
    {
        return properties.size();
    };

    typedef Properties::const_iterator PSIterator;

    PSIterator begin() const {return properties.begin();};
    PSIterator end() const {return properties.end();};
    PropertyState * adjust(const PropertyState * del,const PropertyState * add)
    {
// Simple implementation is to remove del from this and then check that the result
// found all entries in del. If so, union add and return a new PropertyState, else
// return 0.
//
// There is probably an issue over types though. For example, if dels are for a more
// specialised type than the entries in this what should happen?

        vector<Property *> ps;
        set_difference(properties.begin(),properties.end(),
                        del->properties.begin(),del->properties.end(),
                        inserter(ps,ps.begin()));
        if(ps.size() + del->properties.size() == properties.size())
        {
            vector<Property *> qs;
            merge(ps.begin(),ps.end(),add->properties.begin(),add->properties.end(),
                        inserter(qs,qs.begin()));
            return retrieve(tan,qs.begin(),qs.end());
        }
        else
        {
            return 0;
        };
    };
    pair<PropertyState *,PropertyState *> split(Property *);
    template<class TI>
    PropertyState * add(TI s,TI e)
    {
        if(s==e) return this;
        vector<Property *> qs;
        merge(properties.begin(),properties.end(),s,e,inserter(qs,qs.begin()));
        return retrieve(tan,qs.begin(),qs.end());
    };
};

ostream & operator<<(ostream & o,const PropertyState & p);

class TransitionRule;
class mRec;

struct recordIn {
    PropertySpace * ps;

    recordIn(PropertySpace * p) : ps(p) {};

    void operator()(Property * p)
    {
        p->addIn(ps);
    };
};

struct countInState {
    Property * prop;

    countInState(Property * p) : prop(p) {};
    int operator()(PropertyState* ps)
    {
        return ps->count(prop);
    };
};

struct recordSV {
    PropertySpace * ps;
    vector<Property *> & sv;

    recordSV(PropertySpace * p,vector<Property *> & s) : ps(p), sv(s) {};

    void operator()(Property * p);
};

// Two facts will be mutex if they define properties that appear in different
// states of the same (SV) property space, or if they define properties that are
// different instantiations for the same object when only one instance of the
// property appears in a state in a (SV) property space.

class PropertySpace {
private:
    set<PropertyState *> states;
    set<TransitionRule *> rules;
    vector<Property *> properties;
    vector<TIMobjectSymbol *> objects;

    bool isStateValued;

    bool isLS;
    bool LSchecked;

public:
    PropertySpace(Property * p,TransitionRule * t);
    PropertySpace(Property * p) :
        states(), rules(), properties(1,p), objects(), isStateValued(true) {};
    void checkStateValued();
    void merge(PropertySpace * ps)
    {
        copy(ps->states.begin(),ps->states.end(),
                    inserter(states,states.end()));
        copy(ps->rules.begin(),ps->rules.end(),
                    inserter(rules,rules.end()));
        copy(ps->properties.begin(),ps->properties.end(),
                    inserter(properties,properties.end()));
        copy(ps->objects.begin(),ps->objects.end(),
                    inserter(objects,objects.end()));
        isStateValued &= ps->isStateValued;

        delete ps;
    };
    vector<int> countsFor(Property * p)
    {
        vector<int> cs;
        transform(states.begin(),states.end(),inserter(cs,cs.begin()),countInState(p));
        return cs;
    };
    void checkSV(vector<Property *> & sv)
    {
        for_each(properties.begin(),properties.end(),recordSV(this,sv));
    };
    void add(TransitionRule * t);
    PropertySpace * finalise()
    {
        for_each(properties.begin(),properties.end(),recordIn(this));
        return this;
    };
    void assembleMutexes();
    void assembleMutexes(TransitionRule *);
//  void assembleMutexes(TransitionRule *,Property *);
    void assembleMutexes(Property *);
    void assembleMutexes(Property *,Property *);
    void assembleMutexes(VAL::operator_ *,const mRec &);
    void recordRulesInActions();
    void add(PropertyState * ps) {states.insert(ps);};
    void add(TIMobjectSymbol * t) {objects.push_back(t);};

    void write(ostream & o) const;
    bool isState() const {return isStateValued;};
    bool isStatic() const {return rules.empty();};
    void sortObjects() {sort(objects.begin(),objects.end());};
    bool contains(TIMobjectSymbol * to) const;
    typedef vector<TIMobjectSymbol *>::const_iterator OIterator;
    OIterator obegin() const {return objects.begin();};
    OIterator oend() const {return objects.end();};
    bool extend();

    bool examine(vector<PropertySpace*> &);
    PropertySpace * slice(Property * p);

    bool applicableTo(VAL::TypeChecker & tc,const VAL::pddl_type * tp) const;

    typedef set<PropertyState*>::const_iterator SIterator;
    SIterator begin() const {return states.begin();};
    SIterator end() const {return states.end();};
    int numStates() const {return states.size();};
    bool isLockingSpace();
};

ostream & operator<<(ostream & o,const PropertySpace & p);

class rulePartitioner;
class RuleObjectIterator;

enum opType {INSTANT = 0,START = 1,MIDDLE = 2,END = 3};

class TransitionRule {
private:
    TIMAnalyser * tan;
    VAL::operator_ * op;
    VAL::derivation_rule * drv;
    opType opt;
    int var;
    PropertyState * enablers;
    PropertyState * lhs;
    PropertyState * rhs;

    vector<VAL::const_symbol*> objects;

    friend class rulePartitioner;
    friend class RuleObjectIterator;

    TransitionRule(TransitionRule * t,PropertyState * e,PropertyState * l,PropertyState * r);

public:
    TransitionRule(TIMAnalyser * t,VAL::operator_ * o,int v,
                    PropertyState * e,PropertyState * l,PropertyState * r,
                    opType ty = INSTANT);

    TransitionRule(TIMAnalyser * t,VAL::derivation_rule * o,int v,
                    PropertyState * e,PropertyState * l,PropertyState * r,
                    opType ty = INSTANT);

    bool isTrivial() const
    {
        return lhs->empty() && rhs->empty();
    };
    bool isAttribute() const
    {
        return lhs->empty() || rhs->empty();
    };
    bool isIncreasing() const
    {
        return lhs->empty() && !rhs->empty();
    };
    bool isDecreasing() const
    {
        return rhs->empty() && !lhs->empty();
    };

    void distributeEnablers();

    void write(ostream & o) const
    {
        o << (*enablers) << " => " << (*lhs) << " -> " << (*rhs) <<
            (isAttribute()?" attribute rule: ":"") <<
            (isIncreasing()?"increasing":"") <<
            (isDecreasing()?"decreasing":"");
    };

    RuleObjectIterator beginEnabledObjects();
    RuleObjectIterator endEnabledObjects();
    PropertyState * tryRule(PropertyState * p)
    {
        return p->adjust(lhs,rhs);
    };
    void assembleMutex(TransitionRule *);
    void assembleMutex(VAL::operator_*,const mRec & pr);
    Property * candidateSplit();
    void recordInAction(PropertySpace * p);
    int paramNum() const {return var;};
    TransitionRule * splitRule(Property * p);
    const PropertyState * getLHS() const {return lhs;};
    const PropertyState * getRHS() const {return rhs;};
    const PropertyState * getEnablers() const {return enablers;};
    const VAL::operator_ * byWhat() const {return op;};
    bool applicableIn(const PropertyState * p) const;
};

ostream & operator<<(ostream & o,const TransitionRule & tr);

typedef vector<TransitionRule *> TRules;


struct ProtoRule {

    TIMAnalyser * tan;
    VAL::operator_ * op;
    VAL::derivation_rule * drv;
    opType opt;
    int var;

    vector<Property *> enablers;
    vector<Property *> adds;
    vector<Property *> dels;

    ProtoRule(TIMAnalyser * t,VAL::operator_ * o,int v,opType ty = INSTANT) :
        tan(t), op(o), drv(0), opt(ty), var(v) {};

    ProtoRule(TIMAnalyser * t,VAL::derivation_rule * o,int v,opType ty = INSTANT) :
        tan(t), op(0), drv(o), opt(ty), var(v) {};

    void insertPre(Property * p)
    {
        enablers.push_back(p);
    };
    void insertAdd(Property * p)
    {
        adds.push_back(p);
    };
    void insertDel(Property * p)
    {
        dels.push_back(p);
    };

    void addRules(TRules & trules);

};


struct processRule {
    TRules & trules;

    processRule(TRules & tr) : trules(tr) {};

    void operator()(ProtoRule * pr)
    {
        if(!pr) return;
        pr->addRules(trules);
        delete pr;
    };
};

struct doExtension {
    bool again;

    doExtension() : again(false) {};

    void operator()(PropertySpace * p)
    {
        again |= p->extend();
    };

    operator bool() {return again;};
};

struct doExamine {
    TIMAnalyser * tan;
    vector<PropertySpace *> newas;

    doExamine(TIMAnalyser * t) : tan(t) {};

    void operator()(PropertySpace * p);

    operator vector<PropertySpace *>() {return newas;};
};

// Need this because mem_fun won't work with non-const methods like sortObjects.
inline void sortObjects(PropertySpace * p)
{
    p->sortObjects();
};

class TIMpred_decl : public VAL::pred_decl {
public:
    TIMpred_decl() : pred_decl(0,0,0) {};
    TIMpred_decl(VAL::pred_symbol * h,VAL::var_symbol_list * a,VAL::var_symbol_table * vt) :
        pred_decl(h,a,vt) {};
    ~TIMpred_decl()
    {
        args = 0;
        var_tab = 0;
    };
};

class DurativeActionPredicateBuilder : public VAL::VisitController {
private:
    bool inserting;
    vector<VAL::pred_symbol *> toIgnore;
    VAL::durative_action * replacePreconditionsOf;
public:
    DurativeActionPredicateBuilder() : VisitController(), inserting(true) {};
    const vector<VAL::pred_symbol *> & getIgnores() const {return toIgnore;};

    void reverse() {inserting = false;};
    virtual void visit_conj_goal(VAL::conj_goal * cg) {
        using namespace VAL;

        replacePreconditionsOf->precondition = cg->getGoals()->front();
        const_cast<goal_list*>(cg->getGoals())->pop_front();
    }

    virtual void visit_timed_goal(VAL::timed_goal* ) {
        replacePreconditionsOf->precondition = 0;
    }

    virtual void visit_durative_action(VAL::durative_action * p)
    {
        using namespace VAL;
//      cout << "Treating " << p->name->getName() << "\n";
        if(inserting) {
            pred_symbol * nm = current_analysis->pred_tab.symbol_put(p->name->getName());
            toIgnore.push_back(nm);
            pred_decl * pd = new TIMpred_decl(nm,p->parameters,p->symtab);
            current_analysis->the_domain->predicates->push_front(pd);
            effect_lists * es = new effect_lists;
            effect_lists * ee = new effect_lists;
            timed_effect * ts = new timed_effect(es,E_AT_START);
            es->add_effects.push_front(new simple_effect(new proposition(nm,p->parameters)));
            timed_effect * te = new timed_effect(ee,E_AT_END);
            ee->del_effects.push_front(new simple_effect(new proposition(nm,p->parameters)));
            p->effects->timed_effects.push_front(ts);
            p->effects->timed_effects.push_front(te);
            timed_goal * tg = new timed_goal(new simple_goal(new proposition(nm,p->parameters),E_POS),E_OVER_ALL);
            if(p->precondition)
            {
                goal_list * gs = new goal_list;
                gs->push_front(tg);
                gs->push_front(p->precondition);
                conj_goal * cg = new conj_goal(gs);
                p->precondition = cg;
            } else {
                p->precondition = tg;
            }
        }
        else
        {
            timed_effect * t = p->effects->timed_effects.front();
            p->effects->timed_effects.pop_front();
            delete t;
            t = p->effects->timed_effects.front();
            p->effects->timed_effects.pop_front();
            delete t;
            replacePreconditionsOf = p;
            goal * oldprecondition = p->precondition;
            p->precondition->visit(this);
            delete oldprecondition;
        };
    };

    virtual void visit_domain(VAL::domain * p)
    {
        visit_operator_list(p->ops);
    };
};

struct CheckSV {
    vector<Property *> & sv;

    CheckSV(vector<Property*> & s) : sv(s) {};

    void operator()(PropertySpace * ps)
    {
        ps->checkSV(sv);
    };
};

class TIMactionSymbol : public VAL::operator_symbol {
private:
    vector<PropertySpace*> stateChanger;
    vector<TransitionRule*> rules;
    bool fixedDuration;

public:
    TIMactionSymbol(const string & nm) : operator_symbol(nm), fixedDuration(false) {};
    void addStateChanger(PropertySpace * ps,TransitionRule * tr)
    {
        stateChanger.push_back(ps);
        rules.push_back(tr);
    };
    void write(ostream & o) const
    {
        o << name;
        if(fixedDuration) o << "!";
    };
    typedef vector<TransitionRule*>::const_iterator RCiterator;
    RCiterator begin() const {return rules.begin();};
    RCiterator end() const {return rules.end();};
    bool hasRuleFor(int prm) const;
    bool isFixedDuration() const
    {
        return fixedDuration;
    };
    void assertFixedDuration()
    {
        fixedDuration = true;
    };
};

inline ostream & operator<<(ostream & o,const TIMactionSymbol & a)
{
    a.write(o);
    return o;
};

#define TAS(x) static_cast<TIM::TIMactionSymbol*>(x)
#define TASc(x) static_cast<const TIM::TIMactionSymbol* const>(x)

class TIMAnalyser : public VAL::VisitController {
private:
    VAL::TypeChecker & tcheck;
    VAL::analysis * an;
    VAL::FuncAnalysis fan;

    bool adding;
    bool initially;
    bool finally;

    bool isDurative;
    bool atStart;
    bool overall;

    VAL::operator_ * op;
    VAL::derivation_rule * drv;
    vector<ProtoRule *> rules;
    TRules trules;
    vector<PropertySpace *> propspaces;
    vector<PropertySpace *> attrspaces;
    vector<PropertySpace *> staticspaces;

    vector<Property*> singleValued;

    void setUpSpaces();

    static void assembleMutexes(PropertySpace *);
    static void recordRulesInActions(PropertySpace *);

    friend class doExamine;

public:
    TIMAnalyser(VAL::TypeChecker & tc,VAL::analysis * a) :
        tcheck(tc), an(a), fan(a->func_tab),
        adding(true), initially(false), finally(false),
        isDurative(false), overall(false), op(0) ,drv(0)
    {};
    VAL::TypeChecker & getTC() {return tcheck;};

    void insertPre(int v,Property * p);
    void insertEff(int v,Property * p);
    void insertGoal(VAL::parameter_symbol * c,Property * p);
    void insertInitial(VAL::parameter_symbol * c,Property * p,VAL::proposition * prp);

    virtual void visit_simple_goal(VAL::simple_goal * p);
    virtual void visit_qfied_goal(VAL::qfied_goal * p)
    {OUTPUT cout << "Quantified goal\n";};
    virtual void visit_conj_goal(VAL::conj_goal * p)
    {p->getGoals()->visit(this);};
    virtual void visit_disj_goal(VAL::disj_goal * p)
    {OUTPUT cout << "Disjunctive goal\n";};
    virtual void visit_timed_goal(VAL::timed_goal * p)
    {
        using namespace VAL;
        if(p->getTime() == (atStart?E_AT_START:E_AT_END) || (overall && p->getTime()==E_OVER_ALL))
            p->getGoal()->visit(this);
    };
    virtual void visit_imply_goal(VAL::imply_goal * p)
    {
        OUTPUT cout << "Implication goal\n";
    };
    virtual void visit_neg_goal(VAL::neg_goal * p)
    {
        OUTPUT cout << "Negative goal\n";
    };
    virtual void visit_simple_effect(VAL::simple_effect * p);
    virtual void visit_simple_derivation_effect(VAL::derivation_rule * p);
    virtual void visit_forall_effect(VAL::forall_effect * p)
    {
        OUTPUT cout << "Quantified effect\n";
    };
    virtual void visit_cond_effect(VAL::cond_effect * p)
    {
        OUTPUT cout << "Conditional effect\n";
    };
    virtual void visit_timed_effect(VAL::timed_effect * p)
    {
        using namespace VAL;
        if(p->ts==(atStart?E_AT_START:E_AT_END))
            p->effs->visit(this);
    };
    virtual void visit_effect_lists(VAL::effect_lists * p)
    {
        using namespace VAL;
        p->add_effects.pc_list<simple_effect*>::visit(this);
        p->forall_effects.pc_list<forall_effect*>::visit(this);
        p->cond_effects.pc_list<cond_effect*>::visit(this);
        p->timed_effects.pc_list<timed_effect*>::visit(this);
        bool whatwas = adding;
        adding = !adding;
        p->del_effects.pc_list<simple_effect*>::visit(this);
        adding = whatwas;
    };
    virtual void visit_derivation_rule(VAL::derivation_rule * p)
    {
        drv = p;
        adding = true;
        rules = vector<ProtoRule*>(p->get_head()->args->size(),0);
        p->get_body()->visit(this);
        visit_simple_derivation_effect(p);
        for_each(rules.begin(),rules.end(),processRule(trules));
        drv = 0;
    };
    virtual void visit_operator_(VAL::operator_ * p)
    {
        op = p;
        adding = true;
        rules = vector<ProtoRule*>(p->parameters->size(),0);
        p->precondition->visit(this);
        p->effects->visit(this);
        for_each(rules.begin(),rules.end(),processRule(trules));
        op = 0;
    };
    virtual void visit_action(VAL::action * p)
    {
        visit_operator_(p);
    }
    virtual void visit_durative_action(VAL::durative_action * p)
    {
// I think that we can do this in two stages - the at start and the at end.
// We can have a filter on timed goals and effects that decides whether it
// is relevant. Might need to store an optype flag with op, so that we can
// tell whether we generated from a start or end point.
//
// The tricky bit is the linkage: we need record invariants and we also need
// to ensure that we don't lose state change across durative actions. Toni's
// idea is to have a dummy add effect at start that is preconditioned and deleted
// at the end. That should work, but needs a couple of tweaks:
// 1: If the action has several state change effects then this technique will leave
//    them linked together in one state space. Not entirely clear how these could be
//    split, but maybe we can use a technique that generalises the state splitting
//    idea (ab->c, c->ab becomes a->c, c->a and b->c', c'->b).
// 2: The mechanism artificially creates increasing/decreasing effects if there was
//    actually no property that was unlinked before introducing the dummies. We can
//    filter these cases out, I think.
//

        isDurative = true;
        atStart = true;
        overall = false;
        visit_operator_(p);
        atStart = false;
        visit_operator_(p);
        overall = true;
        visit_operator_(p);
        overall = false;
        isDurative = false;
    };
    virtual void visit_domain(VAL::domain * p)
    {
        visit_operator_list(p->ops);
        if (p->drvs) visit_derivations_list(p->drvs);
        setUpSpaces();
    };
    virtual void visit_problem(VAL::problem * p)
    {
        initially = true;
        if (p->initial_state) p->initial_state->visit(this);
        initially = false;
        finally = true;
        if(p->the_goal) p->the_goal->visit(this);
        finally = false;
        if(p->objects) p->objects->visit(this);
        for_each(propspaces.begin(),propspaces.end(),&sortObjects);
        vector<PropertySpace*>::iterator a =
            partition(propspaces.begin(),propspaces.end(),
                    mem_fun(&PropertySpace::isState));
        copy(a,propspaces.end(),inserter(attrspaces,attrspaces.begin()));
        propspaces.erase(a,propspaces.end());
        a = partition(propspaces.begin(),propspaces.end(),
                    not1(mem_fun(&PropertySpace::isStatic)));
        copy(a,propspaces.end(),inserter(staticspaces,staticspaces.end()));
        propspaces.erase(a,propspaces.end());

        while(for_each(attrspaces.begin(),attrspaces.end(),doExtension()));
        while(for_each(propspaces.begin(),propspaces.end(),doExtension()));

        OUTPUT1 {
            for_each(trules.begin(),trules.end(),ptrwriter<TransitionRule>(cout,"\n"));
            for_each(propspaces.begin(),propspaces.end(),
                        ptrwriter<PropertySpace>(cout,"\n"));
        };

        for_each(propspaces.begin(),propspaces.end(),assembleMutexes);
        for_each(propspaces.begin(),propspaces.end(),recordRulesInActions);
        attrspaces = for_each(attrspaces.begin(),attrspaces.end(),doExamine(this));

        OUTPUT1 {
            cout << "Spaces now look like this:\n";
            for_each(propspaces.begin(),propspaces.end(),
                        ptrwriter<PropertySpace>(cout,"\n"));
        };
    };
    virtual void visit_const_symbol(VAL::const_symbol * p)
    {
        TIMobjectSymbol * t = dynamic_cast<TIMobjectSymbol*>(p);
        t->distributeStates(this);
    };
    void checkSV()
    {
        for_each(propspaces.begin(),propspaces.end(),CheckSV(singleValued));
    };

    set<PropertySpace *> relevant(VAL::pddl_type * tp);
    void close(set<Property*> & seed,const VAL::pddl_type * pt);

    typedef vector<PropertySpace *>::const_iterator const_iterator;
    const_iterator pbegin() const {return propspaces.begin();};
    const_iterator pend() const {return propspaces.end();};
    const_iterator abegin() const {return attrspaces.begin();};
    const_iterator aend() const {return attrspaces.end();};
    const_iterator sbegin() const {return staticspaces.begin();};
    const_iterator send() const {return staticspaces.end();};
};

class mutex;

struct mRec {
    Property * first;
    int second;
    opType opt;

    mRec(Property * x,int y,opType z) : first(x), second(y), opt(z) {};

    bool operator<(const mRec & m) const
    {
        return (first < m.first || (first == m.first &&
                    second < m.second) || opt < m.opt);
    };
};

struct pairWith {
    int v;
    opType oo;
    pairWith(int x,opType o) : v(x), oo(o) {};

    mRec operator() (Property * o)
    {
        return mRec(o,v,oo);
    };
};

class MutexStore {
private:
    typedef map<VAL::operator_ *,mutex *> MutexRecord;
    MutexRecord mutexes;

// These are the enablers
    set<mRec> enablers;
    set<mRec> conditions;
// These are the invariants
    set<mRec> invariants;

public:
    virtual ~MutexStore() {};

    mutex * getMutex(VAL::operator_ * o);
    void showMutexes();

    template<class TI>
    void add(TI s,TI e,int v,opType o)
    {
        transform(s,e,inserter(enablers,enablers.begin()),pairWith(v,o));
    };
    void addCondition(Property * p,int v,opType o)
    {
        conditions.insert(mRec(p,v,o));
    };
    void addInvariant(Property * p,int v)
    {
        invariants.insert(mRec(p,v,MIDDLE));
    };
    void additionalMutexes();
};

#define MEX(x) dynamic_cast<TIM::MutexStore *>(x)

class TIMaction : public VAL::action, public MutexStore {
public:
    TIMaction(VAL::operator_symbol* nm,
        VAL::var_symbol_list* ps,
        VAL::goal* pre,
        VAL::effect_lists* effs,
        VAL::var_symbol_table* st) : action(nm,ps,pre,effs,st)
      {};
};

#define TAc(x) static_cast<TIM::TIMaction*>(x)

class TIMdurativeAction : public VAL::durative_action, public MutexStore {
public:
    bool isFixedDuration() const
    {
        return static_cast<TIMactionSymbol*>(name)->isFixedDuration();
    };
};

#define TDA(x) dynamic_cast<TIM::TIMdurativeAction*>(x)

void showMutex(VAL::operator_ * op);
void completeMutexes(VAL::operator_ * op);

/* MUTEX RELATIONSHIPS:
 *
 *  As, Am, Ae, Bs, Bm, Be:
 *
 *      AsxBs, AsxBm, AsxBe    1  2  3
 *      AmxBs, AmxBm, AmxBe    4  5  6
 *      AexBs, AexBm, AexBe    7  8  9
 *
 */

enum MutexTypes { NONE = 0,START_START = 1, START_MID = 2, START_END = 4,
                  MID_START = 8, MID_MID = 16, MID_END = 32,
                  END_START = 64, END_MID = 128, END_END = 256};



struct mutRec {
    int first;
    int second;

    opType one;
    opType other;

    mutRec(int a,int b,opType x = INSTANT,opType y = INSTANT) :
        first(a), second(b), one(x), other(y) {};

    bool operator==(const mutRec & m) const
    {
        return first == m.first && second == m.second && one == m.one && other == m.other;
    };

    bool operator!=(const mutRec & m) const
    {
        return !(*this == m);
    };

    bool operator<(const mutRec & m) const
    {
        return (first < m.first ||
                    (first == m.first && (second < m.second ||
                        (second == m.second && (one < m.one ||
                            (one == m.one && other < m.other))))));
    };

};

template<class TI>
TI getIx(TI s,int x)
{
    while(x > 0)
    {
        ++s;
        --x;
    };
    return s;
};

class mutex {
private:
    VAL::operator_ * op1;
    VAL::operator_ * op2;
    set<mutRec> argPairs;

public:
    mutex(VAL::operator_ * o1,VAL::operator_ * o2) :
        op1(o1), op2(o2)
    {};

    static void constructMutex(VAL::operator_ * o1,int a1,VAL::operator_ * o2,int a2,
                    opType t1 = INSTANT,opType t2 = INSTANT)
    {
        OUTPUT cout << "Adding a mutex between " << o1->name->getName() << ":" << a1 << " and "
            << o2->name->getName() << ":" << a2 << "\n";
        mutex * m = MEX(o1)->getMutex(o2);
// This condition ensures that we don't store the same mutex pair in both orders
// when they are arguments for the same operator. This is good if we are going to
// use the pairs for checking, but it could be less good if we want to check whether
// a specific pair of op-args are mutex.
        if(o1==o2)
        {
            int a = min(a1,a2);
            if(a2 == a)
            {
                opType t3 = t1;
                t1 = t2;
                t2 = t3;
            };
            a2 = max(a1,a2);
            a1 = a;
        }
        else if(m->op2==o1)
        {
            int a = a1;
            a1 = a2;
            a2 = a;
            opType t = t1;
            t1 = t2;
            t2 = t;
        };
        if(m->argPairs.find(mutRec(a1,a2,t1,t2)) == m->argPairs.end())
        {
//      cout << "Inserting " << a1 << ":" << a2 << "\n";
            m->argPairs.insert(mutRec(a1,a2,t1,t2));
        };
    };

    void write(ostream & o) const;

    template<class TI>
    unsigned int getMutexes(VAL::operator_* A,TI sa,TI ea,TI sb,TI eb)
    {
        unsigned int ms = NONE;
        if(A==op2)
        {
            TI x = sa;
            sa = sb;
            sb = x;
            x = ea;
            ea = eb;
            eb = x;
        };

        for(set<mutRec>::const_iterator i = argPairs.begin();i != argPairs.end();++i)
        {
            if(*(getIx(sa,i->first))==*(getIx(sb,i->second)))
            {
//          cout << "Mutex for " << i->first << " " << **(getIx(sa,i->first)) << " and " << i->second
//                  << " " << **(getIx(sb,i->second)) << " " << i->one << " " << i->other << " " << 3*(i->one?i->one:1)+(i->other?i->other:1)
//                  << "\n";
                ms |= 1 << 3*(i->one?i->one-1:0)+(i->other?i->other-1:0);
            };
        };
        return ms;
    };
    template<class TI>
    bool selfMutex(TI sa,TI ea)
    {
        for(set<mutRec>::const_iterator i = argPairs.begin();i != argPairs.end();++i)
        {
            if(i->first != i->second &&
                    *(getIx(sa,i->first))==*(getIx(sa,i->second)))
            {
                return true;
            };
        };
        return false;
    };
};

inline ostream & operator<<(ostream & o,const mutex & m)
{
    m.write(o);
    return o;
};

template<class TI>
unsigned int getMutexes(VAL::operator_ * A,TI sa,TI ea,VAL::operator_ * B,TI sb,TI eb)
{
    return MEX(A)->getMutex(B)->getMutexes(A,sa,ea,sb,eb);
};

template<class TI>
bool isMutex(const VAL::pred_symbol * pa,TI sa,TI ea,const VAL::pred_symbol * pb,TI sb,TI eb)
{
    return cTPS(pa)->checkMutex(sa,ea,cTPS(pb),sb,eb);
};

template<class TI>
bool selfMutex(const VAL::operator_ * op,TI sa,TI ea)
{
    TIM::MutexStore * tm = MEX(const_cast<VAL::operator_ *>(op));
    if(tm)
    {
            return tm->getMutex(const_cast<VAL::operator_*>(op))->selfMutex(sa,ea);
    }
    else
    {
            return false;
    };
};

class TIMfactory : public VAL::StructureFactory {
public:
    virtual VAL::action * buildAction(VAL::operator_symbol* nm,
        VAL::var_symbol_list* ps,
        VAL::goal* pre,
        VAL::effect_lists* effs,
        VAL::var_symbol_table* st) {return new TIMaction(nm,ps,pre,effs,st);};
    virtual VAL::durative_action * buildDurativeAction()
    {
        return new TIMdurativeAction();
    };
};

};

#endif