From 21571c20a10d692382b7d200fbf8dd8db8a498cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20L=C3=BChne?= Date: Thu, 25 Jan 2018 16:50:51 +0100 Subject: [PATCH] Initial commit with Madagascar 2016-01-22 --- Cground.c | 109 ++ Makefile | 74 ++ README | 17 + asyntax.c | 784 +++++++++++++ asyntax.h | 188 +++ build | 1 + clausedb.c | 491 ++++++++ clausedb.h | 91 ++ clausesets.c | 1840 +++++++++++++++++++++++++++++ clausesets.h | 12 + cleanup.c | 259 +++++ cleanup.h | 4 + dimacs.h | 4 + dimacsinput.c | 157 +++ dimacsinput.h | 4 + ground.c | 812 +++++++++++++ heuristics2.c | 828 +++++++++++++ interface.h | 265 +++++ intsets.c | 196 ++++ intsets.h | 75 ++ invariants.c | 605 ++++++++++ invariants.h | 7 + learn2.c | 335 ++++++ lexer.lex | 161 +++ main.c | 755 ++++++++++++ main.h | 71 ++ makedate | 4 + operators.c | 1867 ++++++++++++++++++++++++++++++ operators.h | 167 +++ ordintsets.c | 291 +++++ ordintsets.h | 26 + parser.y | 211 ++++ plan | 1 + printplan.c | 291 +++++ printplan.h | 8 + scc.c | 201 ++++ scc.h | 12 + shortcuts.c | 123 ++ tables.c | 296 +++++ tables.h | 39 + translate2sat.c | 2938 +++++++++++++++++++++++++++++++++++++++++++++++ translate2sat.h | 40 + varvals.c | 364 ++++++ zPOSTF | 1 + zPREF | 1 + 45 files changed, 15026 insertions(+) create mode 100644 Cground.c create mode 100644 Makefile create mode 100644 README create mode 100644 asyntax.c create mode 100644 asyntax.h create mode 100755 build create mode 100644 clausedb.c create mode 100644 clausedb.h create mode 100644 clausesets.c create mode 100644 clausesets.h create mode 100644 cleanup.c create mode 100644 cleanup.h create mode 100644 dimacs.h create mode 100644 dimacsinput.c create mode 100644 dimacsinput.h create mode 100644 ground.c create mode 100644 heuristics2.c create mode 100644 interface.h create mode 100644 intsets.c create mode 100644 intsets.h create mode 100644 invariants.c create mode 100644 invariants.h create mode 100644 learn2.c create mode 100644 lexer.lex create mode 100644 main.c create mode 100644 main.h create mode 100755 makedate create mode 100644 operators.c create mode 100644 operators.h create mode 100644 ordintsets.c create mode 100644 ordintsets.h create mode 100644 parser.y create mode 100755 plan create mode 100644 printplan.c create mode 100644 printplan.h create mode 100644 scc.c create mode 100644 scc.h create mode 100644 shortcuts.c create mode 100644 tables.c create mode 100644 tables.h create mode 100644 translate2sat.c create mode 100644 translate2sat.h create mode 100644 varvals.c create mode 100644 zPOSTF create mode 100644 zPREF diff --git a/Cground.c b/Cground.c new file mode 100644 index 0000000..4cb70ea --- /dev/null +++ b/Cground.c @@ -0,0 +1,109 @@ + +cfma Cgroundfma(Sfma *,int *); + +void Cgroundfmalist(Sfmalist *fs,int *ptr,int *b) { + while(fs != NULL) { + *(ptr++) = Cgroundfma(fs->hd,b); + fs = fs->tl; + } +} + +cfma Cgroundfma(Sfma *sf,int *b) { + int *vals; + int i,cnt; + Sfmalist *fs; + cfma f; + + switch(Sfmatypeof(sf)) { + + case STRUE: return cTRUE; + case SFALSE: return cFALSE; + + case Sconj: + f = (cfma)malloc(sizeof(int *) * (sf->cnt + 1)); + Cgroundfmalist(sf->juncts,f+1,b); + f[0] = 1+(sf->cnt << 1); + return f; + + case Sdisj: + f = (cfma)malloc(sizeof(int *) * (sf->cnt + 1)); + Cgroundfmalist(sf->juncts,f+1,b); + f[0] = (sf->cnt << 1); + return f; + + case Seq: + if(bvalue(sf->p1,b) == bvalue(sf->p2,b)) { + return cTRUE; + } else { + return cFALSE; + } + + case Sneq: + if(bvalue(sf->p1,b) == bvalue(sf->p2,b)) { + return cFALSE; + } else { + return cTRUE; + } + + case Spatom: return cPATOM(atomindex(sf->a,b)); + + case Snatom: return cNATOM(atomindex(sf->a,b)); + + case Sforall: /* Iterate over all values of the variable. */ + + cnt = getdomainsize(sf->ss->t); + + f = (cfma)malloc(sizeof(int *) * (cnt + 1)); + + f[0] = (cnt << 1) + 1; + + vals = getdomain(sf->ss->t); + + for(i=0;iss->v] = vals[i]; + f[i+1] = Cgroundfma(sf->f,b); + } + + return f; + + case Sforsome: /* Iterate over all values of the variable. */ + + cnt = getdomainsize(sf->ss->t); + + f = (cfma)malloc(sizeof(int *) * (cnt + 1)); + + f[0] = (cnt << 1); + + vals = getdomain(sf->ss->t); + + for(i=0;iss->v] = vals[i]; + f[i+1] = Cgroundfma(sf->f,b); + } + + return f; + + } +} + +void printcfma(cfma f) { + int i; + if(((int)f)&1) { /* Atom */ + switch(((int)f)&7) { + case cTRUEtag: printf("TRUE"); break; + case cFALSEtag: printf("FALSE"); break; + case cPATOMtag: printatomi((((int)f) >> 3)); break; + case cNATOMtag: printf("NOT "); printatomi((((int)f) >> 3)); break; + } + } else { + int cnt; + if(((int)(*f))&1) printf("(AND"); else printf("(OR"); + cnt = ((int)(*f)) >> 1; + for(i=0;i +#include +#include +#include + +#include "asyntax.h" +#include "tables.h" +#include "intsets.h" +#include "ordintsets.h" +#include "operators.h" +#include "main.h" + +#define noDEBUG 1 + +#include "parser.tab.h" + +//void printlitarr(int *ptr) { +// if(*ptr == -1) { printf("NOTHING TO PRINT"); } +// while(*ptr != -1) { +// if((*ptr)&1) printf("NOT "); else printf("."); +// printatomi((*ptr) >> 1); +// ptr ++; +// } +// printf("\n"); +//} + +/* DESTRUCTIVE negation of a formula */ + +Sfma *Sneg(Sfma *f) { + Sfmalist *l; + switch(f->t) { + case STRUE: f->t = SFALSE; break; + case SFALSE: f->t = STRUE; break; + case Spatom: f->t = Snatom; break; + case Snatom: f->t = Spatom; break; + case Sconj: + f->t = Sdisj; + l = f->juncts; + while(l != NULL) { + Sneg(l->hd); + l = l->tl; + } + break; + case Sdisj: + f->t = Sconj; + l = f->juncts; + while(l != NULL) { + Sneg(l->hd); + l = l->tl; + } + break; + case Sforall: f->t = Sforsome; Sneg(f->f); break; + case Sforsome: f->t = Sforall; Sneg(f->f); break; + case Seq: f->t = Sneq; break; + case Sneq: f->t = Seq; break; + } + return f; +} + +/* constructors for schematic formulae */ + +Sfma* Sdisjunction(Sfmalist *fs) { + Sfma *f = (Sfma*)statmalloc(20,sizeof(Sfma)); + f->t = Sdisj; + f->juncts = fs; + return f; +} + +Sfma* Sconjunction(Sfmalist *fs) { + Sfma *f = (Sfma*)statmalloc(21,sizeof(Sfma)); + f->t = Sconj; + f->juncts = fs; + return f; +} + +Sfma* Satom(atom a) { + Sfma *f = (Sfma*)statmalloc(22,sizeof(Sfma)); + f->t = Spatom; + f->a = a; + return f; +} + +Sfma* Sfalse() { + Sfma *f = (Sfma*)statmalloc(23,sizeof(Sfma)); + f->t = SFALSE; + return f; +} + +Sfma* Strue() { + Sfma *f = (Sfma*)statmalloc(24,sizeof(Sfma)); + f->t = STRUE; + return f; +} + +Sfma* Sfmaforall(typedvarlist *ss, Sfma *f) { + Sfma *f1 = (Sfma*)statmalloc(25,sizeof(Sfma)); + f1->t = Sforall; + f1->ss = ss; + f1->f = f; + return f1; +} + +Sfma* SconstantTRUE() { + Sfma *f = (Sfma*)statmalloc(26,sizeof(Sfma)); + f->t = STRUE; + return f; +} + +Sfma* Sfmaforsome(typedvarlist *ss, Sfma *f) { + Sfma *f1 = (Sfma*)statmalloc(27,sizeof(Sfma)); + f1->t = Sforsome; + f1->ss = ss; + f1->f = f; + return f1; +} + +Sfma* SfmaEQ(int p1, int p2) { + Sfma *f1 = (Sfma*)statmalloc(28,sizeof(Sfma)); + f1->t = Seq; + f1->p1 = p1; + f1->p2 = p2; + return f1; +} + +/******* Accessors ********/ + +Sfmatype Sfmatypeof(Sfma *f) { + return f->t; +} + +//atom *makeatom(int pr,intlist *pars) { +// atom a = (atom)statmalloc(29,sizeof(atom)); +// a->pred = pr; +// a->params = pars; +// return a; +//} + +/* Printing */ + +void printSfmalist(Sfmalist *); +void printSefflist(Sefflist *); + +void printatom(atom a) { + int n,i; + printf("%s(",symbol(a[0])); + n = a[1]; + for(i=2;iv),symbol(ss->t)); + if(ss->tl != NULL) printf(" "); + ss = ss->tl; + } + printf(")"); +} + +void printSfma(Sfma *f) { + switch(Sfmatypeof(f)) { + case STRUE: printf("TRUE"); break; + case SFALSE: printf("FALSE"); break; + case Seq: printf(" (= %s %s)",symbol(f->p1),symbol(f->p2)); break; + case Sneq: printf(" (not (= %s %s))",symbol(f->p1),symbol(f->p2)); break; + case Spatom: printatom(f->a); break; + case Snatom: printf("(not "); printatom(f->a); printf(")"); break; + case Sdisj: printf("(or "); printSfmalist(f->juncts); printf(")"); break; + case Sconj: printf("(and "); printSfmalist(f->juncts); printf(")"); break; + case Sforall: printf("(forall "); printtypedvars(f->ss); printSfma(f->f); printf(")"); break; + case Sforsome: printf("(exists "); printtypedvars(f->ss); printSfma(f->f); printf(")"); break; + + } +} + +void printSfmalist(Sfmalist *fs) { + while(fs != NULL) { + printSfma(fs->hd); + printf(" "); + fs = fs->tl; + } +} + +void printSeff(Seff *); +void printSefflist(Sefflist *fs) { + while(fs != NULL) { + printSeff(fs->hd); + printf(" "); + fs = fs->tl; + } +} + +void printSeff(Seff *e) { + switch(e->t) { + case SEpatom: printatom(e->a); break; + case SEnatom: printf("(not "); printatom(e->a); printf(")"); break; + case SEconj: printf("(and "); printSefflist(e->juncts); printf(")"); break; + case SEforall: printf("(forall "); printtypedvars(e->ss); printSeff(e->effect); printf(")"); break; + case SEwhen: + printf("(when "); + printSfma(e->cond); + printf(" "); + printSeff(e->effect); + printf(")"); + break; + } +} + +void printSaction(Saction *a) { + typedvarlist *l; + printf(":action %s(",symbol(a->name)); + l = a->params; + while(l != NULL) { + printf("%s",symbol(l->v)); + if(l->t) printf(":%s",symbol(l->t)); + else printf(":UNIV"); + if(l->tl != NULL) printf(" "); + l = l->tl; + } + printf(") (COST %i)\n",a->cost); + printSfma(a->precon); + printf("\n"); + printSeff(a->effect); + printf("\n\n"); +} + +/* constructors for schematic effects */ + +Seff* SPeffatom(atom a) { + Seff *e = (Seff *)statmalloc(30,sizeof(Seff)); + e->t = SEpatom; + e->a = a; + return e; +} + +Seff* SNeffatom(atom a) { + Seff *e = (Seff *)statmalloc(31,sizeof(Seff)); + e->t = SEnatom; + e->a = a; + return e; +} + + +Seff* Seffconjunction(Sefflist *efs) { + Seff *e = (Seff *)statmalloc(32,sizeof(Seff)); + e->t = SEconj; + e->juncts = efs; + return e; +} + +Seff* Seffwhen(Sfma *c,Seff *e) { + Seff *e1 = (Seff *)statmalloc(33,sizeof(Seff)); + e1->t = SEwhen; + e1->cond = c; + e1->effect = e; + return e1; +} + +Seff* Seffforall(typedvarlist *p,Seff *e) { + Seff *e1 = (Seff *)statmalloc(34,sizeof(Seff)); + e1->t = SEforall; + e1->ss = p; + e1->effect = e; + return e1; +} + +int listlen(intlist *l) { + int len = 0; + while(l != NULL) { + len = len+1; + l = l->tl; + } + return len; +} + +/* Create atom */ + +atom newatom(int s,intlist *p) { + int len,i; + int *a; + len = listlen(p); + a = (atom)statmalloc(35,sizeof(int) * (len+2)); + a[0] = s; + a[1] = len; + i = 2; + while(p != NULL) { + a[i++] = p->hd; + p = p->tl; + } + return a; +} + +/* PDDL domain definitions */ + +int nOfTypes; + +#define MAXOBTYPES 1000 +obtype Stypes[MAXOBTYPES]; +int *AStypes[MAXOBTYPES]; +int *AStypesCARD[MAXOBTYPES]; + +#define MAXSCHEMATICACTIONS 10000 + +Sfma *Sgoal; + +void initPDDL() { + nOfSActions = 0; + maxSActions = MAXSCHEMATICACTIONS; + Sactions = (Saction *)statmalloc(36,sizeof(Saction) * maxSActions); + nOfTypes = 0; + Sgoal = (Sfma *)0; + Sactions[0].precon = NULL; + Sactions[0].effect = NULL; + Sactions[0].params = NULL; + Sactions[0].cost = 0.0; +} + +/* Definitions */ + + +/* Typed var lists */ + +typedvarlist *TVappend(typedvarlist *l1,typedvarlist *l2) { + if(l1 == NULL) { + return l2; + } else { + typedvarlist *l3 = TVappend(l1->tl,l2); + typedvarlist *l4 = (typedvarlist *)statmalloc(37,sizeof(typedvarlist)); + l4->v = l1->v; + l4->t = l1->t; + l4->tl = l3; + return l4; + } +} + +/* For a (possibly untyped) list of variables, assign a type */ + +typedvarlist *withtype(int t,intlist *ss) { + typedvarlist *l; + if(ss == NULL) return NULL; + l = (typedvarlist *)statmalloc(38,sizeof(typedvarlist)); + l->v = ss->hd; + l->t = t; + l->tl = withtype(t,ss->tl); + return l; +} + +/* Add a new action */ + +void checkSactionsSize() { + if(nOfSActions >= maxSActions-1) { + maxSActions = maxSActions * 2; + Sactions = (Saction *)realloc(Sactions,maxSActions * sizeof(Saction)); + assert(Sactions != NULL); + } +} + +void addnewaction(int name) { + nOfSActions += 1; + checkSactionsSize(); + Sactions[nOfSActions-1].name = name; + if(Sactions[nOfSActions-1].effect == NULL) { + fprintf(stderr,"ERROR: action has not effect.\n"); + exit(1); + } + if(Sactions[nOfSActions-1].precon == NULL) { + Sactions[nOfSActions-1].precon = SconstantTRUE(); + } + /* Next action */ + Sactions[nOfSActions].precon = NULL; + Sactions[nOfSActions].effect = NULL; + Sactions[nOfSActions].params = NULL; + Sactions[nOfSActions].cost = 0.0; +} + +/* The following three are called by the parser BEFORE addnewaction */ + +void addactionparameters(typedvarlist *params) { + Sactions[nOfSActions].params = params; +} + +void addactionprecond(Sfma *p) { + Sactions[nOfSActions].precon = p; +} + +void addactioncost(int cost) { + // printf("Action cost %i.\n",cost); + Sactions[nOfSActions].cost = cost; +} + +/* Go through the predicates in an action effect and mark non-static ones. */ + +void checkifstatic(Seff *e) { + atom a; + Sefflist *es; + switch(e->t) { + case SEpatom: + case SEnatom: + a = e->a; + setnonstatic(a[0]); + break; + case SEconj: + es = e->juncts; + while(es != NULL) { + checkifstatic(es->hd); + es = es->tl; + } + break; + case SEwhen: + case SEforall: + checkifstatic(e->effect); break; + default: + break; + } +} + +void addactioneffect(Seff *e) { + Sactions[nOfSActions].effect = e; + checkifstatic(e); +} + +/* Requirements */ + +void checkrequirements(intlist *l) { + while(l != NULL) { + if(strcmp(symbol(l->hd),":strips") == 0) { + } else if(strcmp(symbol(l->hd),":conditional-effects") == 0) { + } else if(strcmp(symbol(l->hd),":adl") == 0) { + } else if(strcmp(symbol(l->hd),":typing") == 0) { + } else if(strcmp(symbol(l->hd),":equality") == 0) { + } else if(strcmp(symbol(l->hd),":typing") == 0) { + } else if(strcmp(symbol(l->hd),":conditional-effects") == 0) { + } else if(strcmp(symbol(l->hd),":negative-preconditions") == 0) { + } else if(strcmp(symbol(l->hd),":quantified-preconditions") == 0) { + } else if(strcmp(symbol(l->hd),":action-costs") == 0) { + } else { + fprintf(stderr,"WARNING: unsupported :requirement %s\n",symbol(l->hd)); + } + + if(strcmp(symbol(l->hd),":action-costs") == 0) { + fprintf(stderr,"WARNING: will ignore action costs\n"); + } + + l = l->tl; + } +} + + /* Handling types and objects */ + +int member(int i,intlist *l) { + while(l != NULL) { + if(l->hd == i) return 1; + l = l->tl; + } + return 0; +} + +/* Destructive addition of a non-duplicate element to a NON-EMPTY list */ +intlist *addtolist(int s,intlist *l) { + if(member(s,l)) return l; + return intcons(s,l); +} + +void addobject(int v,int t) { + int i; + i = 0; + while(iv,UNIVTYPE); + addobject(cs->v,cs->t); + cs = cs->tl; + } +} + +/* Type definitions */ + +void addsubtype(int t1,int t2) { + int i; + i = 0; + while(iv,ts->t); + ts = ts->tl; + } +} + +void processtypes() { + int i; + intlist *il,*il2; + + /* Extend subtypes and supertypes to non-immediate ones. */ + for(i=0;ihd,il2->hd); + addsupertype(il->hd,il2->hd); + il2 = il2->tl; + } + il = il->tl; + } + } + + if(flagShowInput) { + for(i=0;ihd)); + il = il->tl; + } + printf("\n"); + printf(" SUBTYPES:"); + il = Stypes[i].subtypes; + while(il != NULL) { + printf(" %s",symbol(il->hd)); + il = il->tl; + } + printf("\n"); + printf(" SUPERTYPES:"); + il = Stypes[i].supertypes; + while(il != NULL) { + printf(" %s",symbol(il->hd)); + il = il->tl; + } + printf("\n"); + } + } + + /* Add objects of a type to all its supertypes. */ + for(i=0;ihd,il2->hd); + il2 = il2->tl; + } + il = il->tl; + } + } +} + + /* PDDL problem definitions */ + +/* Add objects to a type. */ + +void storeobjects(typedvarlist *cs) { + while(cs != NULL) { + addobject(cs->v,UNIVTYPE); + addobject(cs->v,cs->t); + cs = cs->tl; + } +} + +void storeinit(atomlist *a) { + int cnt,i; + cnt = listlen(a); + Sinit = (atom *)malloc((cnt+1) * sizeof(atom)); + for(i=0;ihd; + a = a->tl; + } + Sinit[cnt] = NULL; +} + +void storegoal(Sfma *f) { + Sgoal = f; +} + +/* Domain name */ + +int domain,problem; + +void storedomain(int s) { domain = s; } +void checkdomain(int s) { + if(s != domain) { + fprintf(stderr,"WARNING: problem domain '%s' does not match domain name '%s'\n",symbol(s),symbol(domain)); + } +} +char *domainname() { return symbol(domain); } + +void addproblem(int s) { problem = s; } +char *problemname() { return symbol(problem); } + +/* Lists */ + +Sfmalist *Sfmacons(Sfma *h,Sfmalist *t) { + Sfmalist *r = (Sfmalist *)statmalloc(39,sizeof(Sfmalist)); + r->hd = h; + r->tl = t; + return r; +} + +Sefflist *Seffcons(Seff *h,Sefflist *t) { + Sefflist *r = (Sefflist *)statmalloc(40,sizeof(Sefflist)); + r->hd = h; + r->tl = t; + return r; +} + +intlist *intcons(int h,intlist *t) { + intlist *r = (intlist *)statmalloc(41,sizeof(intlist)); + r->hd = h; + r->tl = t; + return r; +} + +ptrlist *ptrcons(int *h,ptrlist *t) { + ptrlist *r = (ptrlist *)statmalloc(42,sizeof(ptrlist)); + r->hd = h; + r->tl = t; + return r; +} + +atomlist *atomcons(atom h,atomlist *t) { + atomlist *r = (atomlist *)statmalloc(43,sizeof(atomlist)); + r->hd = h; + r->tl = t; + return r; +} + +/* Reading and processing an input file */ + +void showstatistics() { + int i; + printf("%3i action schemata\n",nOfSActions); + for(i=0;ihd)); + ss = ss->tl; + } + printf("\n"); + } +} + +/* Turn object lists Stypes to object arrays AStypes. */ + +void constructtypearrays() { + int i,*ptr,cnt; + intlist *l; + for(i=0;ihd; + // printf(" %s",symbol(*ptr)); + l = l->tl; + ptr = ptr + 1; + } + // printf("\n"); + *ptr = -1; + } +} + +void readfile() { + linenumber = 1; + if(nOfInputFiles == 0) { + printf("Reading from standard input\n"); + lexeropenstdin(); + } else { + lexeropen(inputfiles[0]); + } + errorstring = ""; + initPDDL(); + initsymboltable(); + UNIVTYPE = symbolindex("***UNIVTYPE***"); + yyparse(); + processtypes(); + constructtypearrays(); + if(flagShowInput) showstatistics(); +} + +void yyerror( char *s) { + printf("%s; %s on line %i.\n",s,errorstring,linenumber); + exit(1); +} + +/*******************************************************************/ +/********************* Bindings and domains ************************/ +/*******************************************************************/ + +/* elements associated with a type */ + +int *getdomain(int type) { + int j; + for(j=0;j> 1) + +/* An atomic fact (or schema) P(t1 t2 t3 ... tn) */ + +typedef struct _intlist { int hd; struct _intlist *tl; } intlist; +typedef struct _ptrlist { int *hd; struct _ptrlist *tl; } ptrlist; +typedef struct _stringlist { char *hd; struct _stringlist *tl; } stringlist; +typedef struct _typedvarlist { int v; int t; struct _typedvarlist *tl; } typedvarlist; + +/* An atom is represented as an int vector. + a[0] is the predicate + a[1] is the number of parameters n + a[2..n+2] are the parameters */ + +typedef int *atom; + +/******************* Schematic formulae ******************/ + +/* Definition */ + +typedef enum { + STRUE,SFALSE, + Spatom, Snatom, + Sconj, Sdisj, + Sforall, Sforsome, + Seq, Sneq } Sfmatype; + +typedef struct _Sfma { + Sfmatype t; + union { + atom a; + typedvarlist *ss; /* parameters for quantification */ + int p1; + struct _Sfmalist0 { struct _Sfma *hd; struct _Sfmalist0 *tl; } *juncts; + }; +#ifdef CFMA + int cnt; +#endif + int p2; + struct _Sfma *f; +} Sfma; + +typedef struct _Sfmalist { Sfma *hd; struct _Sfmalist *tl; } Sfmalist; + +/* Constructors formulas */ + +Sfma *Sfalse(); +Sfma *Strue(); +Sfma *Sconjunction(Sfmalist *); +Sfma *Sdisjunction(Sfmalist *); +Sfma *Satom(atom); +Sfma *Sneg(Sfma *); +Sfma *SfmaEQ(int,int); +Sfma *Sfmaforall(typedvarlist *,Sfma *); +Sfma *Sfmaforsome(typedvarlist *,Sfma *); + +Sfma *Sgoal; + +/* Accessors */ + +Sfmatype Sfmatypeof(Sfma *); + +/******************** Schematic effects *********************/ + +typedef enum { SEpatom, SEnatom, SEwhen, SEconj, SEforall } Sefftype; + +/* schematic effects */ + +typedef struct _Seff { + Sefftype t; + union { + atom a; + Sfma *cond; /* condition for when */ + struct _Sefflist0 { struct _Seff *hd; struct _Sefflist0 *tl; } *juncts; /* list of effects for conj */ + typedvarlist *ss; /* parameter in forall quantification */ + }; + struct _Seff *effect; /* effect for when, forall */ +} Seff; + +/* Lists */ + +typedef struct _Sefflist { Seff *hd; struct _Sefflist* tl; } Sefflist; +typedef struct _atomlist { atom hd; struct _atomlist* tl; } atomlist; + +Sfmalist *Sfmacons(Sfma *,Sfmalist *); +Sefflist *Seffcons(Seff *,Sefflist *); +intlist *intcons(int,intlist *); +atomlist *atomcons(atom,atomlist *); +ptrlist *ptrcons(int *,ptrlist *); + +#define EMPTYLIST NULL + +/* Domain */ + +void storedomain(int); +void checkdomain(int); +char *domainname(); + +void storeconstants(typedvarlist *); +void storetypes(typedvarlist *); +void storepredicates(); + +void checkrequirements(intlist *); + + +/* Problem */ + +void addproblem(int); +char *problemname(); + +void storeinit(atomlist *); +void storegoal(Sfma *); +atom *Sinit; + +/* Type variables */ + +int UNIVTYPE; +typedvarlist *withtype(int,intlist *); +typedvarlist *TVappend(typedvarlist *,typedvarlist *); + + +/* An operator schema */ + +typedef struct _Saction { + int name; + typedvarlist *params; + int cost; + Sfma *precon; + Seff *effect; +} Saction; + +int maxSActions; +Saction *Sactions; +int nOfSActions; +void checkSactionsSize(); + +atom newatom(int,intlist *); + +/* Types, with elements. */ + +typedef struct _obtype { + int typename; + intlist *elements; + intlist *supertypes; + intlist *subtypes; +} obtype; + +int *getdomain(int); +int getdomainsize(int); +void bindingaslist(int *,int *,int); + +void storeobjects(typedvarlist *); + +void showatom(atom); + +int linenumber; +char *errorstring; + +void readfile(); + +/* Constructors */ + +/* schematic effects */ +Seff* Seffconjunction(Sefflist *); +Seff* Seffwhen(Sfma*, Seff*); +Seff* Seffforall(typedvarlist *,Seff *); +Seff* SPeffatom(atom); +Seff* SNeffatom(atom); + +/* create new schematic op */ +void addnewaction(int); +void addactionparameters(typedvarlist *); +void addactionprecond(Sfma *); +void addactioneffect(Seff *); +void addactioncost(int); + +/* Grounding */ + +void preprocessoperators(); +void groundoperators(); +void simplifysillyconditionals(); diff --git a/build b/build new file mode 100755 index 0000000..8f58e6d --- /dev/null +++ b/build @@ -0,0 +1 @@ +make diff --git a/clausedb.c b/clausedb.c new file mode 100644 index 0000000..a0c1ea5 --- /dev/null +++ b/clausedb.c @@ -0,0 +1,491 @@ + +/* 2012 (C) Jussi Rintanen, jrintanen.jr@gmail.com */ + +#include +#include + +#include + +#include "main.h" + +#include "interface.h" +#include "clausedb.h" +#include "clausesets.h" +#include "printplan.h" +#include "asyntax.h" +#include "ordintsets.h" +#include "operators.h" +#include "translate2sat.h" + +#define noDEBUG +#define noASSERTS +#define noALIGNMENT /* There is a problem: the padding is not handled by GC! */ + +typedef struct _clausedblist { + int *block; + int permanent; + int blockptr; + struct _clausedblist *nextblock; +} clausedblist; + +#if defined(__LP64__) +#define BLOCKSIZE 1024*1024*8 +#else +#define BLOCKSIZE 1024*1024*2 +#endif + +clausedblist *cdb; +int CDBclauses; + + /* Given an int *, calculate the number of sizeof(int) to the + next 64 byte alignment boundary. This is to align data structures + with cache line boundaries. + */ + +int ptr2intpad(int *ptr) { + int alignment = (((int)ptr)&63) >> 2; + if(alignment) return 16-alignment; + else return 0; +} + +void check_malloc_success(void *ptr,int i) { + if(ptr == NULL) { + fprintf(stderr,"ERROR: Could not allocate more memory %i.\n",i); + exit(1); + } +} + +/* Clauses in the clause data base: +location content + -3 activity + -2 SAT instance number + -1 # of literals in clause + 0 1st literal + 1 2nd literal + . . + . . + n-1 last literal + n -1 + +WARNING: These should always be accessed with the indices PREFIX_xxxx +defined in clausedb.h. + +*/ + +void initclausedb() { + cdb = (clausedblist *)malloc(sizeof(struct _clausedblist)); + check_malloc_success(cdb,1); + + cdb->block = (int *)malloc(BLOCKSIZE*sizeof(int)); + check_malloc_success(cdb->block,2); + + allocatedbyCDB = BLOCKSIZE*sizeof(int); + + cdb->blockptr = 0; + cdb->permanent = 1; + cdb->nextblock = NULL; +#ifdef DEBUG + printf("FIRST CBD BLOCK %i\n",(int)cdb); +#endif + CDBclauses = 0; + clausecount = 0; + GCaggressiveness = 0; /* Remove only very old clauses. */ +} + + +/* Update clause activity counter. The pointer is to the first literal. */ + +void updateactivity(int *c,int act) { + c[PREFIX_ACTIVITY] = act; +} + +/* Set the LBD field of a clause. */ + +void setLBD(int *c,int lbd) { + c[PREFIX_LBD] = lbd; +} + + +/* Allocate a clause. If permflag is 1, space allocated for + the clause won't be freed or reused. */ + +int *allocc(int inst,int len,int permflag) { + clausedblist *cls,*temp; + int *ptr; +#ifdef ALIGNMENT + int alignment; +#endif + +#ifdef MULTICORE +#pragma omp critical +#endif + { + CDBclauses += 1; + clausecount += 1; + + cls = cdb; + while(cls != NULL + && (cls->permanent != permflag + || cls->blockptr+len+PREFIXWORDS+5 > BLOCKSIZE)) + { + cls = cls->nextblock; + } + + if(cls == NULL) { /* Allocate a new block. */ + +#ifdef DEBUG + printf("NEW CDB BLOCK (total of %i clauses now).\n",CDBclauses); +#endif + temp = cdb; + + cdb = (clausedblist *)malloc(sizeof(struct _clausedblist)); + check_malloc_success(cdb,3); + + cdb->block = (int *)malloc(BLOCKSIZE*sizeof(int)); + check_malloc_success(cdb->block,4); + + allocatedbyCDB += BLOCKSIZE*sizeof(int); + + cdb->permanent = permflag; + cdb->nextblock = temp; + cdb->blockptr = 0; + + cls = cdb; + + printf("\t\t\t\tAllocated %i MB %s(total %i MB)\n", + BLOCKSIZE/1024/1024*sizeof(int), + (permflag ? "permanent " : ""), + (int)(memoryused())); + + } + +#ifdef DEBUG + printf("Allocating clause %i of length %i\n",cdb->blockptr,len); +#endif + + /* Allocate it from an existing block. */ + +#ifdef DEBUG + printf("Allocating clause %i of length %i\n",cls->blockptr,len); +#endif + + /* Clauses should be aligned with cache line boundaries (16x4Bs?). + Add something to cls->blockptr to make it align. + */ + +#ifdef ALIGNMENT + cls->blockptr += ptr2intpad(&(cls->block[cls->blockptr])); +#endif + + ptr = &(cls->block[cls->blockptr+PREFIXWORDS]); + } + + cls->block[cls->blockptr+PREFIXWORDS+PREFIX_ACTIVITY] = 0; + cls->block[cls->blockptr+PREFIXWORDS+PREFIX_LBD] = 0; + cls->block[cls->blockptr+PREFIXWORDS+PREFIX_INSTANCE] = inst; + cls->block[cls->blockptr+PREFIXWORDS+PREFIX_CLAUSELEN] = len; + cls->block[cls->blockptr+len+PREFIXWORDS] = -1; + cls->blockptr += len+1+PREFIXWORDS; + + return ptr; +} + + +/* Extract information from a clause pointed to by ptr (the first literal.) */ + +int clauselen(int *ptr) { + return ptr[PREFIX_CLAUSELEN]; +} + + +int SATinstance(int *ptr) { + return ptr[PREFIX_INSTANCE]; +} + + +/* Allocate space for a non-permanent clause. */ + +int *allocpermclause(int inst,int len) { return allocc(inst,len,1); } + +int *allocclause(int inst,int len) { return allocc(inst,len,0); } + + +/* The following has not been tested after the -2 and -3 fields were added. */ + +void showclauses(satinstance sati) { + clausedblist *cls; + int i,j,b; + printf("All clauses in clause db:\n"); + + cls = cdb; + b=0; + while(cls != NULL) { + i = 0; + while(i < cls->blockptr) { + printf("Clause at %i.%i:",b,i); + for(j=i+PREFIXWORDS;jblock[i+PREFIXWORDS+PREFIX_CLAUSELEN]);j++) { + printf(" [%i]:",cls->block[j]); printTlit(sati,cls->block[j]); + } + printf("\n"); + i = i+(cls->block[i+PREFIXWORDS+PREFIX_CLAUSELEN])+PREFIXWORDS+1; + } + cls = cls->nextblock; + b += 1; + } +} + +#ifdef LBD +int nofclausesinblock(clausedblist *block) { + int n = 0; + int i = 0; + while(i < block->blockptr) { + n++; + i = i+(block->block[i+PREFIXWORDS+PREFIX_CLAUSELEN])+PREFIXWORDS+1; + } + return n; +} + +int nofnoninputclauses() { + clausedblist *block = cdb; + int n = 0; + while(block) { + if(block->permanent == 0) n += nofclausesinblock(block); + block = block->nextblock; + } + return n; +} + +int intCmp0(int *a,int *b) { + if(*a > *b) return 1; + else return 0; +} + +int medianLBD() { + int n = nofnoninputclauses(); + { + int i,j; + int tmp[n]; + clausedblist *block = cdb; + j = 0; + while(block != NULL) { + if(block->permanent == 0) { + i = 0; + while(i < block->blockptr) { + tmp[j++] = block->block[i+PREFIXWORDS+PREFIX_LBD]; + i = i+(block->block[i+PREFIXWORDS+PREFIX_CLAUSELEN])+PREFIXWORDS+1; + } + } + block = block->nextblock; + } + qsort(tmp,j,sizeof(int),intCmp0); + return tmp[j >> 1]; + } +} +#endif + + +/***********************************************************************/ +/*** Garbage collection: reclaim space used by useless clauses. ***/ +/***********************************************************************/ + +int uselessp(satinstance sati,int *c,int lbdbound) { + int len,age,lbd; + + len = c[PREFIXWORDS+PREFIX_CLAUSELEN]; + lbd = c[PREFIXWORDS+PREFIX_LBD]; + age = sati->conflicts - c[PREFIXWORDS+PREFIX_ACTIVITY]; + + if(len <= 5) return 0; + + if(age > 200000) return 1; + + if(lbd < lbdbound) return 0; + + if(lbd == lbdbound && age < 500) return 0; + + return 1; +} + + +PTRINT *nextwlelement(satinstance sati,int lit,int *ls) { + if(ls[0] == lit) return &(ls[PREFIX_WATCHA]); + else { +#ifdef ASSERTS + assert(ls[1] == lit); +#endif + return &(ls[PREFIX_WATCHB]); + } +} + + +void findinlist(satinstance sati,int lit,int *c) { + int *ls; + + if(sati->value == 0) return; /* Instance is not used any more. */ + + ls = sati->lits[lit].watches; + do { + if(ls == c) { + printf("Clause %ld found in the list of %i.\n",(PTRINT)c,lit); + return; + } + + ls = *(nextwlelement(sati,lit,ls)); + } while(ls != NULL); + printf("Clause not found!!!\n"); +} + + +/* Remove a clause from the list of clauses in which a literal is watched. */ + +void removefromwlist(satinstance sati,int lit,int *c) { + int *ls; + int **prev; + + if(sati->value == 0) return; /* Instance is not used any more. */ + + ls = sati->lits[lit].watches; + prev = &(sati->lits[lit].watches); + do { + if(ls == c) { + *prev = *(nextwlelement(sati,lit,ls)); + return; + } + prev = nextwlelement(sati,lit,ls); + ls = *prev; +#ifdef ASSERTS + assert(ls != NULL); +#endif + } while(1==1); +} + + +/* Replace a clause by another one in the list of clauses. */ + +void replaceinwlist(satinstance sati,int lit,int *c1,int *c2) { + int *ls; + + if(sati->value == 0) return; /* Instance is not used any more. */ + + ls = sati->lits[lit].watches; + + if(ls==c1) { + sati->lits[lit].watches = c2; + return; + } + + do { + if(ls[0] == lit) { + if(c1 == lsACCESS_WATCHA) { + lsASSIGN_WATCHA = c2; + return; + } + ls = lsACCESS_WATCHA; + } else { +#ifdef ASSERTS + assert(ls[1] == lit); +#endif + if(c1 == lsACCESS_WATCHB) { + lsASSIGN_WATCHB = c2; + return; + } + ls = lsACCESS_WATCHB; + } +#ifdef ASSERTS + assert(ls != NULL); +#endif + } while(1==1); +} + + +/* Delete useless clauses and free the space used by them. */ + +int garbagecollection() { + int i; + int freed,inst; + int ptr,fill,bytes; + clausedblist *blocks; + float freedMB; +#ifdef LBD + int lbdbound = medianLBD(); +#endif + +#ifdef LBD + /* printf("\t\t\t\t\t\tMedian LBD: %i\n",lbdbound); */ +#endif + printf("\t\t\t\t\t\tGC:"); fflush(stdout); + + freed = 0; /* Number of bytes freed. */ + + blocks = cdb; + while(blocks != NULL) { + + ptr = 0; + + fill = 0; /* Where to move clauses when compacting. */ + +#ifdef DEBUG + printf("Fill factor %i/%i (%.2f %, %.2f MB)",blocks->blockptr,BLOCKSIZE,((double)blocks->blockptr)*100.0/((double)BLOCKSIZE),((double)blocks->blockptr)*4.0/1024.0/1024.0); +#endif + + while(ptr < blocks->blockptr) { + + inst = blocks->block[ptr+PREFIXWORDS+PREFIX_INSTANCE]; + + bytes = blocks->block[ptr+PREFIXWORDS+PREFIX_CLAUSELEN]+PREFIXWORDS+1; + + /* Test integrity */ + // findinlist(seqs[inst].sati, + // blocks->block[ptr+PREFIXWORDS], + // &(blocks->block[ptr+PREFIXWORDS])); + // findinlist(seqs[inst].sati, + // blocks->block[ptr+PREFIXWORDS+1], + // &(blocks->block[ptr+PREFIXWORDS])); + + if((seqs[inst].sati->value == 0) + || (!blocks->permanent && (uselessp(seqs[inst].sati,blocks->block+ptr,lbdbound)))) { /* Useless clause? */ + removefromwlist(seqs[inst].sati, + blocks->block[ptr+PREFIXWORDS], + blocks->block+ptr+PREFIXWORDS); + removefromwlist(seqs[inst].sati, + blocks->block[ptr+PREFIXWORDS+1], + blocks->block+ptr+PREFIXWORDS); + freed += bytes; + + } else { /* Otherwise shift it. */ + + if(fill < ptr) { + replaceinwlist(seqs[inst].sati, + blocks->block[ptr+PREFIXWORDS], + blocks->block+ptr+PREFIXWORDS, + blocks->block+fill+PREFIXWORDS); + replaceinwlist(seqs[inst].sati, + blocks->block[ptr+PREFIXWORDS+1], + blocks->block+ptr+PREFIXWORDS, + blocks->block+fill+PREFIXWORDS); + + for(i=0;iblock[fill+i] = blocks->block[ptr+i]; + } + fill += bytes; + } + + ptr += bytes; /* Next clause */ + + } + +#ifdef DEBUG + printf(" -> (%.2f %, %.2f MB).\n", + ((double)fill)*100/((double)BLOCKSIZE), + ((double)fill)*4.0/1024.0/1024.0); +#endif + + blocks->blockptr = fill; + + blocks = blocks->nextblock; + } + + freedMB = ((float)freed) / (1024.0*256.0); + printf(" %.2f MB\n",freedMB); fflush(stdout); + + return (int)freedMB; +} diff --git a/clausedb.h b/clausedb.h new file mode 100644 index 0000000..41496d7 --- /dev/null +++ b/clausedb.h @@ -0,0 +1,91 @@ + +/* 2012 (C) Jussi Rintanen, jrintanen.jr@gmail.com */ + +float memoryused(); +void initclausedb(); /* This must be called once before adding any clauses. */ +int *allocpermclause(int,int); +int *allocclause(int,int); +int clauselen(int *); +int SATinstance(int *); +void showclauses(satinstance); +void updateactivity(int *,int); +void setLBD(int *,int); + +void free_clauses(int); + +int GCaggressiveness; +double collectgarbage(); + +double allocatedbyCDB; + +int clausecount; + +void check_malloc_success(void *,int); + +int ptr2intpad(int *); /* Calculate number of sizeof(int) to align. */ + +void falsifiedsomeclause(satinstance); + +/* The pointers to the next clauses in which the watched literals occur + are respectively either 4 or 8 bytes (1 or 2 sizeof(int)s), depending + on whether we are in a 32 or 64 bit processor. This affects the indices + of the different fields in the clause data structure. */ + +#if defined(__LP64__) +#define PREFIXWORDS 8 +#else +#define PREFIXWORDS 6 +#endif + + + +#if defined(__LP64__) +#define PREFIX_WATCHA -8 +#define PREFIX_WATCHB -6 +#else +#define PREFIX_WATCHA -6 +#define PREFIX_WATCHB -5 +#endif + + +#define PREFIX_ACTIVITY -4 +#define PREFIX_LBD -3 +#define PREFIX_INSTANCE -2 +#define PREFIX_CLAUSELEN -1 + +/* Clauses in the clause data base: +location content + -6 watched literal watched clauses link 1 + -5 watched literal watched clauses link 2 + -4 activity + -3 LBD + -2 SAT instance number + -1 # of literals in clause + 0 1st literal + 1 2nd literal + . . + . . + n-1 last literal + n -1 + +WARNING: These fields should always be accessed with the PREFIX_xxx macros. +*/ + +/* Macros for accessing the pointers at c[PREFIX_WATCHA] and c[PREFIX_WATCHB]. +The issue is that c[] is an integer (4 byte) array, and in 64-bit +architectures pointers are twice as long. */ + + +#define ASSIGN_WATCHA *((PTRINT *)(c+PREFIX_WATCHA)) +#define ACCESS_WATCHA *((PTRINT *)(c+PREFIX_WATCHA)) +#define ADDRESS_WATCHA ((PTRINT *)(c+PREFIX_WATCHA)) + +#define ASSIGN_WATCHB *((PTRINT *)(c+PREFIX_WATCHB)) +#define ACCESS_WATCHB *((PTRINT *)(c+PREFIX_WATCHB)) +#define ADDRESS_WATCHB ((PTRINT *)(c+PREFIX_WATCHB)) + +#define lsASSIGN_WATCHA *((PTRINT *)(ls+PREFIX_WATCHA)) +#define lsACCESS_WATCHA *((PTRINT *)(ls+PREFIX_WATCHA)) + +#define lsASSIGN_WATCHB *((PTRINT *)(ls+PREFIX_WATCHB)) +#define lsACCESS_WATCHB *((PTRINT *)(ls+PREFIX_WATCHB)) diff --git a/clausesets.c b/clausesets.c new file mode 100644 index 0000000..7281040 --- /dev/null +++ b/clausesets.c @@ -0,0 +1,1840 @@ + +/* 2012 (C) Jussi Rintanen, jrintanen.jr@gmail.com */ + +#include +#include + +#include "interface.h" +#include "clausedb.h" +#include "printplan.h" + +#include "main.h" +#include "asyntax.h" +#include "ordintsets.h" +#include "operators.h" +#include "translate2sat.h" + +#include + +#ifdef __LP64__ +#include +#endif + +#define noUCC + +#define ASSERTS + +#ifdef ASSERTS +#define ASSERT(a) (assert(a)) +#else +#define ASSERT(a) (1) +#endif + +#include "varvals.c" + +#define unlikely(expr) (__builtin_expect((expr),0)) +#define likely(expr) (__builtin_expect((expr),1)) +//#define unlikely(expr) (expr) +//#define likely(expr) (expr) + +#define CACHEALIGN +#ifdef CACHEALIGN +#define CACHELINESIZE 64 +#define CACHELINESIZEi 16 +PTRINT cachelineboundary(PTRINT addr) { + if(addr&63) { + return addr+(64-(addr&63)); + } else return addr; +} +PTRINT cachelineboundaryi(PTRINT addr) { + if(addr&63) { + return addr+(16-(addr&15)); + } else return addr; +} +#else +#define CACHELINESIZE 0 +#define CACHELINESIZEi 0 +PTRINT cachelineboundary(PTRINT addr) { + return addr; +} +PTRINT cachelineboundaryi(PTRINT addr) { + return addr; +} +#endif + +/* Interface to malloc */ + +void *ownalloc(int code,int i) { + void *ptr = malloc(i); + ASSERT(ptr); + allocatedbyCL += i; + check_malloc_success(ptr,1000+code); + return (PTRINT)ptr; +} + +#define min(a,b) (((a)<(b))?(a):(b)) +#define max(a,b) (((a)>(b))?(a):(b)) + +/* Heap data structure */ + +#ifdef VSIDS +heap heap_create(int); +void freeheap(heap); +int heap_emptyp(satinstance); +int heap_taketop(satinstance); +void heap_delete(satinstance,int); +void heap_insert(satinstance,int,int); +void heap_increment(satinstance,int); +void heap_increment_by(satinstance,int,int); +void heap_decay(satinstance); +void checkheapconsistency(satinstance); +#endif + +/* Macros for accessing + - the value of a propositional variable, + - the reason for the value of a propositional variable, + - the decision level of the propositional variable, + - the status (mainly the phase) of a propositional variable. +*/ + +#if defined(__LP64__) +#define REASON_INPUT -2L +#define REASON_DECISION -1L +#else +#define REASON_INPUT -2 +#define REASON_DECISION -1 +#endif + + +int VALUE(int l) { return (l&1)^1; } +int NEG(int l) { return l^1; } +int VAR(int l) { return l>>1; } +int PLIT(int v) { return v << 1; } +int NLIT(int v) { return 1+(PLIT(v)); } +int LIT(int v) { return PLIT(v); } + +/* Macros for accessing + - the score of a literal, + - the clauses in which the literal is watched, + - two literal clauses -l V l' for a literal l. +*/ + +#define LITSCORE(l) (sati->lits[(l)].score) + +/* Macros for accessing the heap. */ + +#define HINDEX(v) (sati->hindex[(v)]) + +void report_malloc(char *arrayname,int size) { +#ifdef DEBUG + printf("%s: %.2f MB\n",arrayname,((float)size)/1024.0/1024.0); +#endif +} + +/****** INCLUDED SOURCE FILES: ********************************************/ +#include "heuristics2.c" +/**************************************************************************/ + +#define noDEBUG +#define noHARDDEBUG + + +/* Initialize data structures used for all problem instances. */ + +int adjustheap; + +#ifndef MULTICORE +int cround; /* Counter which is incremented for new conflict clauses */ +int maxwasseen; +int *wasseen; /* Counter when literal was last encountered */ +#endif + +/* Functions for marking literals for different purposes. */ + +void nextround(satinstance sati) { +#ifdef MULTICORE + threads[sati->thread].cround += 1; +#else + cround += 1; +#endif +} + +int seenp(satinstance sati,int l) { /* Was literal already seen on the current round? */ + int tmp; +#ifdef MULTICORE + ASSERT(l < threads[sati->thread].maxwasseen); +#else + ASSERT(l < maxwasseen); +#endif +#ifdef MULTICORE + tmp = (threads[sati->thread].wasseen[l] == threads[sati->thread].cround); + threads[sati->thread].wasseen[l] = threads[sati->thread].cround; /* Mark the literal as seen on the current round. */ +#else + tmp = (wasseen[l] == cround); + wasseen[l] = cround; /* Mark the literal as seen on the current round. */ +#endif + return tmp; +} + +/* This is called from outside after all clauses are there. */ + +float memoryused() { + float MB; + MB = (allocatedbyFE+allocatedbyCDB+allocatedbyCL)/1024.0/1024.0; + return MB; +} + +void init_clausesets(int varspertime) { + int i; + allocatedbyCL = 0.0; + +#ifdef MULTICORE + threads = (thread *)malloc(sizeof(thread) * nOfThreads); + + for(j=0;j= sati->nOfVars) return 0; + return 1; +} +#endif + +nintlist *nintcons(int i,nintlist *l) { + nintlist *l2; + l2 = (nintlist *)malloc(sizeof(nintlist)); + l2->hd = i; + l2->tl = l; + return l2; +} + + +/*************************************************************************/ +/** The size of an instance **********************************************/ +/*************************************************************************/ + +/* Return an estimated size in MB of an instance data structure */ + +float estimateinstancesize(int tpoints,int varsPT,int actions) { + float size; + size = ((float)(tpoints*varsPT)) * + ((float) + (sizeof(int) + /* unitstack, int */ + 2*sizeof(literal) + /* literal, literal */ + sizeof(short) + /* variableval, 2*char */ +#ifdef VSIDS + sizeof(STATUSTYPE) + /* variablestatus, STATUSTYPE */ +#endif + sizeof(PTRINT) + /* variablereason, PTRINT */ + sizeof(int) + /* variabledlevel, int */ + sizeof(int) + /* declevels, int */ +#ifdef COSTS + sizeof(int) + /* declevelscost, int */ +#endif + sizeof(int))) + /* wasseen, int */ + (float)(sizeof(int) * actions * 5); /* Frame axioms, very bad estimate */ + + return size / 1024.0 / 1024.0; +} + +/*************************************************************************/ +/** Initialize an instance **/ +/*************************************************************************/ + +satinstance newinstance(int id,int times,int varsPT,int svars,int actions) { + int i; + satinstance sati = (satinstance)ownalloc(701,sizeof(struct _satinstance)); + + sati->value = -1; /* Truth-value unknown */ + sati->id = id; + sati->thread = -1; + + sati->nOfSVars = svars; + sati->nOfActions = actions; + sati->nOfVarsPerTime = varsPT; + sati->nOfTPoints = times; + + /* Last time point has only state variables, no actions or auxiliaries. */ + /* Is this correct? What happens with complex goals that require Tseitin? */ + + sati->nOfVars = (times-1)*varsPT+sati->nOfSVars; + +#ifdef DEBUG + printf("\n==================================================\n"); + printf("nOfSVars = %i\n",sati->nOfSVars); + printf("nOfActions = %i\n",sati->nOfActions); + printf("nOfVars = %i\n",sati->nOfVars); + printf("nOfVarsPerTime = %i\n",sati->nOfVarsPerTime); + printf("nOfTPoints = %i\n",sati->nOfTPoints); +#endif + + sati->unitstack = (int *)ownalloc(702,sizeof(int) * sati->nOfVars); + report_malloc("unitstack",sizeof(int) * sati->nOfVars); + sati->endunitstack = -1; + sati->startunitstack = 0; + + /* This does not take into account the initial unit clauses coming + from the goal formula (which might also involve Tseitin!). */ + + sati->initialunits = 0; + sati->maxinitialunits = sati->nOfSVars+200; + sati->initialunittable = (int *)ownalloc(703,sati->maxinitialunits * sizeof(int)); + report_malloc("initialunittable",sati->maxinitialunits * sizeof(int)); + + sati->notcalledbefore = 1; + sati->complete = 0; + + if(!noT2clauses) { + sati->l2its = (nintlist **)ownalloc(704,sizeof(nintlist *) + * sati->nOfVarsPerTime * 2); + report_malloc("l2its",sizeof(nintlist *) * sati->nOfVarsPerTime * 2); + for(i=0;inOfVarsPerTime*2;i++) sati->l2its[i] = NULL; + } + + sati->lits = (literal *)ownalloc(706,sizeof(literal) * sati->nOfVars * 2); + report_malloc("lits",sizeof(literal) * sati->nOfVars * 2); + + /* variableval according to the chosen literal value representation */ + +#ifdef REPRONE + sati->variableval = (VALTYPE *)ownalloc(707,sizeof(VALTYPE) * sati->nOfVars); +#endif + +#ifdef REPRTWO + sati->variableval = (VALTYPE *)ownalloc(708,sizeof(VALTYPE) * (1 + sati->nOfVars / 8)); +#endif + +#ifdef REPRTHREE + sati->variableval = (VALTYPE *)ownalloc(708,sizeof(VALTYPE) * 2 * sati->nOfVars); +#endif + +#ifdef REPRFOUR + sati->variableval = (VALTYPE *)ownalloc(708,sizeof(VALTYPE) * (1 + sati->nOfVars / 8)); +#endif + + +#ifdef VSIDS + sati->variablestatus = (STATUSTYPE *)ownalloc(709,sizeof(STATUSTYPE) * sati->nOfVars); + report_malloc("variablestatus",sizeof(STATUSTYPE) * sati->nOfVars); +#endif + +#ifdef REASONDLEVEL + sati->variablerd = (RD *)ownalloc(710,sizeof(RD) * sati->nOfVars); + report_malloc("variablerd",sizeof(RD) * sati->nOfVars); +#else + sati->variablereason = (PTRINT *)ownalloc(710,sizeof(PTRINT) * sati->nOfVars); + sati->variabledlevel = (int *)ownalloc(711,sizeof(int) * sati->nOfVars); + report_malloc("variablereason",sizeof(PTRINT) * sati->nOfVars); + report_malloc("variabledlevel",sizeof(int) * sati->nOfVars); +#endif + report_malloc("variableval",sizeof(VALTYPE) * sati->nOfVars); + + sati->declevels = (int *)ownalloc(800,sizeof(int) * sati->nOfVars); +#ifdef COSTS + sati->declevelscost = (int *)ownalloc(801,sizeof(int) * sati->nOfVars); +#endif + + /* Resize tag arrays if too small. */ + +#ifdef MULTICORE + if(2*sati->nOfVars > threads[0].maxwasseen) { + int i,j; + for(j=0;jnOfVars*3; + threads[j].wasseen = (int *)realloc(threads[j].wasseen,threads[j].maxwasseen * sizeof(int)); + for(i=0;inOfVars > maxwasseen) { + int i; + cround = 1; + maxwasseen = sati->nOfVars*3; + wasseen = (int *)realloc(wasseen,maxwasseen * sizeof(int)); + for(i=0;idecisions = 0; + sati->conflicts = 0; + sati->decaysteps = 0; + + sati->pheuristic = 0; + sati->heuristic = 0; + // sati->nlevel = -1; + + +#ifdef VSIDS + /* Heap for maintaining a priority queue of variables. */ + + /* This is the location of a variable in the heap array. */ + sati->hindex = (int *)ownalloc(712,sizeof(int) * (sati->nOfVars+2)); + report_malloc("hindex",sizeof(int) * sati->nOfVars); + + sati->scoreheap = heap_create(sati->nOfVars); + + /* For efficiency reasons, we don't use heap_insert, and won't order + the heap before all variable weights have been calculated. */ + /* Initially each variable i is in the heap in position i. */ + for(i=0;inOfVars;i++) { + HINDEX(i) = i; + sati->scoreheap->array[i].k = i; + sati->scoreheap->array[i].v = 0; + } + sati->scoreheap->els = sati->nOfVars; + + adjustheap = 0; /* Don't adjust the heap before instance complete. */ + +#endif + + for(i=0;inOfVars*2;i++) { /* Initialize literals. */ + LITWATCHES(i) = NULL; + +#ifdef WEIGHTS + LITSCORE(i) = 0; +#endif + } + + for(i=0;inOfVars;i++) { /* Initialize variables. */ + varunset(sati,i); +#ifdef VSIDS + VARSTATUS(i) = 0; +#endif + } + +#ifdef LBD + sati->LBDflag = (int *)ownalloc(718,sati->nOfVars * sizeof(int)); + for(i=0;inOfVars;i++) sati->LBDflag[i]=0; + sati->LBDcounter = 1; +#endif + + /* Cost vector used when finding assignments with low costs */ + +#ifdef COSTS + sati->costs = (int *)ownalloc(719,sizeof(int) * sati->nOfVarsPerTime); + for(i=0;inOfVarsPerTime;i++) sati->costs[i] = 0; + sati->currentcost = 0; + sati->costbound = 0x7fffffff; +#endif + +#ifdef DEBUG + printf("================================\n"); + printf("Initialized instance:\n"); + printf("total vars: %i\n",sati->nOfVars); + printf("state vars: %i\n",sati->nOfSVars); + printf("vars per time: %i\n",sati->nOfVarsPerTime); + printf("time points: %i\n",sati->nOfTPoints); + printf("================================\n"); +#endif + + return sati; +} + +void setheuristic(satinstance sati,int h) { + sati->heuristic = h; +} + +void setpheuristic(satinstance sati,int h) { + sati->pheuristic = h; +} + + +/**************************************************************************/ +/******* Keeping track of the heuristic ordering of literals *******/ +/**************************************************************************/ + +#ifdef WEIGHTS +int scoreof(satinstance sati,int var) { + return LITSCORE(PLIT(var)) + LITSCORE(NLIT(var)); +} + +void decay_score(satinstance sati) { + int i; + sati->decaysteps += 1; + if((sati->decaysteps & 31) == 0) { /* Discount scores. */ +#ifdef VSIDS + heap_decay(sati); +#endif + for(i=0;i<2*sati->nOfVars;i++) LITSCORE(i) = (LITSCORE(i) >> 1); + } +} + +/* Increase score and update the heap. */ + +void increase_score(satinstance sati,int lit) { + ASSERT(VAR(lit) < sati->nOfVars); + LITSCORE(lit) += 1; +#ifdef VSIDS + if(adjustheap && HINDEX(VAR(lit)) != -1) { /* Update heap. */ + heap_increment(sati,HINDEX(VAR(lit))); + } +#endif +} + +void increase_score_by(satinstance sati,int lit,int n) { + LITSCORE(lit) += n; +#ifdef VSIDS + if(adjustheap && HINDEX(VAR(lit)) != -1) { /* Update heap. */ + heap_increment_by(sati,HINDEX(VAR(lit)),n); + } +#endif +} + +#ifdef VSIDS +int getbest(satinstance sati) { + int var; + + if(!heap_emptyp(sati)) { + do { + var = heap_taketop(sati); + } while((!varunsetp(sati,var)) && (!heap_emptyp(sati))); + + if(!varunsetp(sati,var)) return -1; + + /* Next, decide whether to have the literal POSITIVE or NEGATIVE. */ + + /* Use PHASE and SCORE. Break ties randomly. */ + + switch(VARSTATUS(var) & 3) { /* Check phase. */ + case 2: return NLIT(var); + case 3: return PLIT(var); + default: + if(LITSCORE(PLIT(var)) > LITSCORE(NLIT(var))) return PLIT(var); + if(LITSCORE(PLIT(var)) < LITSCORE(NLIT(var))) return NLIT(var); + if(2&(random())) return NLIT(var); else return PLIT(var); + } + + } + return -1; +} + +int NEWgetbest(satinstance sati) { + int var; + while(!heap_emptyp(sati)) { + var = heap_taketop(sati); + if(varunsetp(sati,var)) { + switch(VARSTATUS(var) & 3) { /* Check phase. */ + case 2: return NLIT(var); + case 3: return PLIT(var); + default: + /* Otherwise use SCORE to decide polarity. Break ties randomly. */ + if(LITSCORE(PLIT(var)) > LITSCORE(NLIT(var))) return PLIT(var); + if(LITSCORE(PLIT(var)) < LITSCORE(NLIT(var))) return NLIT(var); + if(2&(random())) return NLIT(var); else return PLIT(var); + } + } + } + return -1; +} +#endif +#endif + +/**************************************************************************/ +/******* Construction and extension of clause sets *******/ +/**************************************************************************/ + +/* +As explained in Biere's PicoSAT implementation paper. +For each literal, the list of clauses in which it is watched, +is embedded in the clause data structure. +From each literal there is a pointer to the first clause in which the literal +is watched. The clause data includes a pointer to the next (and consequent) +clauses in which the literal occurs. + +IMPLEMENTATION: +table WATCHEDIN[literal] +two additional pointers in each clause + +When new clause C is added for a literal, WATCHEDIN[literal] := C, +and C has pointers to the old WATCHEDIN[literal] + +When watched literal changes, one literal gets a new clause (added +in front of the list), and the other loses one clause (removed from +the middle of the list by changing the pointer in the preceding clause). + +When clauses have been deleted (garbage collection), we must traverse +WATCHEDIN[literal] for all literals, to skip the deleted clauses. + +*/ + +/* Add clause c to literal's watched clause list. */ + +void setwatch(satinstance sati,int lit,int *c,int index) { + if(index==0) ASSIGN_WATCHA = LITWATCHES(lit); + else ASSIGN_WATCHB = LITWATCHES(lit); + LITWATCHES(lit) = c; +} + +/* Create a clause */ + +int from,to,bias,currentlen,minvar,maxvar; +int *currentClause = NULL; +int maxlen = 0; + +/* Insert an input clause (permanent) to the clause database. */ + +void addnewclause(satinstance sati,int len,clausetype ct) { + ASSERT(len >= 2); + + if(currentClause == NULL) { + maxlen = 10000; + currentClause = (int *)malloc(sizeof(int) * maxlen); + } + + currentlen = len; + + if(len > maxlen) { + maxlen = len * 3/2; + currentClause = (int *)realloc(currentClause,sizeof(int) * maxlen); + } + + switch(ct) { + case InitC: from=0; to=0; break; + case FinalC: from=sati->nOfTPoints-1; to=from; break; + case TransC: from=0; to=sati->nOfTPoints-2; break; + } + + minvar = 1000000; + maxvar = -1000000; + bias = from*sati->nOfVarsPerTime; + +} + +void addliteral(satinstance sati,int c,int l) { + int index = l+bias*2; + + currentClause[c] = index; + + minvar = min(VAR(index),minvar); + maxvar = max(VAR(index),maxvar); +} + +/* Finish the clause(s) and return the index of the last clause + that was generated. */ + +void finishclause(satinstance sati) { + int i,j,bias2,l,len; + int *c; + + for(i=from;i<=to;i++) { + + len = currentlen; + bias2 = i*sati->nOfVarsPerTime; + + if(maxvar-bias+bias2 >= sati->nOfVars) goto notthisclause; + if(minvar-bias+bias2 < 0) goto notthisclause; + + c = allocpermclause(sati->id,len); + + ASSERT(c != 0); + + for(j=0;jnOfTPoints-1; to=from; break; + case TransC: from=0; to=sati->nOfTPoints-2; break; + default: assert(1==2); break; + } + + for(i=from;i<=to;i++) { + index = l+2*i*sati->nOfVarsPerTime; + if(sati->initialunits+5 > sati->maxinitialunits) { + sati->maxinitialunits = sati->maxinitialunits*2; + sati->initialunittable = (int *)realloc(sati->initialunittable,sati->maxinitialunits*sizeof(int)); + } + sati->initialunittable[sati->initialunits++] = index; +#ifdef WEIGHTS + increase_score(sati,index); +#endif + } + return 0; +} + +/* Add a 2-literal clause to the clause base. + + The input is clauses without an absolute time. The relative time limits to + InitC: initial state (first time point) only + FinalC: goal state (last time point) only + TransC: transition relation, with current and next state + + The 2-literal clause representation used by the solver associates with + each clause an array of literals that follow from it. + As an intermediate stage, we here construct linked lists that will + be later mapped to those arrays after all input clauses are there. + +*/ + +void add2clauseRAW(satinstance sati,int l1,int l2,clausetype ct) { + int t; +#ifdef WEIGHTS + int i,i1,i2; +#endif + +#ifdef asasASSERTS + assert(l1 >= 0); + assert(l1 < sati->nOfVarsPerTime*4); + assert(l2 >= 0); + assert(l2 < sati->nOfVarsPerTime*4); +#endif + + if(ct == TransC) { + + if(!noT2clauses) { + + int l1time = VAR(l1) / sati->nOfVarsPerTime; + int l2time = VAR(l2) / sati->nOfVarsPerTime; + int nl1 = l1 - 2*l1time*sati->nOfVarsPerTime; + int nl2 = l2 - 2*l2time*sati->nOfVarsPerTime; + int tdiff = l2time-l1time; + int bias = 2*tdiff*sati->nOfVarsPerTime; + + // printf("ADDING 2-LIT "); printTlit(sati,nl1); printf(" "); + // printTlit(sati,nl2); printf(" with tdiff %i\n",tdiff); + + sati->l2its[NEG(nl1)] = nintcons(nl2+bias,sati->l2its[NEG(nl1)]); + sati->l2its[NEG(nl2)] = nintcons(nl1-bias,sati->l2its[NEG(nl2)]); + + } + +#ifdef WEIGHTS + /* Scores of the 2-literal clauses for all literals */ + for(i=0;inOfTPoints;i++) { + + i1 = l1+2*i*sati->nOfVarsPerTime; + i2 = l2+2*i*sati->nOfVarsPerTime; + + if((i1 >= 0) + && (i2 >= 0) + && (i1 < 2*sati->nOfVars) + && (i2 < 2*sati->nOfVars)) { + increase_score(sati,i1); + increase_score(sati,i2); + } + } +#endif + + } else { + if(ct == InitC) t = 0; /* First time point */ + else t=sati->nOfTPoints-1; /* Last time point */ + + // These are not needed if the increase_score below is their only use!!!! + l1 += 2*t*sati->nOfVarsPerTime; + l2 += 2*t*sati->nOfVarsPerTime; + +#ifdef WEIGHTS + increase_score(sati,l1); + increase_score(sati,l2); +#endif + + // LIT2LITS(NEG(l1)) = nintcons(l2,LIT2LITS(NEG(l1))); + // LIT2LITS(NEG(l2)) = nintcons(l1,LIT2LITS(NEG(l2))); + } +} + +void add2clause(satinstance sati,int l1,int l2,clausetype ct) { + if(ct == TransC) add2clauseRAW(sati,l1,l2,ct); + else { /* non-recurring 2-lit clauses handled as long clauses. */ + // printf("@"); + addnewclause(sati,2,ct); + addliteral(sati,0,l1); + addliteral(sati,1,l2); + finishclause(sati); + } +} + +#ifdef COSTS +void addtimedvarcost(satinstance sati,int v,int cost) { + sati->costs[v] = cost; +} +#endif + +int nintlistlen(nintlist *ls) { + int c; + c = 0; + while(ls != NULL) { + c += 1; + ls = ls->tl; + } + return c; +} + +float megab(int i) { + return ((float)i)/(1024.0*1024.0); +} + +#ifdef DEBUG +void showinstancesize(satinstance sati) { + int cnt; + int i; + int longclauses; + nintlist *ls; + + cnt = 0; + + for(i=0;i<2*sati->nOfVarsPerTime;i++) cnt += nintlistlen(sati->l2its[i]); + + longclauses = 0; + for(i=0;i<2*sati->nOfVars;i++) { + ls = LITWATCHES(i); + while(ls != NULL) { + longclauses += ((clauselen((int *)(ls->hd))+5)*4); + ls = ls->tl; + } + } + printf("===========================\n"); + printf("l2its is %.1f MB\n",megab((sati->nOfSVars+2*cnt)*4)); + printf("al2its is %.1f MB\n",megab((sati->nOfSVars+cnt)*4)); + printf("lits is %.1f MB\n",megab(3*4*2*sati->nOfVars+longclauses)); + printf("vars is %.1f MB\n",megab(4*4*sati->nOfVars)); + printf("unitstack is %.1f MB\n",megab(4*sati->nOfVars)); +#ifdef VSIDS + printf("scoreheap is %.1f MB\n",megab(sati->nOfVars*8)); +#endif +#ifdef UCC + printf("UCC is %.1f MB\n",megab(10000*4)); +#endif + printf("===========================\n"); +} +#endif + +/* Run this when all binary clauses are known. + Main function: translated the binary clause linked lists to arrays for + faster access. +*/ + +/* An ordering on lits, based on the variable indices and ignoring polarity */ +int litCmp(int *a,int *b) { + if(((*a) >> 1) < ((*b) >> 1)) return 1; + else return 0; +} + +int litCmp2(int *a,int *b) { + if(((*a) >> 1) > ((*b) >> 1)) return 1; + else return 0; +} + + +void instancecomplete(satinstance sati) { + int i,c,j; + nintlist *ls; + + sati->complete = 1; + + /* Update the heap. */ + +#ifdef VSIDS + for(i=0;inOfVars;i++) heap_increment_by(sati,HINDEX(i),LITSCORE(PLIT(i))+LITSCORE(NLIT(i))); +#endif + + adjustheap = 1; + +#ifdef VSIDS +#ifdef ASSERTS + checkheapconsistency(sati); +#endif +#endif + if(!noT2clauses) { /* First SAT instance: map linked lists to arrays. */ + + int arraysize,*a2litarray,*ptr; + + /* Put the binary clauses' linked lists into arrays. Create one huge + array, and then point into the middle. */ + + arraysize = 1; + + for(i=0;inOfVarsPerTime*2;i++) { + arraysize = cachelineboundaryi(arraysize); + arraysize += (1+nintlistlen(sati->l2its[i])); + } + + arraysize += (CACHELINESIZEi-1); + + a2litarray = (int *)ownalloc(713,sizeof(int) * arraysize); + report_malloc("a2litarray",sizeof(int) * arraysize); + + a2litarray[0] = 0; /* There is only one copy of the empty array, here. */ + + ptr = a2litarray+1; + + sati->al2its = (int **)ownalloc(714,sizeof(int *) * sati->nOfVarsPerTime * 2); + + for(i=0;inOfVarsPerTime*2;i++) { + c = nintlistlen(sati->l2its[i]); + if(c == 0) sati->al2its[i] = a2litarray; + else { + // printf("{%u,",(PTRINT)ptr); + ptr = cachelineboundary((PTRINT)ptr); + // printf("%u}",(PTRINT)ptr); + sati->al2its[i] = ptr; + ptr[0] = c; /* First element of the array is the # of elements. */ + ls = sati->l2its[i]; + for(j=0;jhd; + ls = ls->tl; + } + /* Sort the array to reduce cache misses. */ + qsort(sati->al2its[i]+1,c,sizeof(int),litCmp2); + ptr += (c+1); +#define noSHOW +#ifdef SHOW + printTlit(sati,i); + printf(": "); + for(j=0;jal2its[i][j+1]+2*sati->nOfVarsPerTime) % sati->nOfVarsPerTime); + printTlit(sati,sati->al2its[i][j+1]+2*sati->nOfVarsPerTime); + } + printf("\n"); +#endif + } + } + /* Completed the move to arrays. */ + } + +} + + +/**************************************************************************/ +/******* Functions for unit propagation *******/ +/**************************************************************************/ + +/* Set literals in unitstack true and unit propagate. + +The reason parameter denotes the cause of the literal being set. +-1 means that the literal is a decision literal +-2 means that the literal is one of the unit clauses in the input CNF +if the 2 lsbs are 0, the reason is a pointer to a clause where + the literal was a unit (HERE WE ASSUME THAT ADDRESSES OF CLAUSES + ALWAYS HAVE THEIR 2 LSBs 0.) +otherwise the reason is (l << 1)|1 for another literal l + +If contradiction is reached, return the index of a falsified +clause. */ + + +inline int addtoqueue(satinstance sati,int l,PTRINT reason,int level) { + + if((litunsetp(sati,l))) { /* Literal has no value yet. */ + + sati->unitstack[++(sati->endunitstack)] = l; /* Push it into the stack. */ + litsettrue(sati,l); /* Assign */ + +#ifdef VSIDS + VARSTATUS(VAR(l)) = 2|(VALUE(l)); /* Record phase */ +#endif + + LITREASON(l) = reason; + LITDLEVEL(l) = level; + +#ifdef HARDDEBUG + printf("Inferred "); printTlit(sati,l); printf(".\n"); + printf(" REASON: "); fflush(stdout); + switch(reason) { + case REASON_DECISION: printf("DECISION\n"); break; + case REASON_INPUT: printf("INPUT\n"); break; + default: + if((reason&1) == 0) { + printf("Clause %i of length %i:",reason,clauselen((int *)reason)); + printclause(sati,reason); + printf("\n"); + } else { + printTlit(sati,reason >> 1); printf("\n"); + } + break; + } +#endif + + ASSERT(sati->endunitstack < sati->nOfVars); + +#ifdef COSTS + if((l&1)==0) { /* Variable is true: observe cost. */ + sati->currentcost = sati->currentcost + sati->costs[untimevar(sati,VAR(l))]; +#ifdef HARDDEBUG + printTlit(sati,l); + printf("Adding %i to currentcost.\n",sati->costs[untimevar(sati,VAR(l))]); + printf("Currentcost = %i.\n",sati->currentcost); +#endif + } +#endif + + return 0; + } + + /* Variable had a value already. */ + + if(unlikely(litfalsep(sati,l))) return 1; /* Literal is false. */ + + return 0; /* Literal was true. */ +} + +/* Same as addtoqueue, except that we KNOW that the variable is unassigned. */ + +void simpleaddtoqueue(satinstance sati,int l,PTRINT reason,int level) { + + litsettrue(sati,l); /* Assign */ +#ifdef VSIDS + VARSTATUS(VAR(l)) = 2|(VALUE(l)); /* Record phase */ +#endif + LITREASON(l) = reason; + LITDLEVEL(l) = level; + + sati->unitstack[++(sati->endunitstack)] = l; /* Push it into the stack. */ + + ASSERT(sati->endunitstack < sati->nOfVars); + +#ifdef COSTS + if((l&1)==0) { /* Variable is true: observe cost. */ + sati->currentcost += sati->costs[untimevar(VAR(l))]; +#ifdef HARDDEBUG + printTlit(sati,l); + printf("Adding %i to currentcost for %i/%i.\n",sati->costs[untimevar(sati,VAR(l))],VAR(l),untimevar(sat,VAR(l))); + printf("Currentcost = %i.\n",sati->currentcost); +#endif + } +#endif +} + + +/* Propagation with 2-literal clauses. */ + +/* These variables are the interface from propaga{2lit,long} to learn(). */ + +inline int propagate2lit(satinstance sati,int lit,int level) { + int glit,bias2; + PTRINT reason; + int j; + int nofv2; + int *AAA; + + reason = (lit << 1)|1; /* Reason for the literals to be set. */ + + /* Propagate the 2-literal clauses for all time points. */ + + /* Compact binary clause representation */ + glit = lit%(2*sati->nOfVarsPerTime); + bias2 = lit-glit; + + ASSERT(glit >= 0); + ASSERT(glit < sati->nOfVarsPerTime*2); + + AAA = sati->al2its[glit]; + + nofv2 = 2*sati->nOfVars; + + for(j=1;j<=AAA[0];j++) { + if(likely(AAA[j]+bias2 < nofv2) + && likely(AAA[j]+bias2 >= 0) + && unlikely(addtoqueue(sati,AAA[j]+bias2,reason,level))) { + sati->conflicttype2lit = 1; + sati->conflictl1 = NEG(AAA[j]+bias2); + sati->conflictl2 = lit; + return 1; + } + } + + return 0; +} + +/* Propagation with long clauses (> 2 literals): + Go through clauses in which literal is watched. + If only one unassigned literal left, put into queue. +*/ + +inline int propagatelong(satinstance sati,int l,int level) { + int *c,*c2; + int *nextclause; + PTRINT *prev; + int tmp; + PTRINT *ptmp; + + // printf("#"); + + prev = &(LITWATCHES(NEG(l))); + nextclause = LITWATCHES(NEG(l)); /* Clauses where -l is watched */ + + while(nextclause != NULL) { /* Visit clauses where -l is watched. */ + c = nextclause; + + /* The watched literals are always the first two in a clause. */ + /* Make the current literal the first in the clause. */ + + if(c[0] != NEG(l)) { + tmp = c[0]; c[0] = c[1]; c[1] = tmp; + ptmp = ACCESS_WATCHA; ASSIGN_WATCHA = ACCESS_WATCHB; ASSIGN_WATCHB = ptmp; + } + + // __builtin_prefetch(ACCESS_WATCHA); + + /* If the second watched literal is true, don't do anything. */ + + if(littruep(sati,c[1])) { + prev = ADDRESS_WATCHA; + nextclause = ACCESS_WATCHA; + continue; + } + + ASSERT(isliteral(sati,c[0])); + ASSERT(isliteral(sati,c[1])); + + c2 = c+2; + + /* Find a non-false literal. */ + + while(*c2 != -1) { + ASSERT(isliteral(sati,*c2)); + if(!litfalsep(sati,*c2)) goto nonfalse; + c2 += 1; + } + + /* 2nd watched literal is a new unit clause. */ + + // updateactivity(c,sati->conflicts); + c[PREFIX_ACTIVITY] = sati->conflicts; + + if(addtoqueue(sati,c[1],(PTRINT)c,level)) { + // printf("C"); + sati->conflicttype2lit = 0; + sati->conflictclause = c; + return 1; + /* You might exit here before fixing all the clauses with + the literal watched. Is this correct? */ + } else { + // printf("U%i",*(c+1)); + } + prev = ADDRESS_WATCHA; + nextclause = ACCESS_WATCHA; + continue; + + nonfalse: + + /* Swap the old watched literal (at *c) and the new (at *c2). */ + + tmp = *c2; *c2 = *c; *c = tmp; + + /* Remove the clause from the old literal's watched clause list. */ + + *prev = ACCESS_WATCHA; + + nextclause = ACCESS_WATCHA; /* Go to the next clause. */ + + /* Add the clause to the new literal's watched clause list. */ + + ASSIGN_WATCHA = LITWATCHES(*c); + LITWATCHES(*c) = c; + + } + return 0; +} + +void setUPstacktop(satinstance sati,int top) { + sati->endunitstack = top; + sati->startunitstack = top+1; +} + + +/* Main function for propagation */ + +int propagate(satinstance sati) { + int l; + int startlong; + + startlong = sati->startunitstack; + while(startlong <= sati->endunitstack) { + + while(sati->startunitstack <= sati->endunitstack) { + l = sati->unitstack[sati->startunitstack++]; + + /* Propagate with 2-literal clauses. */ + if(propagate2lit(sati,l,sati->dlevel)) return 1; + } + + /* Propagate with long clauses. */ + + l = sati->unitstack[startlong++]; + + if(propagatelong(sati,l,sati->dlevel)) return 1; + + } + + return 0; /* No contradiction */ +} + +/*************************************************************************/ +/** Computation of learned clauses **/ +/*************************************************************************/ + +#ifdef UCC +/* + The literals that have been added as unit clauses. + They have to be remembered until decision level 0 is visited again, + because their assignments will be undone for example during + the standard CDCL main loop run on levels > 0. + */ + +void addUCC(satinstance sati,int l) { + sati->UCC[sati->NofUCClauses++] = l; + ASSERT(sati->NofUCClauses < MAXUCC); + +#ifdef HARDDEBUG + printf("New unit clause "); printTlit(sati,l); printf("\n"); + printf("lvl: %i start: %i end: %i\n",-999,sati->endunitstack,sati->startunitstack); +#endif +} + +int returnUCC(satinstance sati) { + int i; + for(i=0;iNofUCClauses;i++) { + // The return 1 below should never happen!!!!! + if(addtoqueue(sati,sati->UCC[i],REASON_INPUT,0) || propagate(sati)) return 1; + } + if(sati->dlevel == 0) sati->NofUCClauses = 0; + +#ifdef HARDDEBUG + printf("lvl: %i start: %i end: %i\n",sati->dlevel,sati->endunitstack,sati->startunitstack); +#endif + + return 0; +} +#endif UCC + + +/* Compute a 1-UIP or Last-UIP clause. + +1. Go through the literals in the current clause. +2. If literal for non-decision level, store it. +3. If non-decision literal for the top level, traverse its reasons. +4. If the reason is -2, ignore the literal. + +*/ + +satinstance dlcsati; +int dlevelCmp(int *l1,int *l2) { +#ifdef REASONDLEVEL + if(dlcsati->variablerd[VAR(*l1)].dlevel > dlcsati->variablerd[VAR(*l2)].dlevel) { +#else + if(dlcsati->variabledlevel[VAR(*l1)] > dlcsati->variabledlevel[VAR(*l2)]) { +#endif + return 1; + } + return 0; +} + +#define noFIRSTUIP 1 + +#ifdef FUIP +#include "learn1UIP.c" +#else +//#include "learn1.c" +#include "learn2.c" +//#include "learn3.c" +#endif + +/**************************************************************************/ +/******* The Conflict-Driven Clause Learning algorithm *******/ +/**************************************************************************/ + + +int chooseliteral(satinstance sati) { + switch(PLANheuristic) { + case 0: break; + default: + return do_cpath_heuristic(sati); + } + + /* If planning heuristic was not applicable, use the SAT heuristic. */ + +#ifdef VSIDS + /* Choose unassigned literal with highest score. */ + return getbest(sati); +#else + fprintf(stderr,"No decision literal chosen.\n"); + exit(1); +#endif +} + +#ifdef HARDDEBUG +void showstack(satinstance sati) { + int i,l; + printf("============================\n"); + for(i=sati->endunitstack;i>max(0,sati->endunitstack-20);i--) { + l = sati->unitstack[i]; + printf("%2i: %2i ",i,LITDLEVEL(l)); + printTlit(sati,l); + printf("\n"); + } + printf("----------------------------\n"); + printf("levels:"); + for(i=max(0,sati->dlevel-8);i<=sati->dlevel;i++) { + printf(" %i@%i",i,sati->declevels[i-1]); + } + printf("\n"); + printf("============================\n"); +} +#endif + +void emptystack(satinstance sati) { + int i; + for(i=0;i<=sati->endunitstack;i++) + litunset(sati,sati->unitstack[i]); + + setUPstacktop(sati,-1); +} + +/* Make btlevel the new top decision level by + - undoing all assignments on levels higher than btlevel + - setting current dlevel to btlevel +*/ + +void undo_assignments_until_level(satinstance sati,int btlevel) { + int i,l; + // printf("FROM %i TO %i AT BTLEVEL %i\n",sati->declevels[btlevel],sati->endunitstack,btlevel); + + for(i=sati->declevels[btlevel];i<=sati->endunitstack;i++) { + l = sati->unitstack[i]; + + litunset(sati,l); +#ifdef HARDDEBUG + printf("UNSET "); printTlit(sati,l); printf("\n"); +#endif + +#ifdef VSIDS + if(HINDEX(VAR(l)) == -1) heap_insert(sati,VAR(l),scoreof(sati,VAR(l))); +#endif + } +#ifdef COSTS + sati->currentcost = sati->declevelscost[btlevel]; +#ifdef HARDDEBUG + printf("Reverted currentcost = %i.\n",sati->currentcost); +#endif +#endif + sati->dlevel = btlevel; + setUPstacktop(sati,sati->declevels[btlevel]-1); +} + +void undo_assignments_until_level_NOHEAP(satinstance sati,int btlevel) { + + int i,l; + // printf("FROM %i TO %i AT BTLEVEL %i\n",sati->declevels[btlevel],sati->endunitstack,btlevel); + + for(i=sati->declevels[btlevel];i<=sati->endunitstack;i++) { + l = sati->unitstack[i]; + + litunset(sati,l); + // printf("UNSET "); printTlit(sati,l); printf("\n"); + + } +#ifdef COSTS + sati->currentcost = sati->declevelscost[btlevel]; +#ifdef HARDDEBUG + printf("Reverted currentcost = %i.\n",sati->currentcost); +#endif +#endif + + setUPstacktop(sati,sati->declevels[btlevel]-1); +} + +/* The standard CDCL Conflict Driven Clause Learning algorithm */ + +int solve0(satinstance sati,int conflictstogo,int restart) { + int l,p,btlevel; + int q; + PTRINT CCreason; + + if(sati->notcalledbefore) { + sati->notcalledbefore = 0; + for(p=0;pinitialunits;p++) { + if(addtoqueue(sati,sati->initialunittable[p],REASON_INPUT,0)) goto UNSAT; + } + + if(propagate(sati)) goto UNSAT; +#ifdef UCC + sati->NofUCClauses = 0; +#endif + setUPstacktop(sati,-1); /* Drop the input unit clauses from the stack. */ + + sati->dlevel = 0; + + if(sati->pheuristic >= 1) sati->heuristic_mode = 0; + } + + q = 0; + + do { + + if(q || propagate(sati)) { /* Got a conflict? */ + + if(sati->dlevel == 0) goto UNSAT; + +#ifdef WEIGHTS + decay_score(sati); +#endif + + sati->heuristic_mode = 0; + sati->conflicts += 1; + conflictstogo -= 1; + + learn(sati,sati->dlevel,&p,&CCreason,&btlevel); + /* When exiting learn(), CCreason points to the newly learned clause, + and btlevel is the decision level of the second highest literal + in the clause. */ + + ASSERT(btlevel >= 0); + ASSERT(btlevel < sati->dlevel); + ASSERT(LITDLEVEL(p) == sati->dlevel); + +#ifdef HARDDEBUG + printf("Conflict level %i literal ",sati->dlevel); printTlit(sati,p); + printf(", next level is %i.\n",btlevel); + showstack(sati); +#endif + + undo_assignments_until_level(sati,btlevel); + ASSERT(litunsetp(sati,p)); + +#ifdef UCC + if(returnUCC(sati)) goto UNSAT; +#endif + +#ifdef HARDDEBUG + printf("Setting "); printTlit(sati,p); printf(" true (flipping).\n"); fflush(stdout); +#endif + + /* CCreason refers to the conflict clause. */ + + q = addtoqueue(sati,p,CCreason,sati->dlevel); + ASSERT(littruep(sati,p)); + + // IF THE NEXT LINE IS MISSING, LEARNING A CLAUSE RIGHT BEFORE + // A RESTART SOMTIMES LEADS TO UNASSIGNING DEC LEVEL 0 LITERAL p + // AND IF IT IS THERE, heuristic2.c SOMTIMES CRASHES BECAUSE NO + // BEST VARIABLE IS FOUND. REASON UNCLEAR!!!!!!!! + // sati->declevels[sati->dlevel] = sati->endunitstack+1; + + } else { /* Extend the assignment. */ + + if(conflictstogo <= 0) { + sati->declevels[sati->dlevel] = sati->endunitstack+1; + break; + } + + l = chooseliteral(sati); + + if(l == -1) goto SAT; /* All variables assigned already. */ + + ASSERT(VAR(l) < sati->nOfVars); + ASSERT(litunsetp(sati,l)); + +#ifdef DEBUG + printf("DECISION %i: ",sati->dlevel); + printTlit(sati,l); + printf("\n"); +#endif + + sati->declevels[sati->dlevel] = sati->endunitstack+1; +#ifdef COSTS + sati->declevelscost[sati->dlevel] = sati->currentcost; +#endif + sati->dlevel += 1; + sati->decisions += 1; + + simpleaddtoqueue(sati,l,REASON_DECISION,sati->dlevel); + q=0; + } + + // } while(conflictstogo); + } while(1==1); + + /* Satisfiability status not determined. */ + + if(restart) { + + // PROBLEM: if decision level 0 learned clause is added right before + // a restart, it will never get propagated. KESKEN + +#ifdef HARDDEBUG + printf("DOING A RESTART\n"); +#endif + + undo_assignments_until_level(sati,0); + + // if(propagate(sati)) goto UNSAT; +#ifdef UCC + if(returnUCC(sati)) goto UNSAT; +#endif + setUPstacktop(sati,-1); + } + + return -1; + + UNSAT: + sati->value = 0; + return 0; + SAT: + printf("SAT (%i decisions %i conflicts)\n",sati->decisions,sati->conflicts); +#ifdef COSTS + printf("FINAL COST %i.\n",sati->currentcost); + sati->costbound = sati->currentcost; +#endif + sati->value = 1; + return 1; +} + +int solve(satinstance sati) { + int result; + int interval; + interval = 32; + do { + result = solve0(sati,interval,1); + interval = interval + 5; + } while(result == -1); + return result; +} + + +void freeinstance(satinstance sati) { + /* sati->lits is needed when garbage collecting the first time after + the instance has become useless. */ + // if(sati->lits) { free(sati->lits); sati->lits = NULL; } + + if(sati->variableval) { free(sati->variableval); sati->variableval = NULL; } +#ifdef VSIDS + if(sati->variablestatus) { free(sati->variablestatus); sati->variablestatus = NULL; } +#endif +#ifdef REASONDLEVEL + if(sati->variablerd) { free(sati->variablerd); sati->variablerd = NULL; } +#else + if(sati->variablereason) { free(sati->variablereason); sati->variablereason = NULL; } + if(sati->variabledlevel) { free(sati->variabledlevel); sati->variabledlevel = NULL; } +#endif + if(sati->initialunittable) { free(sati->initialunittable); sati->initialunittable = NULL; } + if(sati->unitstack) { free(sati->unitstack); sati->unitstack = NULL; } + +#ifdef VSIDS + if(sati->hindex) { free(sati->hindex); sati->hindex = NULL; } + if(sati->scoreheap) { freeheap(sati->scoreheap); sati->scoreheap = NULL; } +#endif +} + + +void showvaluation(satinstance sati) { + int i; + printf("Valuation:"); + for(i=0;inOfVars;i++) + if(vartruep(sati,i)) { + printf(" "); + printTlit(sati,PLIT(i)); + } + printf("\n"); +} + + +/*************************************************************************/ +/** Heap for keeping track of highest score variables **/ +/*************************************************************************/ + +#ifdef VSIDS + +/* Calculate the index of the parent of an index. */ + +inline int parent(int i) { + return (i-1) >> 1; +} + +/* Calculate the index of the 1st child of an index. */ + +inline int child1(int i) { + return i*2+1; +} + +/* Calculate the index of the 2nd child of an index. */ + +inline int child2(int i) { + return i*2+2; +} + +/* Test whether the heap is empty. */ + +int heap_emptyp(satinstance sati) { + return (sati->scoreheap->els == 0); +} + +/* Return true if index is a leaf. */ + +int leafp(heap h,int index) { + return (child1(index) >= h->els); +} + +heap heap_create(int elements) { + heap h; + h = (heap)ownalloc(716,sizeof(struct _heap)); + h->els = 0; + h->maxels = elements; + h->array = (pair *)ownalloc(717,sizeof(pair) * elements); + return h; +} + +void freeheap(heap h) { + free(h->array); + free(h); +} + +/* After moving a non-top element to the top, restore the heap property. */ + +inline int heap_property_down(satinstance sati,int index) { + int c1index,c2index; + int swap; + int key,val; + heap h; + + h = sati->scoreheap; + + ASSERT(index < h->els && index >= 0); + + key = h->array[index].k; + val = h->array[index].v; + + c1index = child1(index); + c2index = child2(index); + + /* Should one child be higher than the parent? */ + + while(((c1index < h->els && h->array[c1index].v > val) || (c2index < h->els && h->array[c2index].v > val))) { /* Not a leaf */ + + if(c2index < h->els) { + if(h->array[c1index].v > h->array[c2index].v) swap = c1index; + else swap = c2index; + } else swap = c1index; + + ASSERT(index < h->els && index >= 0); + + /* Move child to the parent's node. */ + + h->array[index].k = h->array[swap].k; + h->array[index].v = h->array[swap].v; + + HINDEX(h->array[index].k) = index; + + /* Continue with the child's node. */ + + index = swap; + + c1index = child1(index); + c2index = child2(index); + + } + + /* Leave the node here when low enough. */ + + h->array[index].k = key; + h->array[index].v = val; + + HINDEX(h->array[index].k) = index; + + return index; +} + +void printheap(satinstance sati) { + heap h = sati->scoreheap; + int node; + for(node=0;nodeels;node++) { + printf("(%i,%i) ",h->array[node].k,h->array[node].v); + } + printf("\n"); +} + +/* Get the top element of the heap (with the highest value). */ + +int heap_taketop(satinstance sati) { + int key; + heap h = sati->scoreheap; + + ASSERT(h->els); + + key = h->array[0].k; + + if(h->els > 1) { /* Move last element to top and then push down. */ + + h->array[0].k = h->array[h->els-1].k; + h->array[0].v = h->array[h->els-1].v; + + HINDEX(h->array[0].k) = 0; + + } + HINDEX(key) = -1; + + h->els -= 1; + + if(h->els) heap_property_down(sati,0); + + return key; +} + +/* Move a new element to an appropriate place in the heap. */ + +void heap_property_up(satinstance sati,int index) { + int pindex; + int key,val; + heap h = sati->scoreheap; + + ASSERT(index >= 0 && index < h->els); + + key = h->array[index].k; + val = h->array[index].v; + + pindex = parent(index); + while(index > 0 && val > h->array[pindex].v) { + /* Move parent down. */ + h->array[index].k = h->array[pindex].k; + h->array[index].v = h->array[pindex].v; + + HINDEX(h->array[index].k) = index; + + /* Continue with the parent. */ + index = pindex; + pindex = parent(index); + } + /* When all parents are OK, leave the new element here. */ + h->array[index].k = key; + h->array[index].v = val; + + HINDEX(h->array[index].k) = index; +} + +/* Add new element to the heap. */ + +void heap_insert(satinstance sati,int key,int val) { + heap h = sati->scoreheap; + + /* You could speed this a bit up by not writing key and val to memory yet. */ + /* But this would be for heap_insert only. */ + h->array[h->els].k = key; + h->array[h->els].v = val; + h->els += 1; + ASSERT(h->els <= h->maxels); + heap_property_up(sati,h->els-1); +} + +/* Increment the value of a heap element. */ + +void heap_increment(satinstance sati,int index) { + heap h = sati->scoreheap; + + h->array[index].v += 1; + heap_property_up(sati,index); +} + +void heap_increment_by(satinstance sati,int index,int n) { + heap h = sati->scoreheap; + + h->array[index].v += n; + heap_property_up(sati,index); +} + +/* Perform the decay operation, i.e. halve the value of each element. */ + +void heap_decay(satinstance sati) { + int i; + heap h = sati->scoreheap; + for(i=0;iels;i++) h->array[i].v = (h->array[i].v) >> 1; +} + +/* Delete an arbitrary element from the heap. */ + +void heap_delete(satinstance sati,int index) { + int loc; + heap h = sati->scoreheap; + + ASSERT((h->els > index) && (index >= 0)); + + h->array[index].v = -1000; + loc = heap_property_down(sati,index); + + ASSERT(leafp(h,loc)); + + h->array[loc].k = h->array[h->els-1].k; + h->array[loc].v = h->array[h->els-1].v; + + HINDEX(h->array[loc].k) = loc; + + h->els -= 1; + + if(loc < h->els) heap_property_up(sati,loc); +} +#ifdef ASSERTS +void checkheapproperty(heap h) { + int i; + for(i=1;iels;i++) { + assert(h->array[parent(i)].v >= h->array[i].v); + } +} + +void checkheapconsistency(satinstance sati) { + int i; + heap h = sati->scoreheap; + + for(i=0;iels;i++) { + assert(HINDEX(h->array[i].k) == i); + } + + checkheapproperty(h); +} +#endif +#endif + +/**************************** INCLUDED SOURCE FILES ***********************/ +#include "shortcuts.c" +/**************************************************************************/ diff --git a/clausesets.h b/clausesets.h new file mode 100644 index 0000000..7e746fe --- /dev/null +++ b/clausesets.h @@ -0,0 +1,12 @@ + +/* 2010 (C) Jussi Rintanen */ + +/* Literal and types: + + */ + +#define UNASS -1 + +int propagate(satinstance); + +void init_clausesets(); diff --git a/cleanup.c b/cleanup.c new file mode 100644 index 0000000..6490367 --- /dev/null +++ b/cleanup.c @@ -0,0 +1,259 @@ + +/* 2012 (C) Jussi Rintanen jrintanen.jr@gmail.com */ + +#include + +#include "main.h" +#include "asyntax.h" +#include "intsets.h" +#include "ordintsets.h" +#include "operators.h" + +#define noDEBUG + +int unconditional(int l,fma *f) { + fmalist *fs; + switch(f->t) { + case disj: + return 0; + case conj: + fs = f->juncts; + while(fs != NULL) { + if(unconditional(l,fs->hd)) return 1; + fs = fs->tl; + } + return 0; + break; + case natom: + if(feNLIT(f->a) == l) return 1; + return 0; + break; + case patom: + if(fePLIT(f->a) == l) return 1; + return 0; + break; + default: + return 0; + } + return 0; +} + +int doesnothing(fma *p,eff *e) { + int *l; + while(e != NULL) { + l = e->effectlits; + while(*l != -1) { + if(!unconditional(*l,p)) return 0; + l = l + 1; + } + e = e->tl; + } + return 1; +} + +/* Remove operators which don't do anything. */ + +void cleanupoperatorsNOOP() { + int i; + int removed; + removed = 0; + for(i=0;i 1 && removed) printf("Removed %i actions with inconsistent effects.\n",removed); +} + +/* Remove operators with inconsistent effects. */ + +int inconsistentp(int *ls) { + int *i,*j; + i = ls; + while(*i != -1) { + j = i+1; + while(*j != -1) { + if(*j == feNEG(*i)) return 1; + j = j + 1; + } + i = i + 1; + } + return 0; +} + +void cleanupoperators0() { + int i; + int removed; + eff *e; + removed = 0; + for(i=0;ieffectlits)) { + removed += 1; + actions[i] = actions[nOfActions-1]; + nOfActions -= 1; + if(i <= nOfActions-1) goto again; + } + e = e->tl; + } + } + if(debugOutput > 1 && removed) printf("Removed %i actions with inconsistent effects.\n",removed); +} + +/* Conform with funny PDDL semantics on actions that _simultaneously_ + set something both TRUE and FALSE. */ + +void removefrom(eff *e) { + int *nptr; + int *pptr = e->effectlits; + while(*pptr != -1) { + if(((*pptr)&1) == 0) { /* It's a positive literal. */ + nptr = e->effectlits; + while(*nptr != -1) { + if(*nptr == feNEG(*pptr)) { /* Remove positive literal's complement. */ + while(*nptr != -1) { + *nptr = *(nptr+1); + nptr = nptr + 1; + } + pptr = e->effectlits; + break; + } + nptr = nptr + 1; + } + } + pptr = pptr + 1; + } +} + +/* Standard PDDL behaviour: if both v:=0 and v:=1, then ignore v:=0. */ + +void cleanupoperators1() { + int i; + int removed; + eff *e; + removed = 0; + for(i=0;itl; + } + } + if(debugOutput > 1 && removed) printf("Removed %i actions with inconsistent effects.\n",removed); +} + +/* Remove effects that are entailed by the precondition. */ + +int entailed(int l,fma *f) { + fmalist *fs; + + switch(f->t) { + + case patom: return (l == fePLIT(f->a)); + case natom: return (l == feNLIT(f->a)); + + case conj: + fs = f->juncts; + while(fs != NULL) { + if(entailed(l,fs->hd)) return 1; + fs = fs->tl; + } + return 0; + default: return 0; + } +} + +int aseffect(int l,eff *effects) { + int *es; + + while(effects != NULL) { + es = effects->effectlits; + while(*es != -1) { + if(*es == l) return 1; + es = es + 1; + } + effects = effects->tl; + } + return 0; +} + +int a; + +void removeredundante(eff *alleffects,eff *e,fma *f) { + int *rp,*wp; + + rp = e->effectlits; + wp = rp; + + while(*rp != -1) { + + *wp = *rp; + + if((!entailed(*wp,f) && !entailed(*wp,e->condition)) + || (aseffect(feNEG(*wp),alleffects))) { + wp = wp + 1; + } else { +#ifdef DEBUG + printf("Removing effect "); + if((*wp) & 1) printf("NOT "); + printatomi(feVAR(*wp)); + printf(" in action %i\n",a); +#endif + } + rp = rp + 1; + } +} + +void removeredundanteffects() { + int i; + eff *e; + for(i=0;itl; + } + } +} + +void cleanupoperators() { + int i; + if(flagPDDLadddel) cleanupoperators1(); + else cleanupoperators0(); + // removeredundanteffects(); + cleanupoperatorsNOOP(); + // printf("After simplifications: %i actions\n",nOfActions); + + if(planSemantics == EStepOgata) { + /* Randomly shuffle the action array. */ + + for(i=0;i +#include +#include "interface.h" +#include "clausedb.h" +#include "main.h" + +#define noDEBUG + +int lineno; + +void nextline(FILE *f) { + char c; + do { + c = getc(f); + } while(c != '\n'); + lineno += 1; +} + +int numeric(char c) { return '0' <= c && c <= '9'; } +int numvalue(char c) { return c-'0'; } + +int readnat(FILE *f) { + char c; + int i; + do { + c = getc(f); + if(c == '%') nextline(f); + if(c == '\n') lineno += 1; + } while (c == ' ' || c == '\n' || c == '\t' || c == '%'); + i = 0; + if(! numeric(c)) { + fprintf(stderr,"Found illegal character %c on line %i ... exiting.\n",c,lineno); + exit(0); + } + i = numvalue(c); + do { + c = getc(f); + if(numeric(c)) i = i*10+numvalue(c); + } while(numeric(c)); + ungetc(c,f); + return i; +} + +int readint(FILE *f) { + char c; + int i; + int neg; + neg = 0; + do { + c = getc(f); + if(c == '%') nextline(f); + if(c == '\n') lineno += 1; + } while (c == ' ' || c == '\n' || c == '\t' || c == '%'); + i = 0; + if((! numeric(c)) && (c != '-')) { + fprintf(stderr,"Found illegal character %c on line %i ... exiting.\n",c,lineno); + exit(0); + } + if(c == '-') { + neg = 1; i = 0; + } else i = numvalue(c); + do { + c = getc(f); + if(numeric(c)) i = i*10+numvalue(c); + } while(numeric(c)); + ungetc(c,f); + return neg ? 0-i : i; +} + +int dsatlit(int l) { + if(l < 0) return ((-l-1) << 1)|1; + return ((l-1) << 1); +} + +int inputclause[100000]; + +satinstance DIMACSinput() { + FILE *f; + satinstance sati; + int i,len,j,n; + char c; + int numberOfProps; + int numberOfClauses; + + if(nOfInputFiles != 1) { + fprintf(stderr,"ERROR: DIMACS input has to be exactly one file!\n"); + exit(1); + } + + f = fopen(inputfiles[0],"r"); + if(f == NULL) { + fprintf(stderr,"ERROR: could not open file '%s'\n",inputfiles[0]); + exit(1); + } + + lineno = 1; + + initclausedb(); + + numberOfProps = -1; + numberOfClauses = -1; + + while(1 == 1) { + c = getc(f); + switch(c) { + case 'c': nextline(f); break; + case 'p': + printf("Reading DIMACS header\n"); + do { c = getc(f); } while(c != 'c'); + do { c = getc(f); } while(c != 'n'); + do { c = getc(f); } while(c != 'f'); + numberOfProps = readnat(f); + numberOfClauses = readnat(f); + printf("%i variables %i clauses\n",numberOfProps,numberOfClauses); + nextline(f); + break; + default: + ungetc(c,f); + goto preambleended; + } + } + preambleended: + + sati = newinstance(1,1,numberOfProps,0,0); + + for(i=0;i +#include +#include +#include + +#include "asyntax.h" +#include "tables.h" +#include "intsets.h" +#include "ordintsets.h" +#include "operators.h" +#include "main.h" +//#include "instantiation.h" + +#define noDEBUG + +/*****************************************************************************/ +/*************************** Preprocess **************************************/ +/*****************************************************************************/ + +int binding[200]; +int nOfBindings; +int scope[200]; + +#ifdef CFMA +#include "Cground.c" +#endif + +/* replace parameter variables by their index in the parameter list */ + +int NEWparamindex(int i,int qdepth) { + int j; + for(j=qdepth-1;j>=0;j--) { + if(scope[j] == i) return -1-j; + } + fprintf(stderr,"ERROR: variable %s is not a parameter\n",symbol(i)); + exit(1); +} + +/* This applies paramindex in the right places */ + +void NEWpreprocessatom(atom a,int qdepth) { + int i; + for(i=2;i<2+a[1];i++) { + if(isvar(a[i])) { + a[i] = NEWparamindex(a[i],qdepth); + } + } +} + +/* This applies paramindex in the right places. */ +/* For quantification, this replaces the quantified variables name + with the next available integer index. */ + +void NEWpreprocessfma(Sfma *f,int qdepth) { + Sfmalist *l; + switch(Sfmatypeof(f)) { + case STRUE: + case SFALSE: + break; + case Spatom: + case Snatom: + NEWpreprocessatom(f->a,qdepth); + break; + case Sdisj: + case Sconj: +#ifdef CFMA + f->cnt = listlen(f->juncts); +#endif + l = f->juncts; + while(l != NULL) { + NEWpreprocessfma(l->hd,qdepth); + l = l->tl; + } + break; + case Sforall: + case Sforsome: + if(f->ss->tl) { /* Split multiple quantification. */ + Sfma *f1 = (Sfma*)malloc(sizeof(Sfma)); + f1->t = f->t; + f1->ss = f->ss->tl; + f1->f = f->f; + + f->ss->tl = NULL; + f->f = f1; + } + scope[qdepth] = f->ss->v; +#ifdef DEBUG + printf("scope[%i] = %s\n",qdepth,symbol(f->ss->v)); +#endif + f->ss->v = -1-qdepth; + NEWpreprocessfma(f->f,qdepth+1); + break; + case Seq: + case Sneq: + if(isvar(f->p1)) f->p1 = NEWparamindex(f->p1,qdepth); + if(isvar(f->p2)) f->p2 = NEWparamindex(f->p2,qdepth); + break; + } +} + +/* This applies paramindex in the right places */ + +void NEWpreprocesseff(Seff *e,int qdepth) { + Sfmalist *l; + switch(e->t) { + case SEpatom: + case SEnatom: + NEWpreprocessatom(e->a,qdepth); + break; + case SEconj: + l = e->juncts; + while(l != NULL) { + NEWpreprocesseff(l->hd,qdepth); + l = l->tl; + } + break; + case SEforall: + if(e->ss->tl) { /* Split multiple quantification. */ + Seff *e1 = (Seff*)malloc(sizeof(Seff)); + e1->t = SEforall; + e1->ss = e->ss->tl; + e1->effect = e->effect; + + e->ss->tl = NULL; + e->effect = e1; + } + scope[qdepth] = e->ss->v; +#ifdef DEBUG + printf("scope[%i] = %s\n",qdepth,symbol(e->ss->v)); +#endif + e->ss->v = -1-qdepth; + NEWpreprocesseff(e->effect,qdepth+1); + break; + case SEwhen: + NEWpreprocessfma(e->cond,qdepth); + NEWpreprocesseff(e->effect,qdepth); + break; + } +} + +void NEWpreprocessoperators() { + int i,qdepth; + typedvarlist *ps; + + for(i=0;iv)); +#endif + scope[qdepth++] = ps->v; + ps = ps->tl; + } + + // printf("Qdepth = %i\n",qdepth); + NEWpreprocessfma(Sactions[i].precon,qdepth); + NEWpreprocesseff(Sactions[i].effect,qdepth); + +#ifdef DEBUG + printf("AFTER:\n"); +#endif + if(flagShowInput) printSaction(&Sactions[i]); + } + NEWpreprocessfma(Sgoal,0); +} + + +/***************************************************************************/ +/********************************* Grounding *******************************/ +/***************************************************************************/ + +Sfma *whenstack[1000]; /* Array for nested when-conditions */ + +int NEWnOfEffectLitsL(Sefflist *); + +int NEWnOfEffectLits(Seff *se) { + switch(se->t) { + case SEpatom: return 1; + case SEnatom: return 1; + case SEconj: return NEWnOfEffectLitsL(se->juncts); + case SEwhen: return 0; + case SEforall: return (getdomainsize(se->ss->t)) * NEWnOfEffectLits(se->effect); + } + return 0; +} + +int NEWnOfEffectLitsL(Sefflist *l) { + if(l == NULL) return 0; + return NEWnOfEffectLits(l->hd) + NEWnOfEffectLitsL(l->tl); +} + +int *NEWinserteffectlitsL(int *,Sefflist *,int *); + +int *NEWinserteffectlits(int *a,Seff *se,int *b) { + int *vals; + switch(se->t) { + case SEpatom: *a = fePLIT(atomindex(se->a,b)); return a+1; + case SEnatom: *a = feNLIT(atomindex(se->a,b)); return a+1; + case SEconj: return NEWinserteffectlitsL(a,se->juncts,b); + case SEwhen: return a; + case SEforall: + vals = getdomain(se->ss->t); + while(*vals != -1) { + b[-1-se->ss->v] = *vals; + + a = NEWinserteffectlits(a,se->effect,b); + + vals = vals + 1; + } + return a; + + default: return a; + } +} + +int *NEWinserteffectlitsL(int *a,Sefflist *l,int *b) { + if(l == NULL) return a; + return NEWinserteffectlitsL(NEWinserteffectlits(a,l->hd,b),l->tl,b); +} + +int someunconditional(Seff *se) { + Sefflist *ses; + switch(se->t) { + case SEconj: + ses = se->juncts; + while(ses != NULL) { + if(someunconditional(ses->hd)) return 1; + ses = ses->tl; + } + return 0; + case SEpatom: return 1; + case SEnatom: return 1; + case SEwhen: return 0; + case SEforall: return someunconditional(se->effect); + default: return 0; + } +} + +fma *NEWgroundfma(Sfma *,int *); + +eff *NEWlocateconditionals(Seff *se,int *b,eff *ac,int whennesting) { + int *vals,i,*ptr; + eff *e,*ac0; + Sefflist *ses; + + switch(se->t) { + + case SEconj: + ses = se->juncts; + while(ses != NULL) { + ac = NEWlocateconditionals(ses->hd,b,ac,whennesting); + ses = ses->tl; + } + return ac; + + case SEwhen: + e = (eff *)malloc(sizeof(eff)); + + whenstack[whennesting] = se->cond; + ac0 = NEWlocateconditionals(se->effect,b,ac,whennesting+1); + + if(se->cond->t == SFALSE) return ac0; + if(!someunconditional(se->effect)) return ac0; + + if(whennesting == 0) { /* Non-nested when */ + + e->condition = NEWgroundfma(se->cond,b); +#ifdef CFMA + e->ccondition = Cgroundfma(se->cond,b); + // printcfma(e->ccondition); +#endif + + } else{ /* Nesting of 2 or more whens */ + + fmalist *fs = NULL; + for(i=0;i<=whennesting;i++) { + fs = fmacons(NEWgroundfma(whenstack[i],b),fs); + } + e->condition = (fma *)malloc(sizeof(fma)); + e->condition->t = conj; + e->condition->juncts = fs; + } + + e->effectlits = (int *)malloc((NEWnOfEffectLits(se->effect)+1) * sizeof(int)); + ptr = NEWinserteffectlits(e->effectlits,se->effect,b); + *ptr = -1; + e->tl = ac0; + return e; + + case SEforall: + + vals = getdomain(se->ss->t); + + while(*vals != -1) { + b[-1-se->ss->v] = *vals; + + ac = NEWlocateconditionals(se->effect,b,ac,whennesting); + + vals = vals + 1; + } + return ac; + + default: return ac; + } +} + + +void NEWgroundeff(Seff *se,int *b, eff *e) { + int *ptr,cnt; + // eff *e = (eff *)malloc(sizeof(eff)); + e->condition = (fma *)malloc(sizeof(fma)); + e->condition->t = TRUE; +#ifdef CFMA + e->ccondition = cTRUE; +#endif + cnt = NEWnOfEffectLits(se); + // printf("There are %i effect literals: ",cnt); + e->effectlits = (int *)malloc((cnt+1) * sizeof(int)); + ptr = NEWinserteffectlits(e->effectlits,se,b); + *ptr = -1; + // printlitarr(e->effectlits); + e->tl = NEWlocateconditionals(se,b,NULL,0); +} + +fmalist *NEWgroundfmalist(Sfmalist *,int *); + +fma *NEWgroundfma(Sfma *sf,int *b) { + int *vals; + fma *f = (fma *)malloc(sizeof(fma)); + + switch(Sfmatypeof(sf)) { + + case STRUE: f->t = TRUE; break; + case SFALSE: f->t = FALSE; break; + + case Sconj: + f->t = conj; + f->juncts = NEWgroundfmalist(sf->juncts,b); + break; + + case Sdisj: + f->t = disj; + f->juncts = NEWgroundfmalist(sf->juncts,b); + break; + + case Seq: + if(bvalue(sf->p1,b) == bvalue(sf->p2,b)) { + f->t = TRUE; + } else { + f->t = FALSE; + } + break; + + case Sneq: + if(bvalue(sf->p1,b) == bvalue(sf->p2,b)) { + f->t = FALSE; + } else { + f->t = TRUE; + } + break; + + case Spatom: + f->t = patom; + f->a = atomindex(sf->a,b); + break; + + case Snatom: + f->t = natom; + f->a = atomindex(sf->a,b); + break; + + case Sforall: /* Iterate over all values of the variable. */ + + f->t = conj; + f->juncts = NULL; + + vals = getdomain(sf->ss->t); + + while(*vals != -1) { + b[-1-sf->ss->v] = *vals; + f->juncts = fmacons(NEWgroundfma(sf->f,b),f->juncts); + vals = vals + 1; + } + break; + + case Sforsome: /* Iterate over all values of the variable. */ + + f->t = disj; + f->juncts = NULL; + + vals = getdomain(sf->ss->t); + + while(*vals != -1) { + b[-1-sf->ss->v] = *vals; + f->juncts = fmacons(NEWgroundfma(sf->f,b),f->juncts); + vals = vals + 1; + } + break; + } + return f; +} + +fmalist *NEWgroundfmalist(Sfmalist *l,int *b) { + if(l == NULL) return NULL; + return fmacons(NEWgroundfma(l->hd,b),NEWgroundfmalist(l->tl,b)); +} + +/* Is it a variable, and not assigned? */ + +inline int assignedvar(int v,int i) { + if(v < 0 && (-1-v) <= i) return 1; + else return 0; +} + +/* Check all static atomic conjuncts of precon to found out whether the bindings + until parameter i are compatible with the initial state. */ + +inline int staticp(int i) { + return index2stentry[i]->staticpredicate; +} + +/* + Generate bindings so that the formula f is not trivially violated by + the true literals in the initial state in the sense that there is a positive + literal as a conjunct of f that is false in the initial state. + + How is this done? + */ + +/* + Test whether the formula f with the current partial binding is compatible + with the true literals in the initial state. + This is only tested for positive literals appearing as conjuncts of + the formula. All such literals must match the initial state. + */ + +int legalstaticbindingA(int i,int *a) { + int j; + atom *as; + + /* Go through the atoms in the initial state description, and check. */ + as = Sinit; + if(staticp(a[0]) == 0) return 1; + while(*as != NULL) { /* Go through all initial state atoms. */ + +#ifdef DEBUG + printf("Matching "); + printSfma(f); + printf(" against "); + printatom(*as); + printf(" with"); + for(j=0;j<=i;j++) { + printf(" #%i:%s",j,symbol(binding[j])); + } + printf("\n"); +#endif + + if((*as)[0] == a[0]) { /* Same predicate. Binding OK? */ + for(j=2;jt) { + + case Spatom: return legalstaticbindingA(i,f->a); + + case Sconj: + fs = f->juncts; + while(fs != NULL) { + if(legalstaticbinding(i,fs->hd) == 0) return 0; + fs = fs->tl; + } + + default: return 1; + } + return 1; +} + +#define noNEWSTATICB +#ifdef NEWSTATICB +int litcnt; +int *trueposlits[1000]; +int relevantbindings[100000]; + +/* General procedure for identifying relevant bindings. +Check every conjunct of the precondition and every true variable in +the initial state, and check if there is a match, binding the current +parameter. +Match the first literal first, to identify a candidate value. +If there is a second (and further literals), check whether the match +is good. + */ + +void identifyposlits(int i,Sfma *f) { + Sfmalist *fs; + int j; + + switch(f->t) { + case Spatom: + if(!staticp(f->a[0])) return; + for(j=0;ja[1];j++) { + if(f->a[j+2] == -1-i) { + trueposlits[litcnt++] = f->a; + printatom(f->a); + return; + } + } + return; + case Sconj: + fs = f->juncts; + while(fs != NULL) { + identifyposlits(i,fs->hd); + fs = fs->tl; + } + return; + + default: return; + } +} + +int match(int *patom,int *initlit,int param,int *value) { + int i; + *value = -1; + + if(initlit[0] != patom[0]) return 0; /* Wrong predicate */ + if(initlit[1] != patom[1]) return 0; /* Wrong arity */ + + for(i=0;i 0); + + printf("\n"); + + /* Match first lit with the initial state to obtain a binding, and + verify that others match with this binding. */ + + printf("Relevant bindings for parameter %i are...\n",i); + + as = Sinit; + + while(*as != NULL) { + printf("Trying match with "); printatom(*as); printf(":"); + if(match(trueposlits[0],*as,i,&value)) { /* There is a match. */ + for(j=0;jhd)); +#ifdef DEBUG + printf("----------------------------------\n"); +#endif + +#ifdef NEWSTATICB + NEWgothrough(i+1,sc,domains,staticrestriction); +#else + if(legalstaticbinding(i,Sactions[sc].precon)) { /* Legal binding? */ + NEWgothrough(i+1,sc,domains,staticrestriction); + } +#endif + + l = l + 1; + } + } else { + + /* Value not restricted by a static predicate. */ + + while(*l != -1) { + binding[i] = *l; + // printf("(%s)",symbol(l->hd)); + NEWgothrough(i+1,sc,domains,staticrestriction); + l = l + 1; + } + } + } else { + +#ifdef DEBUG + printf("INSTANTIATE\n"); +#endif + + nOfActions += 1; + + if(nOfActions >= maxActions) { + maxActions = 2*maxActions; + actions = (action *)realloc(actions,maxActions * sizeof(action)); + } + + actions[nOfActions-1].name = (int *)malloc((nOfBindings+2) * sizeof(int)); + actions[nOfActions-1].name[0] = Sactions[sc].name; + copybindings(actions[nOfActions-1].name+1,binding,nOfBindings); + + actions[nOfActions-1].precon = NEWgroundfma(Sactions[sc].precon,binding); +#ifdef CFMA + actions[nOfActions-1].cprecon = Cgroundfma(Sactions[sc].precon,binding); + // printcfma(actions[nOfActions-1].cprecon); +#endif + NEWgroundeff(Sactions[sc].effect,binding,&(actions[nOfActions-1].effects)); + actions[nOfActions-1].cost = Sactions[sc].cost; + + // printaction(nOfActions-1); + } + +} + +/* Does parameter i occur in a static positive literal, a conjunct of f? */ + +int occursinstatic(int i,Sfma *f) { + Sfmalist *fs; + int j; + + switch(f->t) { + case Spatom: + if(!staticp(f->a[0])) return 0; + for(j=0;ja[1];j++) { + if(f->a[j+2] == -1-i) { + return 1; + } + } + return 0; + case Sconj: + fs = f->juncts; + while(fs != NULL) { + if(occursinstatic(i,fs->hd)) return 1; + fs = fs->tl; + } + return 0; + + default: return 0; + } +} + +void NEWgroundoperators() { + int i,j; + int *domains[1000]; + int binding[1000]; + int staticrestriction[1000]; + atom *al; + + NEWpreprocessoperators(); + + initactions(); /* initialize the ground action data structure */ + initatomtable(); /* initialize the tables for atoms */ + + for(i=0;iv)); +#endif + domains[nOfBindings] = getdomain(l->t); + nOfBindings += 1; + l = l->tl; + } + +#ifdef ASSERTS + assert(nOfBindings < 100); +#endif + + /* Go through all parameter assignments and ground */ + + NEWgothrough(0,i,domains,staticrestriction); + + } + + goal = NEWgroundfma(Sgoal,binding); + + /* Go through the initial state description to assign + indices to initial state atoms. */ + + al = Sinit; + while(*al != NULL) { + atomindex(*al,NULL); + al = al + 1; + } + + initialstate = (int *)malloc(sizeof(int) * nOfAtoms); + for(i=0;i=0); assert(jvar != -1;ptr++) { /* All ways of making l true. */ + if(!tvarfalsep(sati,ptr->var,t)) { /* Is it applicable? */ + return 1; + } + } + return 0; +} + +inline int goallitvalue(satinstance sati,int l,int t0) { + int t,t2; + t = t0; + switch(HEURordmode) { + case 1: + /* How long the goal lit has been true before t. */ + while(t >= 0 && tlittruep(sati,l,t)) t = t - 1; + return t+1; + case 2: + /* How long the goal lit has been true before t. */ + while(t >= 0 && tlittruep(sati,l,t)) t = t - 1; + t2 = t; + /* How much earlier it was last false. */ + while(t2 >= 0 && !tlitfalsep(sati,l,t2)) t2 = t2-1; + return (t+1)*200+(t-t2); + case 3: + /* How long the goal lit must have been true before t (check applicability + of actions making it true!) */ + t = t-1; + while(t >= 0 && anyactionapplicable(sati,l,t) == 0) t = t - 1; + return t+1; + case 4: + /* How wide is the gap in which it must be made true? */ + /* WARNING: This stops depth-first! */ + t = t-1; + while(t >= 0 && anyactionapplicable(sati,l,t) == 0) t = t - 1; + t2 = t; + while(t2 >= 0 && !tlitfalsep(sati,l,t2)) t2 = t2 - 1; + return t-t2; + case 5: + /* Case 1 with Case 4 as a tie-breaker. */ + /* How wide is the gap in which it must be made true? */ + t = t-1; + while(t >= 0 && tlittruep(sati,l,t)) t = t - 1; + t2 = t; + while(t2 >= 0 && !tlitfalsep(sati,l,t2)) t2 = t2 - 1; + return t*1000+t-t2; + case 6: + /* Case 3 with Case 4 as a tie-breaker. */ + /* How wide is the gap in which it must be made true? */ + t = t-1; + while(t >= 0 && anyactionapplicable(sati,l,t) == 0) t = t - 1; + t2 = t; + while(t2 >= 0 && !tlitfalsep(sati,l,t2)) t2 = t2 - 1; + return t*1000+t-t2; + default: + return 0; + } +} + +void push2goalstack(satinstance sati,int l,int t) { + int v,i; + + i = stackptr++; + + ASSERT(stackptr < STACKSIZE); + + v = goallitvalue(sati,l,t); + + /* Insert the literal in the stack. Lowest .val is on top (last). */ + /* This means that we have a depth-first traversal: support for + one precondition (or top-level goal) is found first, before + proceeding with another precondition (or top-level goal). */ + + while(i > 0 && stack[i-1].val < v) { + stack[i].lit = stack[i-1].lit; + stack[i].t = stack[i-1].t; + stack[i].val = stack[i-1].val; + i = i-1; + } + + stack[i].lit = l; + stack[i].t = t; + stack[i].val = v; +} + +/* Push the constituent literals of a conjunctive goal formula in the stack. */ + +void push2goalstackCfma(satinstance sati,fma *f,int t) { + fmalist *fs; + switch(f->t) { + case patom: push2goalstack(sati,PLIT(f->a),t); break; + case natom: push2goalstack(sati,NLIT(f->a),t); break; + case conj: + fs = f->juncts; + while(fs != NULL) { + push2goalstackCfma(sati,fs->hd,t); + fs = fs->tl; + } + break; + case TRUE: break; + default: + assert(1==2); + } +} + +/* Push a subset of the literals in a general NNF formula which are + sufficient for making the formula true, in the stack. + This is as in the ICAPS'11 submission. + For conjunctions all conjuncts have to be taken. + For disjunctions one of the disjuncts is taken. If at least one of + the disjuncts is true or unknown, then the chosen disjunct cannot + be a false one. +*/ + +/* The implementation is in with a stack of sets of literals. + The operations are + - adding a set into the set (empty or singleton) + - taking the union of two top stacks + - removing the top or the second set from the stack + - comparing the two top sets (cardinality?) for choosing a disjunct + +tset_stack: element is the index of the first element of the set in tset_store +*/ + +typedef struct { + int l; + short t; +} storepair; + +int stacktop; +int storetop; +int tset_stack[1000]; +int tset_card[1000]; +storepair tset_store[100000]; + +#define CARDTOP (storetop-tset_stack[stacktop]+1) +#define CARD2ND (tset_stack[stacktop]-tset_stack[stacktop-1]) + +void tset_emptyset() { +#ifdef DEBUGDISJ + printf("tset_emptyset\n"); +#endif + stacktop += 1; + tset_card[stacktop] = 0; + tset_stack[stacktop] = storetop+1; +} + +void tset_show() { +#ifdef DEBUGDISJ + int i,j; + printf("=========================================================\n"); + for(i=0;i<=storetop+1;i++) { + for(j=0;j<=stacktop;j++) { + if(tset_stack[j] == i) printf("START %i (card %i)\n",j,tset_card[j]); + } + if(i<=storetop) { + printf("%i: ",i); printlit(tset_store[i].l); printf("@%i\n",tset_store[i].t); + } + } + printf(" =========================================================\n"); +#endif +} + +/* Add the empty set in the stack. */ + +void tset_makeempty() { +#ifdef DEBUGDISJ + printf("tset_makeempty\n"); +#endif + stacktop=-1; + storetop=-1; + tset_emptyset(); /* Always have an empty set in the stack. */ +} + +/* Add a singleton set into the stack. */ + +void tset_singleton(int l,int t) { +#ifdef DEBUGDISJ + printf("tset_singleton "); printlit(l); printf("@%i\n",t); +#endif + storetop = storetop+1; + tset_store[storetop].l = l; + tset_store[storetop].t = t; + stacktop = stacktop+1; + tset_stack[stacktop] = storetop; + tset_card[stacktop] = 1; +} + +/* Take the union of the two top sets. */ + +void tset_union() { +#ifdef DEBUGDISJ + printf("tset_union\n"); +#endif + tset_card[stacktop-1] = tset_card[stacktop-1]+tset_card[stacktop]; + stacktop = stacktop - 1; +} + +/* Return TRUE if top element has a smaller cardinality than the second. */ + +int tset_top_better() { + if(tset_card[stacktop] < tset_card[stacktop-1]) return 1; else return 0; +} + +/* Remove the top set from the stack. */ + +void tset_top_delete() { +#ifdef DEBUGDISJ + printf("tset_top_delete\n"); +#endif + storetop = storetop-tset_card[stacktop]; + stacktop = stacktop-1; +} + +/* Remove the second set from the stack. */ + +void tset_second_delete() { + int i,n; +#ifdef DEBUGDISJ + printf("tset_second_delete\n"); +#endif + n = tset_card[stacktop]; + /* Move the top set where the second one was. */ + for(i=0;it) { + /* Here we have to restrict to literals that are not FALSE ? */ + case patom: + if(tvarfalsep(sati,f->a,t)) return 0; + tset_singleton(PLIT(f->a),t); + return 1; + case natom: + if(tvartruep(sati,f->a,t)) return 0; + tset_singleton(NLIT(f->a),t); + return 1; + case conj: /* The literal sets for all conjuncts are combined. */ + tset_emptyset(); + fs = f->juncts; + while(fs != NULL) { + if(traverseDfma(sati,fs->hd,t) == 0) { + tset_top_delete(); + return 0; + } + tset_union(); + fs = fs->tl; + } + return 1; + case disj: /* The set for one of the disjuncts is chosen, others ignored. */ + // tset_emptyset(); ??????????????????? + have = 0; + fs = f->juncts; + while(fs != NULL) { + if(traverseDfma(sati,fs->hd,t)) { + if(have) { +#ifdef DEBUGDISJ + tset_show(); +#endif + if(tset_top_better()) tset_second_delete(); else tset_top_delete(); + } + have = 1; + } + fs = fs->tl; + } + return have; + case TRUE: tset_emptyset(); return 1; + case FALSE: return 0; + } + return 0; +} + +void push2goalstackDfma(satinstance sati,fma *f,int t) { + int i,l,t2; + tset_makeempty(); + if(traverseDfma(sati,f,t) == 0) return; +#ifdef DEBUGDISJ + tset_show(); +#endif + // if(tset_stack[stacktop]+1>storetop) printf("Not pushing anything\n"); + /* Push the literals from the traverseDfma stack into the heuristic stack. */ + for(i=tset_stack[stacktop];i<=storetop;i++) { + l = tset_store[i].l; + t2 = tset_store[i].t; +#ifdef DEBUGDISJ + printf("Pushing %i:",l); printlit(l); printf("@%i\n",t2); +#endif + push2goalstack(sati,l,t2); + } +} + +#ifdef HARDDEBUG +void showheustack(satinstance sati) { + int i; + printf("STACK CONTENTS:\n"); + for(i=0;ilits[PLIT(TVAR(plansteps[i].var,plansteps[i].t))].score + 10000-100*plansteps[i].flaws; +} + +/* Identify actions that are useful in reaching the goals. */ + +int do_cpath_heuristic(satinstance sati) { + int i,j,best,besttime; +#ifdef WEIGHTS + int tmparray[TMPARRAYSIZE]; +#endif + + nextround(sati); + + Nsteps = 0; + stackptr = 0; + + switch(sati->heuristic_mode) { + + case 0: /* Choose an action. */ + + if(goalisdisjunctive) { + push2goalstackDfma(sati,goal,sati->nOfTPoints-1); + } else { + push2goalstackCfma(sati,goal,sati->nOfTPoints-1); + } + +#ifdef HARDDEBUG + showheustack(sati); +#endif + + /* Find paths */ + do_cpath(sati); + + /* Pick action. */ + + /* Only one action to choose from: return it directly. */ + if(Nsteps == 1) return PLIT(TVAR(plansteps[0].var,plansteps[0].t)); + + if(Nsteps > 0) { + + switch(HEURactionchoice) { + case 0: /* Choose action randomly. */ + i = random() % Nsteps; + break; + case 1: /* Choose the earliest possible action. */ + best = -1; + besttime = 100000; + for(i=0;i best) best = score; + } + j = 0; + for(i=0;iheuristic_mode = 1; + sati->heuristic_time = 1; + sati->heuristic_index = 0; + + case 1: /* No actions needed. Do inertia. */ + +#ifdef HEURDEBUG + printf("Doing INERTIA\n"); +#endif + + while(sati->heuristic_time < sati->nOfTPoints) { + + i = sati->heuristic_index; + j = sati->heuristic_time; + + if(i+1 == sati->nOfSVars) { + sati->heuristic_index = 0; + sati->heuristic_time += 1; + } else { + sati->heuristic_index += 1; + } + + if(tvarunsetp(sati,i,j)) { + if(tvartruep(sati,i,j-1)) return PLIT(TVAR(i,j)); + else return NLIT(TVAR(i,j)); + } + + } + + sati->heuristic_mode = 2; + sati->heuristic_time = 0; + sati->heuristic_index = 0; + + case 2: /* All state variables have a value. Set actions to FALSE. */ + + while(sati->heuristic_time < sati->nOfTPoints-1) { + + i = sati->heuristic_index; + j = sati->heuristic_time; + + if(i+1 == sati->nOfActions) { + sati->heuristic_index = 0; + sati->heuristic_time += 1; + } else { + sati->heuristic_index += 1; + } + + if(tvarunsetp(sati,ACTVAR(i),j)) return NLIT(TVAR(ACTVAR(i),j)); + } + + } + + return -1; + +} + +int fmavalue(satinstance sati,fma *f,int t) { + fmalist *juncts; + switch(f->t) { + case patom: if(!tvarfalsep(sati,f->a,t)) return 1; else return 0; + case natom: if(!tvartruep(sati,f->a,t)) return 1; else return 0; + case disj: + juncts = f->juncts; + while(juncts != NULL) { + if(fmavalue(sati,juncts->hd,t) != 0) return 1; + juncts = juncts->tl; + } + return 0; + case conj: + juncts = f->juncts; + while(juncts != NULL) { + if(fmavalue(sati,juncts->hd,t) == 0) return 0; + juncts = juncts->tl; + } + return 1; + case TRUE: return 1; + case FALSE: return 0; + } + return 0; +} + +/* Estimate the value for an action */ + +int actionvalue(satinstance sati,int var,int t,fma *precondition,int disjunctive) { + int i; + int val; + switch(HEURops) { + case 1: /* Evaluate 'constrainedness' of action */ + /* How many steps later can this action be taken? */ + val = 0; + while(t+1 < sati->nOfTPoints-1 && !tvarfalsep(sati,var,t+1)) { + t = t+1; + val = val + 1; + } + return val; + case 2: /* Evaluate 'constrainedness' of action */ + /* How many steps later can this action be taken? */ + val = 0; + while(t+1 < sati->nOfTPoints-1 && !tvarfalsep(sati,var,t+1)) { + t = t+1; + val = val + 1; + } + return 1000-val; + case 3: /* Evaluate 'constrainedness' of precondition */ + /* How many steps later can the precondition be true? */ + val = 0; + while(t+1 < sati->nOfTPoints && fmavalue(sati,precondition,t+1) != 0) { + t = t+1; + val = val + 1; + } + return val; + case 4: /* Evaluate 'constrainedness' of precondition */ + /* How many steps later can the precondition be true? */ + val = 0; + while(t+1 < sati->nOfTPoints && fmavalue(sati,precondition,t+1) != 0) { + t = t+1; + val = val + 1; + } + return 1000-val; + case 5: + /* How many steps earlier can the precondition be true? */ + val = 0; + while(t-1 >= 0 && fmavalue(sati,precondition,t-1) != 0) { + t = t-1; + val = val + 1; + } + return val; + case 6: + /* How many steps earlier can the precondition be true? */ + val = 0; + while(t-1 >= 0 && fmavalue(sati,precondition,t-1) != 0) { + t = t-1; + val = val + 1; + } + return 1000-val; + case 7: + /* How many later suggested actions the action disables/affects. */ + val = 0; + for(i=0;i t) && (actaffects(var,plansteps[i].var))) { + val = val + 1; + } + } + // printf("{%i}",val); + return 1000-val; + default: assert(2==7); + } +} + +/* Go through actions at time point t-1 to find one that could + make literal l true at t. "Could" means: l occurs as a conditional + or unconditional effect, and we don't care about the condition. + + This is based on the following parameters (given on command line): + HEURtime: which time to consider, 0 = earliest, 1 = latest, 2 = all + HEURops: which operator to consider 0 = first (arbitrary), 1 = all + HEURchoice: which action@time to choose, 0 = random, 1 = weight +*/ + +/* Choose an action at t1-1 that can make l@t TRUE. The action is returned + in var,t. */ + +void supports(satinstance sati,int t0,int t1,int l,int *var,int *t,fma **precondition,int *disjunctive) { + compactCEstruct *ptr; + int bestvalue,value; + int bestvar,bestt,bestdisjunctive; + fma *bestprecondition; + + if(HEURops == 0) { /* Return the "first" (arbitrary) action. */ + + for(ptr=cCEs[l];ptr->var != -1;ptr++) { /* All ways of making l true. */ + if(!tvarfalsep(sati,ptr->var,t1-1)) { /* Is it applicable? */ +#ifdef HARDDEBUG + printf("Add ACTION %i:",ptr->var); printUvar(ptr->var); printf("@%i\n",t1-1); +#endif + *var = ptr->var; + *t = t1-1; + *precondition = ptr->condition; + *disjunctive = ptr->disjunctive; + return; + } + } + + assert(1==2); + } + + bestvar = -1; + + for(ptr=cCEs[l];ptr->var != -1;ptr++) { /* All ways of making l true. */ + if(!tvarfalsep(sati,ptr->var,t1-1)) { /* Is it applicable? */ +#ifdef HARDDEBUG + printf("Consider ACTION %i:",ptr->var); printUvar(ptr->var); printf("@%i\n",t1-1); +#endif + if(bestvar == -1) { + bestvar = ptr->var; + bestt = t1-1; + bestprecondition = ptr->condition; + bestdisjunctive = ptr->disjunctive; + bestvalue = actionvalue(sati,ptr->var,t1-1,ptr->condition,ptr->disjunctive); + } else { + value = actionvalue(sati,ptr->var,t1-1,ptr->condition,ptr->disjunctive); + if(value > bestvalue) { + bestvar = ptr->var; + bestt = t1-1; + bestprecondition = ptr->condition; + bestdisjunctive = ptr->disjunctive; + bestvalue = value; + } + } + } + } + + assert(bestvar != -1); + +#ifdef DECDEBUG + printf("Best action: "); + printUvar(bestvar); + printf("@%i for ",bestt); + printlit(l); + printf(" has value %i.\n",bestvalue); +#endif + + *var = bestvar; + *t = bestt; + *precondition = bestprecondition; + *disjunctive = bestdisjunctive; +} + + +/* Is some action op actually making l true at t-1? (= op assigned TRUE?) */ + +int litmadetrue(satinstance sati,int l,int t,fma **precondition,int *disjunctive) { + int i; + + if(!littruep(sati,litwithtime(sati,l,t))) return -1; /* l@t is not even true: no action! */ + + for(i=0;cCEs[l][i].var != -1;i++) { /* All ways of making l@t-1 true. */ + if(tvartruep(sati,cCEs[l][i].var,t-1)) { + *precondition = cCEs[l][i].condition; + *disjunctive = cCEs[l][i].disjunctive; + return cCEs[l][i].var; + } + } + + return -1; /* l@t-1 not made true. */ +} + +/***********************************************************************/ +/*** Heuristic: ***/ +/*** Find an unfulfilled (sub)goal and fulfill it at the earliest ***/ +/*** possible time point. ***/ +/*** ***/ +/***********************************************************************/ + +#define noPRUNEfromGOAL +#define noPRUNEtoGOAL + +void do_cpath(satinstance sati) { + int l,t,t1; + int j,var,isthere; + int suggestedactionsfound; + int depthlimitHIGH; + fma *precondition; + int disjunctive; + + depthlimitHIGH = -1; + suggestedactionsfound = 0; + + while(stackptr > 0) { + + /* Pop literal-time pair from the stack. */ + l = stack[stackptr-1].lit; + t = stack[--stackptr].t; + +#ifdef PRUNEtoGOAL + if(HEURactiondepthlimit && suggestedactionsfound && t >= depthlimitHIGH) + return; +#endif + +#ifdef HEURDEBUG + printf("Find action for goal "); printlit(l); printf("@%i.\n",t); +#endif + + /* Starting from last time point, find last time t such that either + 1) an action op@t-1 makes l@t TRUE, or + 2) l@t-1 is FALSE and l@t is TRUE or UNASSIGNED. + */ + isthere = 0; + var = -1; + + for(j=t;j>0;j--) { + var = litmadetrue(sati,l,j,&precondition,&disjunctive); + if(var != -1) { + isthere = 1; + t1 = j-1; + break; + } + + if(litfalsep(sati,litwithtime(sati,l,j-1))) break; + } + + if(j == 0) { /* Literal is true at time 0. */ +#ifdef HEURDEBUG + printf("(true in the initial state.)\n"); +#endif + continue; + } + + /* Literal is last false at time point j-1. */ + + if(var == -1) { /* Choose an action that turns l true between j-1 and j. */ + supports(sati,t,j,l,&var,&t1,&precondition,&disjunctive); + /* The following assertions cannot be false because + there must be an action that could make l true at t1 (i.e. is not FALSE). + If there were not, the frame action (-l & l) -> ... would + contradict Ass1 and Ass2. + */ + ASSERT(var != 0); + ASSERT(precondition->t != -1); + ASSERT(tlitfalsep(sati,l,j-1)); + ASSERT(!tlitfalsep(sati,l,j)); + } + + if(seenp(sati,TVAR(var,t1))) continue; /* Operator already processed once. */ + + /* Don't go back to top-level goals. */ + +#ifndef PRUNEtoGOAL + if(HEURactiondepthlimit && suggestedactionsfound && t1 >= depthlimitHIGH) + return; +#endif + + if(!isthere) { /* Add the variable to the list of candidate decisions. */ + suggestedactionsfound += 1; + plansteps[Nsteps].var = var; + plansteps[Nsteps].t = t1; + plansteps[Nsteps].flaws = 0; + if(HEURops == 7) { + for(j=0;j= HEURactions) return; + +#ifdef HARDDEBUG + printf(" Push preconditions of %i:",var); printUvar(var); printf("@%i into the stack (%i).\n",t1,isthere); +#endif + + if(t1 > 0) { /* Push preconditions in the stack. */ + if(disjunctive == 0) { + push2goalstackCfma(sati,precondition,t1); + } else { + push2goalstackDfma(sati,precondition,t1); + } +#ifdef HARDDEBUG + showheustack(sati); +#endif + + } + } +} diff --git a/interface.h b/interface.h new file mode 100644 index 0000000..6418098 --- /dev/null +++ b/interface.h @@ -0,0 +1,265 @@ + +/* 2012 (C) Jussi Rintanen, jrintanen.jr@gmail.com */ + +#if defined(__LP64__) +#define PTRINT long +#else +#define PTRINT int +#endif + +typedef struct _thread { + int cround; /* Counter which is incremented for new conflict clauses */ + int maxwasseen; + int *wasseen; /* Counter when literal was last encountered */ +#define MAXCCLENGTH 10000000 + int cc[MAXCCLENGTH]; /* Conflict clause which is being constructed */ +#ifndef FUIP + int stck[MAXCCLENGTH]; /* The stack used during computing the conflict clause */ +#endif + +} thread; + +thread *threads; + +#define SVAR(v) (v) +#define ACTVAR(a) ((a)+(sati->nOfSVars)) +#define TVAR(v,t) ((v)+(t)*(sati->nOfVarsPerTime)) +#define TLIT(l,t) ((l)+2*(t)*(sati->nOfVarsPerTime)) +#define TACT(a,t) ((ACTVAR(a))+(t)*(sati->nOfVarsPerTime)) + +typedef struct _nintlist { int hd; struct _nintlist *tl; } nintlist; + + +/*********************** VARIABLES *******************/ + +#define STATUSTYPE char + +/************* LITERALS & WATCH LISTS *****************/ + +/* The watch list has the watch list EMBEDDED in the clause data structure + (Biere et al. ???) +*/ + +#define LITWATCHES(l) (sati->lits[(l)].watches) + +typedef struct _literal { + int *watches; +#ifdef WEIGHTS + short score; /* Scores for choosing decision variables */ +#endif +} literal; + +/********************** HEAP *********************/ + +/* Heap for keeping track of the highest score variables. + Each element in the heap has two components: + k: key, i.e. the index of the variable + v: value, i.e. the current VSIDS score/weight + */ + +typedef struct { + int k; + short v; +} pair; + +typedef struct _heap { + int els; + int maxels; + pair *array; +} *heap; + + +/******************* SAT INSTANCE *******************/ + +#define REASONDLEVEL + +#ifdef REASONDLEVEL +typedef struct { + PTRINT reason; + int dlevel; +} RD; +#endif + +typedef struct _satinstance { + short id; /* Unique integer id for the instance */ + int thread; /* The thread this is run in. */ + + short value; /* The truth-value of the instance, -1 = unknown */ + int nOfVars; /* Number of propositional variables */ + int nOfVarsPerTime; /* Number of vars per time point */ + short nOfTPoints; /* Number of time points */ + + nintlist **l2its; /* Array for 2-literal clauses (for all time points), non-changing */ + int **al2its; /* Array for 2-literal clauses (for all time points), non-changing */ + + literal *lits; /* Data structure for literals */ + + int *declevels; +#ifdef COSTS + int declevelscost; +#endif + +#if defined REPRTWO || defined REPRFOUR +#define VALTYPE int +#else +#define VALTYPE char +#endif + + VALTYPE *variableval; + + int dlevel; /* Current decision level of the SAT instance. */ + + int decisions; /* How many decision made */ + int conflicts; /* How many conflicts */ + int decaysteps; /* Counter for variable weight decays */ + + int conflicttype2lit; + int *conflictclause; /* Clause that was falsified */ + int conflictl1; /* Following four set when empty clause derived. */ + int conflictl2; + +#ifndef MULTICORE + int cc[MAXCCLENGTH]; /* Conflict clause which is being constructed */ +#ifndef FUIP + int stck[MAXCCLENGTH]; /* The stack used during computing the conflict clause */ +#endif +#endif + +#ifdef VSIDS + STATUSTYPE *variablestatus; + /* These are the status bits. + bit 0 is phase there? + bit 1 phase + bit 2 dirty? (whether inferred with the goal clauses) + */ +#define VARSTATUS(v) (sati->variablestatus[(v)]) +#endif + +#ifndef REASONDLEVEL + + PTRINT *variablereason; + int *variabledlevel; +#define LITREASON(l) (sati->variablereason[VAR(l)]) +#define LITDLEVEL(l) (sati->variabledlevel[VAR(l)]) + +#else + + RD *variablerd; + +#define LITREASON(l) (sati->variablerd[VAR(l)].reason) +#define LITDLEVEL(l) (sati->variablerd[VAR(l)].dlevel) + +#endif + + +#ifdef VSIDS + int *hindex; /* Index of each variable in the heap. */ + heap scoreheap; /* Literals ordered according to their score */ +#endif + + int *initialunittable; /* Table for the unit clauses in the input */ + int maxinitialunits; /* The size of the table */ + int initialunits; /* Number of unit clauses in the table */ + + int *unitstack; /* Stack of assignments made */ + int endunitstack,startunitstack; /* Unprocessed part of the stack */ + + int nOfSVars; /* Planning: number of state variables (per time) */ + int nOfActions; /* Planning number of actions (per time) */ + + int complete; /* true if all input clauses have been added */ + int notcalledbefore; /* true if solve0 not called yet. */ + + /* Fields for the heuristics */ + int pheuristic; /* Which planning-based heuristic to use. */ + int heuristic; /* Which branching heuristic to use. */ + /* Unit clauses that have been learned */ +#define MAXUCC 10000 + int NofUCClauses; + int UCC[MAXUCC]; + + /* Variables for the planning heuristic */ + int heuristic_mode; /* This is 0 for actions, 1 for inertia, 2 for noops. */ + int heuristic_time; /* The next two are for inertia and noops. */ + int heuristic_index; +#ifdef COSTS + int costbound; /* Cost bound */ + int currentcost; /* Cost of current (partial) assignment */ + int *costs; /* Costs all (untimed) state variables */ +#endif + + +#ifdef GOALWEIGHTS + int *supportsg; /* Which subgoal action supports. */ + int *supportsa; /* Which action (previous decision) action supports. */ +#endif + +#ifdef LBD + int LBDcounter; + int *LBDflag; +#endif + +} *satinstance; + +typedef enum { InitC, FinalC, TransC } clausetype; + +float estimateinstancesize(int,int,int); + +satinstance newinstance(int,int,int,int,int); +void freeinstance(satinstance); + +void addnewclause(satinstance,int,clausetype); /* Number of literals in the clause (> 2) */ +void addliteral(satinstance,int,int); /* Put literal to the given loc in the clause */ +void finishclause(satinstance); /* Finish adding the clause */ + +int add1clause(satinstance,int,clausetype); /* Add a 1-literal clause */ +void add2clause(satinstance,int,int,clausetype); /* Add a 2-literal clause */ + +void instancecomplete(); + +void planningparameters(satinstance,int,int); +void setheuristic(satinstance,int); +void setpheuristic(satinstance,int); + +int solve(satinstance); +int solve0(satinstance,int,int); + +int noT2clauses; + +void addtimedvarcost(satinstance,int,int); + +int varvalue(satinstance,int); +int vartruep(satinstance,int); +int tvarvalue(satinstance,int,int); +int tvarvar(satinstance,int); +int tvartime(satinstance,int); + +int VALUE(int); +int NEG(int); +int VAR(int); +int PLIT(int); +int NLIT(int); +int LIT(int); + +#define UNASS -1 + +int propagate(satinstance); + +void init_clausesets(int); + +double allocatedbyCL; +float memoryused(); + +int flagShortCutHorizon; + +void shortcuts(satinstance sati); + +typedef struct _shortcutclause { + int l1,l2,tdiff; +} shortcutclause; + +shortcutclause *shortcutclauses; +int nofshortcutclauses; +int maxshortcutclauses; + +void nextround(satinstance sati); diff --git a/intsets.c b/intsets.c new file mode 100644 index 0000000..4c07cc1 --- /dev/null +++ b/intsets.c @@ -0,0 +1,196 @@ + +/* 2012 (C) Jussi Rintanen */ + +#include "intsets.h" +#include +#include + +int *fieldaddress(intset s) { + return ((int *)s)+3; +} + +/* BUG? There was a segmentation fault caused by the assingment to s->maxEls + below. It is not obvious whether it was the call to statmalloc that + has now been replaced by malloc, or something else. */ + +intset IScreateSize(int size) { + intset s; + s = (intset)malloc(sizeof(struct _intset)); + // s = (intset)malloc(sizeof(struct _intset) + size * sizeof(int)); + s->maxEls = size; + s->nOfEls = 0; + // s->elements = (int *)statmalloc(602,s->maxEls * sizeof(int)); + s->elements = (int *)malloc(s->maxEls * sizeof(int)); + // s->elements = fieldaddress(s); + return s; +} + +intset IScreate() { + return IScreateSize(30); +} + +int IScard(intset s) { + return s->nOfEls; +} + +int ISemptyp(intset s) { + return s->nOfEls == 0; +} + +void ISmakeempty(intset s) { + s->nOfEls = 0; +} + +int *ISrealloc(intset s) { + // if(s->elements != fieldaddress(s)) { + s->elements = (int *)realloc(s->elements,s->maxEls * sizeof(int)); + // } else { + // printf("Reallocated.\n"); + // s->elements = (int *)malloc(s->maxEls * sizeof(int)); + // } +} + + +void ISinsert(int i,intset s) { + int j; + for(j=0;jnOfEls;j++) { + if(s->elements[j] == i) return; + } + if(s->nOfEls == s->maxEls) { + s->maxEls = s->maxEls + 100; + ISrealloc(s); + } + s->nOfEls += 1; + s->elements[s->nOfEls-1] = i; + // if(s->nOfEls > maxcard) maxcard = s->nOfEls; +} + +/* Insert new element that you know is new, without checking duplicates. */ + +void ISinsertNODUP(int i,intset s) { + if(s->nOfEls == s->maxEls) { + s->maxEls = s->maxEls + 100; + ISrealloc(s); + } + s->nOfEls += 1; + s->elements[s->nOfEls-1] = i; + // if(s->nOfEls > maxcard) maxcard = s->nOfEls; +} + +void ISremove(int i,intset s) { + int j; + for(j=0;jnOfEls;j++) { + if(s->elements[j] == i) { + s->elements[j] = s->elements[s->nOfEls-1]; + s->nOfEls -= 1; + return; + } + } +} + +void ISremoveSet(intset s1,intset s2) { + int i; + for(i=0;inOfEls;i++) ISremove(s1->elements[i],s2); +} + +void ISaddelements(intset s1,intset s2) { + int i; + for(i=0;inOfEls;i++) { + ISinsert(s1->elements[i],s2); + } +} + +int ISintersectwith(intset s1,intset s2) { + int i; + int change; + change = 0; + i = 0; + while(inOfEls) { + if(ISmember(s1->elements[i],s2)) { + i += 1; + } else { + change = 1; + s1->elements[i] = s1->elements[s1->nOfEls-1]; + s1->nOfEls -= 1; + } + } + return change; +} + +/* Compute the intersection of first two sets and put it into the third */ + +void ISintersectto(intset s1,intset s2,intset s3) { + int i; + ISmakeempty(s3); + for(i=0;inOfEls;i++) { + if(ISmember(s1->elements[i],s2)) ISinsert(s1->elements[i],s3); + } +} + +/* Compute the difference of first two sets and put it into the third */ + +void ISdifferenceto(intset s1,intset s2,intset s3) { + int i; + ISmakeempty(s3); + for(i=0;inOfEls;i++) { + if(!ISmember(s1->elements[i],s2)) ISinsertNODUP(s1->elements[i],s3); + } +} + +/* Copy set to another */ + +void IScopyto(intset s1,intset s2) { + int i; + s2->nOfEls = s1->nOfEls; + if(s1->nOfEls >= s2->maxEls) { + s2->maxEls = s1->nOfEls + 10; + ISrealloc(s2); + } + for(i=0;inOfEls;i++) { + s2->elements[i] = s1->elements[i]; + } +} + +int ISmember(int i,intset s) { + int j; + for(j=0;jnOfEls;j++) { + if(s->elements[j] == i) return 1; + } + return 0; +} + +void ISfree(intset s) { + free(s->elements); + free(s); +} + +void ISprint(intset s) { + int i; + int first; + first = 1; + ITstart(s); + while(ITnext(&i)) { + if(first) printf(" "); + printf("%i",i); + first = 0; + } +} + +/* Iterator for going through the elements of a list */ + +int *ITptr; +int ITcounter; + +void ITstart(intset s) { + ITcounter = s->nOfEls; + ITptr = s->elements; +} + +int ITnext(int *i) { + if(ITcounter <= 0) return 0; + ITcounter -= 1; + *i = *(ITptr++); + return 1; +} + +void printgraph(char *n,intset s) { } diff --git a/intsets.h b/intsets.h new file mode 100644 index 0000000..9094264 --- /dev/null +++ b/intsets.h @@ -0,0 +1,75 @@ + +/* 2012 (C) Jussi Rintanen */ + +#define AATREEnot +#define AADIRECTnot + +#ifndef AATREE +#ifndef AADIRECT +typedef struct _intset { + int maxEls; + int nOfEls; + int *elements; +} *intset; +#endif +#endif + +#ifdef AATREE +typedef struct _intsetel { + int el; + short level; + short c1; + short c2; +} intsetel; + +typedef struct _intset { + int root; + int maxEls; + int nOfEls; + int lastEl; + int freed; + intsetel *elements; +} *intset; +#endif + +#ifdef AADIRECT +typedef struct _intsetel { + int el; + short level; + struct _intsetel *c1; + struct _intsetel *c2; +} *intsetel; + +typedef struct _intset { + intsetel root; + int nOfEls; +} *intset; +#endif + +intset IScreate(); +intset IScreateSize(int); +int IScard(intset); +int ISemptyp(intset); +void ISmakeempty(); +void ISinsertNODUP(int,intset); +void ISinsert(int,intset); +void ISremove(int,intset); +void ISremoveSet(intset,intset); +void ISaddelements(intset,intset); +/* int ISintersectwith(intset,intset); */ +/* void ISintersectto(intset,intset,intset); */ +void ISdifferenceto(intset,intset,intset); +void ISadddifferenceto(intset,intset,intset); +void IScopyto(intset,intset); +int ISmember(int,intset); + +void ISprint(intset); + +/* Iterator */ + +void ITstart(intset); +int ITnext(int *); + +/* Debugging */ + +void printgraph(char *,intset); diff --git a/invariants.c b/invariants.c new file mode 100644 index 0000000..52280e4 --- /dev/null +++ b/invariants.c @@ -0,0 +1,605 @@ + +/* 2012 (C) Jussi Rintanen jrintanen.jr@gmail.com */ + +#include +#include + +#include "asyntax.h" +#include "intsets.h" +#include "ordintsets.h" +#include "operators.h" +#include "tables.h" +#include "invariants.h" +#include "main.h" + +#define noDEBUG + + +/* Local copies (for inlining) of intsets.c functions */ + +int *iITptr; +int iITcounter; + +inline void iITstart(intset s) { + iITcounter = s->nOfEls; + iITptr = s->elements; +} + +inline int iITnext(int *i) { + if(iITcounter <= 0) return 0; + iITcounter -= 1; + *i = *(iITptr++); + return 1; +} + +/* */ + +void printlitlist(intset s) { + int i; + iITstart(s); + while(iITnext(&i)) { + if(i&1) printf(" -"); + else printf(" "); + printatomi(feVAR(i)); + } +} + +void showInvariants() { + int i,cntpersistent; + + cntpersistent = 0; + printf("PERSISTENT LITERALS:"); fflush(stdout); + for(i=0;icondition->t == TRUE && all != current) { + ptr = all->effectlits; + while(*ptr != -1) { + ISinsert(*ptr,s); + ptr = ptr+1; + } + } + all = all->tl; + } +} + +void guaranteedtrue(fma *f,intset ac) { + fmalist *fs; + switch(f->t) { + case FALSE: + case TRUE: + break; + case conj: + fs = f->juncts; + while(fs != NULL) { + guaranteedtrue(fs->hd,ac); + fs = fs->tl; + } + break; + case disj: break; + case patom: ISinsert(fePLIT(f->a),ac); break; + case natom: ISinsert(feNLIT(f->a),ac); break; + } +} + +int nofcondeffs(eff *e) { + int cnt; + cnt = 0; + while(e != NULL) { + cnt = cnt + 1; + e = e->tl; + } + return cnt; +} + +llist **prepros; /* */ + +void preprocess() { + int i,j,effcnt; + intset preconlits; + eff *e; + + prepros = (llist **)statmalloc(401,nOfActions * sizeof(llist *)); + preconlits = IScreate(1000); + + for(i=0;icondition,prepros[i][j].before); + ISaddelements(preconlits,prepros[i][j].before); + +#ifdef DEBUG + printf("BEFORE"); fflush(stdout); + printlitlist(prepros[i][j].before); fflush(stdout); + printf("\n"); fflush(stdout); +#endif + + prepros[i][j].after = IScreateSize(20); + + addeffectlitsL(e->effectlits,e,&(actions[i].effects),prepros[i][j].after); +#ifdef DEBUG + printf("AFTER"); fflush(stdout); + printlitlist(prepros[i][j].after); fflush(stdout); + printf("\n\n"); fflush(stdout); +#endif + + e = e->tl; + j = j + 1; + } + + } +} + +int **alleffectlits; + +int nofeffectlits(eff *e) { + int cnt = 0; + int *ptr; + + while(e != NULL) { + ptr = e->effectlits; + while(*ptr != -1) { + cnt = cnt + 1; + ptr = ptr + 1; + } + e = e-> tl; + } + return cnt; +} + +void preprocess2() { + int i,sz; + eff *e; + int *ptr,*fill; + + alleffectlits = (int **)statmalloc(499,nOfActions * sizeof(int *)); + for(i=0;ieffectlits; + while(*ptr != -1) { + *fill = *ptr; + fill = fill + 1; + ptr = ptr + 1; + } + e = e->tl; + } + *fill = -1; + } +} + +#ifdef CFMA +inline int ctruep(cfma f) { + + switch(((int)f)&7) { + + case cNATOMtag: return (onelits[((int)f) >> 3] != 1); + case cPATOMtag: return (onelits[((int)f) >> 3] != 0); + case cTRUEtag: return 1; + case cFALSEtag: return 0; + + default: + + if(((int)(*f))&1) { /* Conjunction */ + + int i,cnt; + cnt = ((int)(f[0])) >> 1; + + for(i=0;i> 1; + + for(i=0;it) { + case natom: return (onelits[f->a] != 1); + case patom: return (onelits[f->a] != 0); + case disj: + fs = f->juncts; + while(fs != NULL) { + if(truep(fs->hd)) return 1; + fs = fs->tl; + } + return 0; + case conj: + fs = f->juncts; + while(fs != NULL) { + if(!truep(fs->hd)) return 0; + fs = fs->tl; + } + return 1; + case TRUE: return 1; + case FALSE: return 0; + } + return 0; +} + +//int notmadefalse(int l,eff *e) { +// int *ls; +// while(e != NULL) { +// ls = e->effectlits; +// while(*ls != -1) { +// if(l == feNEG(*ls)) return 0; +// ls = ls + 1; +// } +// e = e->tl; +// } +// return 1; +//} + +int madefalse(int l,int i) { + int *ptr; + ptr = alleffectlits[i]; + while(*ptr != -1) { + if(*ptr == feNEG(l)) return 1; + ptr = ptr + 1; + } + return 0; +} + +void removefalsified(eff *e,intset s) { + int *ptr; + while(e != NULL) { + ptr = e->effectlits; + while(*ptr != -1) { ISremove(feNEG(*ptr),s); ptr = ptr + 1; } + e = e->tl; + } +} + +int localISmember0(int i,intset s) { + int j; + for(j=0;jnOfEls;j++) { + if(s->elements[j] == i) return 1; + } + return 0; +} + +int localISmember1(int i,intset s) { + int j; + for(j=0;jnOfEls;j++) { + if(s->elements[j] == i) return 1; + } + return 0; +} + +int localISmember2(int i,intset s) { + int j; + + for(j=0;jnOfEls;j++) { + if(s->elements[j] == i) return 1; + } + return 0; +} + +int localISmember3(int i,intset s) { + int j; + for(j=0;jnOfEls;j++) { + if(s->elements[j] == i) return 1; + } + return 0; +} + +int wastruebefore(int l,intset before) { + int i; + // if(localISmember(l,before)) return 1; + /* Go through the relevant invariants. */ + for(i=0;inOfEls;i++) { + if(before->elements[i] == l) return 1; + if(localISmember0(l,twolits[feNEG(before->elements[i])])) return 1; + } + return 0; +} + +void computeinvariants() { + int i,iteration,change,j,k; + eff *e; + int *il; + llist *prep; + intset trueones,ext; + int trueonesinitialized; + + preprocess(); + preprocess2(); + + ext = IScreateSize(10000); + + trueones = IScreateSize(10000); + + onelits = (int *)statmalloc(403,sizeof(int) * nOfAtoms); + twolits = (intset *)statmalloc(404,sizeof(intset) * nOfAtoms * 2); + + for(i=0;iccondition)) { +#else + if(truep(e->condition)) { +#endif + + /* In the following: + We have newly true literals in prep->after and + all true literals in trueones. + + For every l in prep->after and m in trueones, -l V m + is an invariant. + These are all invariants involving -l. + + We want to store all of these such that both -l and m + can have both value true and false. + */ + + /* Go through effect literals */ + + il = e->effectlits; + + while(*il != -1) { + int l; + l = *il; + il = il + 1; + + /* See whether making literal l true falsifies something. */ + + if(onelits[feVAR(l)] == (l&1)) { /* Falsified a 1-literal */ + + if(trueonesinitialized == 0) { + + trueonesinitialized = 1; + ISmakeempty(trueones); + + /* literals true because they are in the precondition */ + ISaddelements(prep->before,trueones); + + /* literals true because a 2-literal clause is satisfied */ + iITstart(prep->before); + while(iITnext(&j)) ISaddelements(twolits[feNEG(j)],trueones); + + /* Remove literals that are falsified by this conditional effect + or possibly by other conditional effects. */ + removefalsified(&(actions[i].effects),trueones); + + /* Add literals that are made true. */ + ISaddelements(prep->after,trueones); + } + + change = 1; + + onelits[feVAR(l)] = -1; + + /* Add 2-literals -a | l */ + + iITstart(trueones); + while(iITnext(&k)) { + if(l != k && (onelits[feVAR(k)] == -1 || (localISmember1(k,prep->after) && onelits[feVAR(k)] == (k&1)))) { + ISinsertNODUP(k,twolits[feNEG(l)]); + ISinsertNODUP(feNEG(l),twolits[k]); + } + } + } else if(onelits[feVAR(l)] == -1) { /* Check preservation of 2-literal clauses */ + + /* Remove candidate 2-literal invariants which were falsified. */ + + IScopyto(twolits[feNEG(l)],ext); + + iITstart(ext); + while(iITnext(&k)) { + if(!(localISmember2(k,prep->after) + || ( + wastruebefore(k,prep->before) + && + !madefalse(k,i) + ))) { + change = 1; + ISremove(k,twolits[feNEG(l)]); + ISremove(feNEG(l),twolits[k]); + } + } + + /* If enabled a new state variable value (= invalidated + a candidate one-literal invariant), add new candidate + two-literal invariants that still remain true. */ + + iITstart(prep->after); + while(iITnext(&k)) { + if(l != k && onelits[feVAR(k)] == -1 && localISmember3(k,twolits[feNEG(l)])) { + ISinsert(feNEG(l),twolits[k]); + } + } + + } + + } + + } + e = e->tl; + prep++; + } + + // showInvariantsBrief(); + } + + iteration += 1; + } + + for(i=0;ithread].stck; + cc = threads[sati->thread].cc; +#else + stck = sati->stck; + cc = sati->cc; +#endif + +#ifdef LBD + int lbd; +#endif + + /* This counter is used for eliminating multiple occurrences of + a literal from the derivation of the conflict clause. + If the literal is associated with the current round, it has + been seen already and will be ignored. */ + + nextround(sati); + + ptr = -1; /* The clause we will learn is still empty. */ + top = -1; /* All literals in the clause are in the stack. */ + + *maxnondecisionlevel = -1; /* Highest non-decision level. */ + + if(sati->conflicttype2lit) { /* A 2-literal clause was falsified. */ + stck[0] = sati->conflictl1; /* Push both literals into the stack. */ + stck[1] = sati->conflictl2; + + top = 1; + +#ifdef MULTICORE + threads[sati->thread].wasseen[sati->conflictl1] = threads[sati->thread].cround; + threads[sati->thread].wasseen[sati->conflictl2] = threads[sati->thread].cround; +#else + wasseen[sati->conflictl1] = cround; + wasseen[sati->conflictl2] = cround; +#endif + +#ifdef HARDDEBUG + printf("Violated binary clause "); + printTlit(sati,sati->conflictl1); + printf(" "); + printTlit(sati,sati->conflictl2); + printf("\n"); +#endif + +#ifdef ASSERTS + assert(isliteral(sati,sati->conflictl1)); + assert(isliteral(sati,sati->conflictl2)); +#endif + + } else { /* A clause of >= 3 literals was falsified. */ + + len = sati->conflictclause[PREFIX_CLAUSELEN]; + +#ifdef DEBUG + printf("Violated clause %i (len %i):\n",(int)(sati->conflictclause),len); + for(i=0;iconflictclause[i]); } + // for(i=0;iconflictclause[i]); } + printf("\n"); +#endif + +#ifdef ASSERTS + for(i=0;iconflictclause[i]))); +#endif + + /* Push all literals in the clause into the stack or in the cc array. */ + for(i=0;ithread].wasseen[NEG(sati->conflictclause[i])] = + threads[sati->thread].cround; +#else + wasseen[NEG(sati->conflictclause[i])] = cround; +#endif + if(LITDLEVEL(sati->conflictclause[i]) == dlevel) { + stck[++top] = NEG(sati->conflictclause[i]); + } else { + int l = sati->conflictclause[i]; + if(LITREASON(l) != REASON_INPUT) { + *maxnondecisionlevel = max(LITDLEVEL(l),*maxnondecisionlevel); + cc[++ptr] = l; + } + } + } + } + + // printf("FALSIFIED A %i-LITERAL CLAUSE.\n",len); + + // for(i=0;i<=top;i++) printf("{%i}",sati->variabledlevel[VAR(stck[i])]); + // for(i=0;i<=top;i++) printTlit(sati,stck[i]); + // printf("\n"); + + CCwatch1 = -1; + CCwatch2 = -1; + +#ifdef ASSERTS + assert(ptr=-1); + assert(top>=0); /* Necessarily at least one literal at the decision level. */ +#endif + + while(top >= 0) { + + l = stck[top--]; /* Pop literal from the stack. */ + +#ifdef ASSERTS + assert(ptr=-1); +#endif + + r = LITREASON(l); + + /* Infer (learn) a new clause from the falsified clause, one literal + at a time. */ + + if(r == REASON_DECISION) { /* It is the decision literal. */ + cc[++ptr] = NEG(l); + CCwatch1 = NEG(l); + *CCdliteral = NEG(l); + } else if(r&1) { /* Reason is a literal (2 lit clause) */ +#ifdef WEIGHTS + increase_score(sati,l); /* Increase score */ +#endif + + if(!seenp(sati,r >> 1)) { + stck[++top] = (r >> 1); +#ifdef ASSERTS + assert(isliteral(sati,r >> 1)); +#endif + } + } else { /* Reason is a clause */ +#ifdef WEIGHTS + increase_score(sati,l); /* Increase score */ +#endif + + c = (int *)r; + while(*c != -1) { /* Literals except l into the stack or into the CC. */ + if(VAR(*c) != VAR(l) && !seenp(sati,NEG(*c))) { + if(LITDLEVEL(*c) == dlevel) { + stck[++top] = NEG(*c); + } else { + *maxnondecisionlevel = max(LITDLEVEL(*c),*maxnondecisionlevel); + cc[++ptr] = *c; + } + } + c += 1; + } + } + } + +#ifdef ASSERTS + assert(ptr=-1); +#endif + +#ifdef DEBUG + printf("Learned clause %i (%i lits):",clausecount,ptr+1); + for(i=0;i<=ptr;i++) { printf(" %i:",VAR(cc[i])); printTlit(sati,cc[i]); } + printf("\n"); +#endif + +#ifdef ASSERTS + /* See that the learned clause is false in the current valuation. */ + for(i=0;i<=ptr;i++) { + assert(!littruep(sati,cc[i])); + assert(!litunsetp(sati,cc[i])); + } +#endif + + /* Minimize the size of the learned clause: + 1. Mark all literals in the clause. + 2. Remove literals whose parent is marked. + */ + +#define noMINIMIZE + +#ifdef MINIMIZE +{ + PTRINT rr; + cround += 1; + for(i=0;i<=ptr;i++) wasseen[NEG(cc[i])] = cround; + i = 0; + while(i<=ptr) { + rr = LITREASON(cc[i]); + if(rr != REASON_DECISION && (((int)rr)&1) && (wasseen[((int)rr) >> 1] == cround)) { /* Remove. */ + // printf("*"); + cc[i] = cc[ptr--]; + } else { + if(LITDLEVEL(cc[i]) == *maxnondecisionlevel) CCwatch2 = cc[i]; + i = i + 1; + } + } +} +#else + for(i=0;i<=ptr;i++) { + if(LITDLEVEL(cc[i]) == *maxnondecisionlevel) { + CCwatch2 = cc[i]; + break; + } + } +#endif + +#ifdef LBD + /* Calculate the Literal Block Distance LBD of Laurent & Simon IJCAI'09. */ + + lbd = 0; + sati->LBDcounter += 1; + for(i=0;i<=ptr;i++) { + if(sati->LBDflag[LITDLEVEL(cc[i])] != sati->LBDcounter) { + lbd += 1; + sati->LBDflag[LITDLEVEL(cc[i])] = sati->LBDcounter; + } + } +#endif + +//printf("LEARNED A %i-LITERAL CLAUSE.\n",ptr+1); +//if(ptr+1 > 20000) printf("QZ(%i,%i)",ptr+1,dlevel); + +// printf("ADDING NEW CLAUSE, ptr == %i\n",ptr); + + /* Add the new clause to the clause set. */ + + if(ptr+1 > stats_longest_learned) stats_longest_learned = ptr+1; + + if(ptr >= 2) { /* Clause with at least 3 literals */ + +#ifdef ASSERTS + assert(isliteral(sati,CCwatch1)); + assert(isliteral(sati,CCwatch2)); + assert(CCwatch1 != CCwatch2); +#endif + + newClause = allocclause(sati->id,ptr+1); + + // updateactivity(newClause,sati->conflicts); + newClause[PREFIX_ACTIVITY] = sati->conflicts; + +#ifdef LBD + // printf("/%i/",lbd); + setLBD(newClause,lbd); +#endif + + /* The watched literals are the ones with the highest levels, + that is, the one at the decision level and one on the + next highest level. */ + + newClause[0] = CCwatch1; + newClause[1] = CCwatch2; + +#ifdef WEIGHTS + increase_score(sati,newClause[0]); + increase_score(sati,newClause[1]); +#endif + + // Sort the learned clause. Impact on total runtime??????? + qsort(cc,ptr+1,sizeof(int),litCmp); + + j = 2; + for(i=0;i<=ptr;i++) { +#ifdef ASSERTS + assert(isliteral(sati,cc[i])); + // assert(cc[i] != cc[i+1]); +#endif + if(cc[i] != CCwatch1 && cc[i] != CCwatch2) { + newClause[j++] = cc[i]; +#ifdef WEIGHTS + increase_score(sati,newClause[j-1]); +#endif + } + } + +#ifdef ASSERTS + assert(j == ptr+1); + assert(newClause[ptr+1] == -1); +#endif + + *CCreason = (PTRINT)newClause; + + setwatch(sati,CCwatch1,(int *)(*CCreason),0); + setwatch(sati,CCwatch2,(int *)(*CCreason),1); + + } else if(ptr == 1) { /* Clause with 2 literals */ + +#ifdef DEBUG + printf("LEARNED A 2-LITERAL CLAUSE (horizon %i)\n",sati->nOfTPoints); +#endif + + add2clause(sati,cc[0],cc[1],InitC); + + if(cc[0] == *CCdliteral) rl = cc[1]; + else rl = cc[0]; + *CCreason = ((NEG(rl))<< 1)|1; + + } else { /* Unit clause */ + +#ifdef DEBUG + printf("LEARNED A 1-LITERAL CLAUSE! (horizon %i)\n",sati->nOfTPoints); +#endif +#ifdef UCC + addUCC(sati,cc[0]); +#endif + *CCreason = REASON_INPUT; + *maxnondecisionlevel = 0; + + } + +} diff --git a/lexer.lex b/lexer.lex new file mode 100644 index 0000000..a6568ed --- /dev/null +++ b/lexer.lex @@ -0,0 +1,161 @@ + + /* 2012 (C) Jussi Rintanen */ + +/* Definitions */ + +%{ + +#include +#include +#include "asyntax.h" +#include "parser.tab.h" +#include "main.h" + +#include "tables.h" + + int lexeropen(char *fn) { + yyin = fopen(fn,"r"); + if(yyin == NULL) { + fprintf(stderr,"ERROR: opening file %s\n",fn); + exit(1); + } + return 0; + } + + int lexeropenstdin() { + yyin = stdin; + nOfInputFiles = 0; + currentInputFile=-1; + return 0; + } + +int yywrap() { + linenumber = 1; + if(currentInputFile == nOfInputFiles-1) return 1; + fclose(yyin); + currentInputFile += 1; + yyin = fopen(inputfiles[currentInputFile],"r"); + if(yyin == NULL) { + fprintf(stderr,"ERROR: opening input file #%i: %s",currentInputFile,inputfiles[currentInputFile]); + exit(1); + } + return 0; +} + +void lowercase(char *tmp) { + while(*tmp != 0) { + if(*tmp >= 'A' && *tmp <= 'Z') *tmp += ('a'-'A'); + tmp += 1; + } +} + +%} + +ALPHA [a-zA-Z] +ALPNUM [0-9a-zA-Z\-_,/] +NUM [0-9] + +%% + +":"{ALPHA}{ALPNUM}* { + lowercase(yytext); +#ifdef DEBUG + printf(":ID %s\n",yytext); +#endif + if(strcmp(yytext,":action") == 0) return rwACTION; + if(strcmp(yytext,":parameters") == 0) return rwPARAMS; + if(strcmp(yytext,":effect") == 0) return rwEFFECT; + if(strcmp(yytext,":precondition") == 0) return rwPRECOND; + if(strcmp(yytext,":predicates") == 0) return rwPREDICATES; + if(strcmp(yytext,":requirements") == 0) return rwREQUIREMENTS; + if(strcmp(yytext,":functions") == 0) return rwFUNCTIONS; + if(strcmp(yytext,":types") == 0) return rwTYPES; + if(strcmp(yytext,":constants") == 0) return rwCONSTANTS; + if(strcmp(yytext,":objects") == 0) return rwOBJECTS; + if(strcmp(yytext,":init") == 0) return rwINIT; + if(strcmp(yytext,":goal") == 0) return rwGOAL; + if(strcmp(yytext,":domain") == 0) return rwDOMAIN; + if(strcmp(yytext,":metric") == 0) return rwMETRIC; + + yylval.i = symbolindex(yytext); + return ID; + } + +{ALPHA}{ALPNUM}* { + lowercase(yytext); +#ifdef DEBUG + printf("ID %s\n",yytext); +#endif + + if(strcmp(yytext,"define") == 0) return rwDEFINE; + if(strcmp(yytext,"and") == 0) return rwAND; + if(strcmp(yytext,"or") == 0) return rwOR; + if(strcmp(yytext,"imply") == 0) return rwIMPLY; + if(strcmp(yytext,"when") == 0) return rwWHEN; + if(strcmp(yytext,"not") == 0) return rwNOT; + if(strcmp(yytext,"exists") == 0) return rwEXISTS; + if(strcmp(yytext,"forall") == 0) return rwFORALL; + if(strcmp(yytext,"problem") == 0) return rwPROBLEM; + if(strcmp(yytext,"domain") == 0) return rwDOMAIN; + if(strcmp(yytext,"either") == 0) return rwEITHER; + if(strcmp(yytext,"increase") == 0) return rwINCREASE; + if(strcmp(yytext,"minimize") == 0) return rwMINIMIZE; + + yylval.i = symbolindex(yytext); + return ID; + } + +"?"{ALPHA}{ALPNUM}* { + lowercase(yytext); +#ifdef DEBUG + printf("VAR %s\n",yytext); +#endif + yylval.i = symbolindex(yytext); + return VAR; + } + +{NUM}{NUM}* { + sscanf(yytext,"%d",&yylval.i); + return INT; + } + +"(" { +#ifdef DEBUG + printf("Left (\n"); +#endif + return LPAREN; + } + + +")" { +#ifdef DEBUG + printf("Right )\n"); +#endif + return RPAREN; + } + +"-" { +#ifdef DEBUG + printf("DASH\n"); +#endif + return DASH; + } + +"=" { +#ifdef DEBUG + printf("EQUA\n"); +#endif + return EQUA; + } + +[ \015\t]+ { } + +\n { linenumber += 1; } + +";".*\n { linenumber += 1; } + +. printf("Unrecognized character %i '%s'\n",yytext[0],yytext); + +%% + +/* User subroutines */ diff --git a/main.c b/main.c new file mode 100644 index 0000000..9f251fa --- /dev/null +++ b/main.c @@ -0,0 +1,755 @@ + +/* 2012 (C) Jussi Rintanen jrintanen.jr@gmail.com */ + +#include +#include + +#include "main.h" +#include "asyntax.h" +#include "intsets.h" +#include "ordintsets.h" + +#include "interface.h" +#include "dimacsinput.h" +#include "clausedb.h" + +#include "operators.h" +#include "tables.h" +//#include "staticpredicates.h" +#include "cleanup.h" +#include "invariants.h" +#include "scc.h" +#include "translate2sat.h" + +#include + +#include +#include +#include +#include +#include +#include +#include + +#ifdef MULTICORE +#include +#endif + +char state_for_random[256]; +char dump_for_random[256]; + +char stri[1000]; + +long time10ms() { /* The time spent in user mode in 100ms */ + struct tms TMS; + times(&TMS); + return TMS.tms_utime / (sysconf(_SC_CLK_TCK) / 100); +} + +int abstimesec() { + struct timeval aux; + gettimeofday(&aux,NULL); + return aux.tv_sec; +} + +int abstimeusec() { + struct timeval aux; + gettimeofday(&aux,NULL); + return aux.tv_usec; +} + +intset test; + +void givememorystatistics() { + char buf[30]; + snprintf(buf, 30, "/proc/%u/statm", (unsigned)getpid()); + FILE* pf = fopen(buf, "r"); + + + if (pf) { + unsigned size; // total program size + unsigned resident;// resident set size + unsigned share;// shared pages + unsigned text;// text (code) + unsigned lib;// library + unsigned data;// data/stack + int MB; + + fscanf(pf, "%u %u %u %u %u %u", &size, &resident, &share, &text, &lib, &data); + + MB = ((double)size)/256.0; + + printf("total size %.3f %s\n", + /* + resident size: %u\n + shared pages : %u\n + text (code) : %u\n + library : %u\n + data/stack : %u\n", + */ + (MB < 700.0) ? MB : MB / 1024.0, + (MB < 700.0) ? "MB" : "GB"); + } + fclose(pf); +} + +/***************** MALLOC STATISTICS *****************/ + +#define noSHOWMALLOCSTATS + +#ifdef SHOWMALLOCSTATS +long statmallocs[1000]; + +void initstatmalloc() { + int i; + allocatedbyFE = 0.0; + for(i=0;i<1000;i++) statmallocs[i] = 0; +} + +void showstatsmalloc() { + int i; + double sum; + sum = 0.0; + printf("Malloc statistics:\n"); + for(i=0;i<1000;i++) { + if(statmallocs[i]) { + printf("%i: %.2f\n",i,((float)statmallocs[i])/1024.0/1024.0); + sum = sum + ((double)statmallocs[i])/1024.0/1024.0; + } + } + printf("TOTAL = %.2f\n",sum); +} +#endif + +void *statmalloc(int n,int s) { + void *tmp; + tmp = malloc(s); +#ifdef SHOWMALLOCSTATS + statmallocs[n] += s; + assert(tmp); +#else + allocatedbyFE += s; +#endif + return tmp; +} + + +/******************** TIME OUTS ********************/ + +void timeouthandler(int i) { + printf("\nTimeout after %i seconds of real time.\n",flagRealTimeout); + givememorystatistics(); +#ifdef SHOWMALLOCSTATS + showstatsmalloc(); +#endif + exit(0); +} + +float time2real(long dif) { + return ((float)dif)/100.0; +} + +float timefromstart() { + return time2real(time10ms() - TIMEstart); +} + +int numer(char c) { + return (c >= '0' && c <= '9'); +} + +void processheuristic(char *decls) { + int position,n; + + HEURordmode = 0; + HEURordmin = 0; + HEURordrnd = 0; + + HEURtime = 0; + HEURops = 0; + HEURchoice = 0; + + HEURactions = 1; + HEURactionchoice = 0; + HEURactiondepthlimit = 0; + + position = 0; + + if(!numer(*decls)) { + printf("ERROR: Expected numeric option.\n"); + exit(1); + } + + do { + + n = 0; + + while(numer(*decls)) { + n = n*10 + (*(decls++) - '0'); + } + + if(*decls != 0 && *decls != ':') { + printf("ERROR: Number separator is : and not %c.\n",*decls); + exit(1); + } + + switch(position) { + case 0: HEURordmode = n; break; + case 1: HEURordmin = n; break; + case 2: HEURordrnd = n; break; + case 3: HEURtime = n; break; + case 4: HEURops = n; break; + case 5: HEURchoice = n; break; + case 6: HEURactions = n; break; + case 7: HEURactionchoice = n; break; + case 8: HEURactiondepthlimit = n; break; + default: printf("ERROR: too many parameters.\n"); exit(1); + } + + position += 1; + + } while(*(decls++) == ':'); + +} + +int main(int argc,char **argv) { + int i,j; + + syntacticclass sclass; + + nOfInputFiles = 0; + + TIMEstartReal = time(NULL); + TIMEstart = time10ms(); +#include "zPRINTDATE" + +#ifdef __LP64__ + printf(" amd64"); +#else + printf(" x86-32"); +#endif + +#ifdef MULTICORE + printf(" multi-core"); +#else + printf(" 1-core"); +#endif + +#ifdef VSIDS + printf("\n"); +#else + printf(" (no VSIDS)\n"); +#endif + +#ifdef MULTICORE + nOfThreads = omp_get_num_procs(); + printf("%i CPUS available\n",nOfThreads); +#endif + + stats_longest_learned = 0; + + /* Process command line options. */ + + flagShortCutHorizon = 5; + + flagShowInput = 0; + flagPDDLadddel = 1; + flagRestartInterval = 60; + flagRestartScheme = 0; + flagPreprocessing = 0; + flagCEvariables = 1; + flagRandomSeedTime = 0; + flagNoInvariants = 0; + flagEliminateConverses = 1; + + currentInputFile = 0; + outputfile = NULL; + +#ifdef __LP64__ + flagMemoryLimit = 8.0*1024.0; /* By default, use max 8 GB of memory. */ +#else + flagMemoryLimit = 3500.0; /* By default, use max 3.5 GB of memory. */ +#endif + + flagOutputDIMACS = 0; + flagIPCplans = 0; + +#if (MPDOWNLOAD || CMPDOWNLOAD) + PLANheuristic = 1; + HEURordmode = 1; + HEURordmin = 0; + HEURordrnd = 0; + HEURtime = 0; + HEURops = 1; /* This was 0 for long. */ + HEURchoice = 0; + HEURactions = 50; /* This was 40 for the AIJ article. */ + HEURactionchoice = 4; + HEURactiondepthlimit = 1; +#else + PLANheuristic = 0; /* By default don't use planning heuristic, but VSIDS. */ +#endif + + flagTimeout = 0; + flagRealTimeout = 0; + + lastTimePoint = 3000; + outputTimeStep = 5; + + firstTimePoint = 0; + debugOutput = 0; + +#ifdef CMPDOWNLOAD + evalAlgorithm = 2; + paramC = 1.414214; /* Default: Algorithm C */ +#else + evalAlgorithm = 1; + paramB = 0.9; /* Default: Algorithm B */ +#endif + + paramM = 20; + + planFrontend = 1; + planSemantics = EStep; + + filenamebase = NULL; + + if(argc == 1) { + printf("\n"); + printf("The command line parameters are the input file names and options:\n"); + printf("-A n Run algorithm A with parameter n (range 1 to 50)"); if(evalAlgorithm==0) printf(" default -A %i.\n",paramA); else printf("\n"); + printf("-B r Run algorithm B with parameter r (range 0.1 to 0.9999)"); if(evalAlgorithm==1) printf(" default -B %.2f.\n",paramB); else printf("\n"); + printf("-C r Run algorithm C with parameter r (range 1.2 to 2.0)"); if(evalAlgorithm==2) printf(" default -C %.2f.\n",paramC); else printf("\n"); + printf("-M n With algorithm B, use maximum n processes (default -M %i).\n",paramM); + printf("-S n Step for horizon lengths 0,n,2n,3n,... (default -S %i, algorithms A and B only)\n",outputTimeStep); + // printf("-H n Use SAT heuristic n.\n"); + // printf("-pH n Use planning heuristic n (0 = none).\n"); + printf("-F n Starting horizon length (default -F %i)\n",firstTimePoint); + printf("-T n Ending horizon length (default -T %i)\n",lastTimePoint); + printf("-P n Choose plan type n: (default -P 2)\n"); + printf(" 0 = sequential plans\n"); + printf(" 1 = A-step plans (Graphplan parallelism)\n"); + printf(" 2 = E-step plans (Rintanen et al. 2004, 2006)\n"); + // printf(" 3 = E-step plans (Ogata et al. 2004)\n"); + printf("-O Write formulas in a file in DIMACS format instead of solving.\n"); + printf("-X Don't use PDDL semantics for simultaneous v:=0 v:=1.\n"); + printf("-Q Output plans in the IPC format.\n"); + printf("-o [filename] Output plan to file.\n"); + printf("-b [filename] Name for the DIMACS CNF files.\n"); + printf("-t n Timeout n seconds of CPU time\n"); + printf("-r n Timeout n seconds of real time\n"); + printf("-m n Allocating max. n MB of memory (default -m %i)\n",(int)flagMemoryLimit); + printf("-N Don't compute invariants.\n"); + printf("-c Don't eliminate converse literals.\n"); + printf("-W Use time as the random seed (instead of seed 0).\n"); + // printf("-Z n Select preprocessing.\n"); + printf("-i n Restart interval is n (default -i %i).\n",flagRestartInterval); + printf("-R n Restart scheme n=0 constant n=1 Luby (default -R %i).\n",flagRestartScheme); +#ifdef CP3 + printf("-E Use external preprocessor.\n"); +#endif + // printf("-K n Add shortcuts for horizon n.\n"); + // printf("-I Show input and auxiliary data in detail.\n"); + // printf("-2 Use the closure of binary clauses to speed up propagation.\n"); + // printf("-d b Level of debug output (default = 0).\n"); + exit(0); + } + + printf("Options:"); + + for(i=1;i= 1) printf("Eliminating static...\n"); + // + // eliminatestatic(); + // // simplifysillyconditionals(); + // + // if(debugOutput >= 1) printf("Grounding...\n"); + // + // groundoperators(); + + if(debugOutput >= 1) printf("Grounding...\n"); + + NEWgroundoperators(); + + printf("Parser: %i ground actions and %i state variables\n",nOfActions,nOfAtoms); + + if(flagShowInput) { + for(i=0;i= 1) printf("Cleaning up...\n"); + + cleanupoperators(); + +#ifdef SHOWMALLOCSTATS + showstatsmalloc(); +#endif + + TIMEinvariants = time10ms(); + + if(debugOutput >= 1) printf("Preparing to compute invariants...\n"); + + computeinvariants(); + if(!flagNoInvariants) printf(" %.2f secs\n", time2real(time10ms() - TIMEinvariants)); + + simplifyoperatorsstatic(); + + eliminatestaticvariables(); + + if(flagEliminateConverses) mergecontras(); + + printf("Simplified: %i ground actions and %i state variables\n",nOfActions,nOfAtoms); + + sortactions(); + + if(flagShowInput) { + for(i=0;i 0) printf("time %.2f for preprocessing for disabling graph\n", time2real(time10ms() - TIMEdisaprepro)); + + if(planSemantics == EStep) { + int maxsize; + TIMEdisabling = time10ms(); + maxsize = scc(nOfActions); + printf(" %.2f secs (max SCC size %i)\n",time2real(time10ms() - TIMEdisabling),maxsize); + } + + TIMEpreprocess = time10ms(); + + encoding(); + + printf("total time %.2f preprocess %.2f \n", + time2real(time10ms() - TIMEstart), + time2real(TIMEpreprocess - TIMEstart)); + + givememorystatistics(); + + printf("max. learned clause length %i\n",stats_longest_learned); + + if(flagOutputDIMACS == 0) { + printf("t val conflicts decisions\n"); + i = 0; + do { + printf("%i %i %i %i\n",seqs[i].sati->nOfTPoints-1,seqs[i].sati->value,seqs[i].sati->conflicts,seqs[i].sati->decisions); + i += 1; + } while(i*outputTimeStep+firstTimePoint <= lastTimePoint && seqs[i].sati && seqs[i-1].sati->value != 1); + // } while(i*outputTimeStep+firstTimePoint < lastTimePoint); + } + + } + +#ifdef SHOWMALLOCSTATS + showstatsmalloc(); +#endif + + return 0; +} diff --git a/main.h b/main.h new file mode 100644 index 0000000..deec528 --- /dev/null +++ b/main.h @@ -0,0 +1,71 @@ + +/* 2010 (C) Jussi Rintanen */ + +int SATheuristic; +int PLANheuristic; +int planFrontend; +int flagShowInput; +int flagRestartInterval; +int flagRestartScheme; +int flagTimeout; +int flagRealTimeout; +int debugOutput; +int flagPDDLadddel; +int flagPreprocessing; +int flagIPCplans; +int flagCEvariables; /* Create a variable for each conditional effect. */ +int flagRandomSeedTime; /* Use the time as a random seed (instead of 0). */ +int flagNoInvariants; +int flagEliminateConverses; /* Eliminate redundant converse literals. */ +int flagExternalPreprocessor; +float flagMemoryLimit; /* Max. MB of memory allowed to allocate. */ + +long TIMEstartReal,TIMEstart,TIMEpreprocess,TIMEdisabling,TIMEdisaprepro,TIMEinvariants; + +#ifdef MULTICORE +int nOfThreads; +#endif + +float timefromstart(); + +double allocatedbyFE; + +typedef enum { Sequ, EStep, EStepOgata, AStep } semantics; + +semantics planSemantics; + +int currentInputFile; +int nOfInputFiles; +char *inputfiles[10]; +char *outputfile; + +int flagOutputDIMACS; + +void *statmalloc(int,int); +//#define statmalloc(a,b) malloc(b) + +int firstTimePoint; +int lastTimePoint; +int outputTimeStep; + +char *filenamebase; + +int evalAlgorithm; /* 0 = A, 1 = B, 2 = C */ +int paramA; +float paramB; +float paramC; +int paramM; /* Max. processes for algorithm B. */ + +/* Heuristics */ + +int HEURordmode; /* 0 = earliest, 1 = latest, 2 = difference */ +int HEURordmin; /* 0 = smaller is better, 1 = bigger is better */ +int HEURordrnd; /* 1 = randomly shuffle (to break ties) */ +int HEURtime; /* 0 = earliest, 1 = latest, 2 = all */ +int HEURops; /* 0 = first, 1 = all */ +int HEURchoice; /* 0 = random, 1 = weight */ +int HEURactions; /* How many suggested actions found? */ +int HEURactionchoice; /* choose action 0 = randomly, 1 = minimal time stamp */ +int HEURactiondepthlimit; + +int stats_longest_learned; diff --git a/makedate b/makedate new file mode 100755 index 0000000..9d75e4e --- /dev/null +++ b/makedate @@ -0,0 +1,4 @@ +rm -f zDATE zPRINTDATE +date '+ %d/%m/20%y %H:%M:%S");' > zDATE +cat zPREF zDATE > zPRINTDATE +rm -f zDATE diff --git a/operators.c b/operators.c new file mode 100644 index 0000000..643bad7 --- /dev/null +++ b/operators.c @@ -0,0 +1,1867 @@ + +/* 2012 (C) Jussi Rintanen jrintanen.jr@gmail.com */ + +#include +#include +#include + +#include "main.h" +#include "asyntax.h" +#include "intsets.h" +#include "ordintsets.h" +#include "operators.h" +#include "tables.h" +#include "invariants.h" + +#define noASSERTS +#define noDEBUG + +/* Local copies (for inlining) of intsets.c functions */ + +int *jITptr; +int jITcounter; + +void jITstart(intset s) { + jITcounter = s->nOfEls; + jITptr = s->elements; +} + +int jITnext(int *i) { + if(jITcounter <= 0) return 0; + jITcounter -= 1; + *i = *(jITptr++); + return 1; +} + +fmalist *fmacons(fma *h,fmalist *t) { + fmalist *r = (fmalist *)statmalloc(4,sizeof(fmalist)); + r->hd = h; + r->tl = t; + return r; +} + +void initactions() { + nOfActions = 0; + maxActions = 100000; + actions = (action *)statmalloc(5,maxActions * sizeof(action)); +} + +fma *Fconj(fmalist *fs) { + fma *f; + + if(fs == NULL) { /* No conjuncts */ + f = (fma *)statmalloc(6,sizeof(fma)); + f->t = TRUE; + } else if(fs->tl == NULL) { /* Only one conjunct */ + return fs->hd; + } else { + f = (fma *)statmalloc(7,sizeof(fma)); + f->t = conj; + f->juncts = fs; + } + return f; +} + +/* Test whether a formula has disjunction in it. */ + +int disjunctivep(fma *f) { + fmalist *l; + switch(f->t) { + case patom: + case natom: + return 0; + case disj: return 1; + case conj: + l = f->juncts; + while(l != NULL) { + if(disjunctivep(l->hd)) return 1; + l = l->tl; + } + } + return 0; +} + +fma *Fdisj(fmalist *fs) { + fma *f; + + if(fs == NULL) { /* No disjuncts */ + f = (fma *)statmalloc(8,sizeof(fma)); + f->t = FALSE; + } else if(fs->tl == NULL) { /* Only one disjunct */ + return fs->hd; + } else { + f = (fma *)statmalloc(9,sizeof(fma)); + f->t = disj; + f->juncts = fs; + } + return f; +} + +fma *Fconj2(fma *f1,fma *f2) { + fma *f; + + f = (fma *)statmalloc(10,sizeof(fma)); + f->t = conj; + f->juncts = fmacons(f1,fmacons(f2,NULL)); + + return f; +} + +fma *Fdisj2(fma *f1,fma *f2) { + fma *f; + + f = (fma *)statmalloc(11,sizeof(fma)); + f->t = disj; + f->juncts = fmacons(f1,fmacons(f2,NULL)); + + return f; +} + +fma *Fatom(int a) { + fma *f = (fma *)statmalloc(12,sizeof(fma)); + f->t = patom; + f->a = a; + return f; +} + +fma *Fnatom(int a) { + fma *f = (fma *)statmalloc(13,sizeof(fma)); + f->t = natom; + f->a = a; + return f; +} + +fma *Ffalse() { + fma *f = (fma *)statmalloc(14,sizeof(fma)); + f->t = FALSE; + return f; +} + +fma *Ftrue() { + fma *f = (fma *)statmalloc(15,sizeof(fma)); + f->t = TRUE; + return f; +} + +fma *Fimpl(fma *f1,fma *f2) { + if(f1->t == TRUE) return f2; + return Fdisj(fmacons(Fneg(f1),fmacons(f2,NULL))); +} + +fma *Fneg(fma *f) { + fmalist *l; + fma *nf; + nf = (fma *)statmalloc(16,sizeof(fma)); + + switch(f->t) { + + case TRUE: nf->t = FALSE; break; + case FALSE: nf->t = TRUE; break; + + case patom: nf->t = natom; nf->a = f->a; break; + case natom: nf->t = patom; nf->a = f->a; break; + + case conj: + nf->t = disj; + l = f->juncts; + nf->juncts = NULL; + while(l != NULL) { + nf->juncts = fmacons(Fneg(l->hd),nf->juncts); + l = l->tl; + } + break; + + case disj: + nf->t = conj; + l = f->juncts; + nf->juncts = NULL; + while(l != NULL) { + nf->juncts = fmacons(Fneg(l->hd),nf->juncts); + l = l->tl; + } + break; + } + + return nf; +} + +/* Test whether a formula is true in a state. */ + + +int ptruep(fma *f,int *state) { + fmalist *fs; + switch(f->t) { + case natom: return (state[f->a] != 1); + case patom: return (state[f->a] != 0); + case disj: + fs = f->juncts; + while(fs != NULL) { + if(ptruep(fs->hd,state)) return 1; + fs = fs->tl; + } + return 0; + case conj: + fs = f->juncts; + while(fs != NULL) { + if(!ptruep(fs->hd,state)) return 0; + fs = fs->tl; + } + return 1; + case TRUE: return 1; + case FALSE: return 0; + } + return 0; +} + +/* Execute action in a state and modify the successor state. +*/ + +int execute(int a,int *state,int *state2) { + eff *e; + int *ls; + + if(!ptruep(actions[a].precon,state)) return 0; + + e = &(actions[a].effects); + while(e != NULL) { + if(ptruep(e->condition,state)) { + ls = e->effectlits; + while(*ls != -1) { +#ifdef DEBUG + printf("Changing value of "); printatomi(feVAR(*ls)); printf(" TRUE\n"); +#endif + state2[feVAR(*ls)] = 1-((*ls)&1); + ls = ls + 1; + } + } + e = e->tl; + } + return 1; +} + +void executeNOprecon(int a,int *state,int *state2) { + eff *e; + int *ls; + + e = &(actions[a].effects); + while(e != NULL) { + if(ptruep(e->condition,state)) { + ls = e->effectlits; + while(*ls != -1) { + state2[feVAR(*ls)] = 1-((*ls)&1); + ls = ls + 1; + } + } + e = e->tl; + } +} + +/* Test whether o1 affects o2 in state. This means: is there an _active_ + effect of o1 that disables o2 or changes it's (conditional) effects. */ + +int opaffectsinstate(int *state,int o1,int o2) { + eff *es; + int *ls; + + es = &(actions[o1].effects); + + /* Go through all effects of o1. */ + while(es != NULL) { + + if(ptruep(es->condition,state)) { /* Only look at active effects. */ + + ls = es->effectlits; + while(*ls != -1) { + if(isaffectedby(o2,*ls)) return 1; + // printf("{"); printatomi((*ls) >> 1); printf("}"); + ls = ls + 1; + } + + } + + es = es->tl; + + } + + return 0; +} + + +/* Print various things. */ + +void printfmalist(fmalist *); +void printfma(fma *f) { + switch(f->t) { + case patom: printatomi(f->a); break; + case natom: printf("(not "); printatomi(f->a); printf(")"); break; + case conj: + printf("(and "); + printfmalist(f->juncts); + printf(")"); + break; + case disj: + printf("(or "); + printfmalist(f->juncts); + printf(")"); + break; + case TRUE: + printf("TRUE"); break; + case FALSE: + printf("FALSE"); break; + } +} + +void printfmalist(fmalist *l) { + if(l == NULL) return; + printfma(l->hd); + if(l->tl != NULL) printf(" "); + printfmalist(l->tl); +} + +void printeff(eff *e) { + fma *c; + int *ls; + if(e == NULL) return; + c = e->condition; + if(c->t != TRUE) { + printf("(when "); + printfma(c); + } + ls = e->effectlits; + while(*ls != -1) { + printf(" "); + if((*ls)&1) { + printf("(not "); + printatomi(feVAR(*ls)); + printf(")"); + } else { + printatomi(feVAR(*ls)); + } + ls = ls + 1; + } + if(c->t != TRUE) printf(")"); + printeff(e->tl); +} + +int fprintactionname(FILE *f,int i) { + int *l; + int len; + l = actions[i].name; + fprintf(f,"%s(",symbol(*l)); + len = strlen(symbol(*l))+1; + l = l + 1; + while(*l != -1) { + fprintf(f,"%s",symbol(*l)); + len += strlen(symbol(*l)); + if(*(l+1) != -1) { + fprintf(f,","); + len += 1; + } + l = l + 1; + } + fprintf(f,")"); + return len+1; +} + +int printactionname(int i) { + return fprintactionname(stdout,i); +} + +int fprintactionnameIPC(FILE *f,int i) { + int *l; + int len; + l = actions[i].name; + fprintf(f,"(%s",symbol(*l)); + len = strlen(symbol(*l))+1; + l = l + 1; + while(*l != -1) { + fprintf(f," %s",symbol(*l)); + len += strlen(symbol(*l)); + l = l + 1; + } + fprintf(f,")"); + return len+1; +} + +int printactionnameIPC(int i) { + return fprintactionnameIPC(stdout,i); +} + +void printaction(int i) { + int *l; + /* Print operator name action(p1,...,pn) */ + l = actions[i].name; + printf("ACTION %i:%s(",i,symbol(*l)); + l = l + 1; + while(*l != -1) { + printf("%s",symbol(*l)); + if(*(l+1) != -1) printf(","); + l = l + 1; + } + printf(") (COST %i)\n",actions[i].cost); + /* Print precondition */ + printfma(actions[i].precon); + printf("\n"); + /* Print effect */ + printeff(&(actions[i].effects)); + printf("\n"); +} + +/* Simplify a formula */ + +fmalist *allconjuncts(fmalist *fs,fmalist *ac) { + while(fs != NULL) { + if(fs->hd->t == conj) ac = allconjuncts(fs->hd->juncts,ac); + else if(fs->hd->t != TRUE) ac = fmacons(fs->hd,ac); + fs = fs->tl; + } + return ac; +} + +fmalist *alldisjuncts(fmalist *fs,fmalist *ac) { + while(fs != NULL) { + if(fs->hd->t == disj) ac = alldisjuncts(fs->hd->juncts,ac); + else if(fs->hd->t != FALSE) ac = fmacons(fs->hd,ac); + fs = fs->tl; + } + return ac; +} + +void simplifyfma(fma *f) { + fmalist *fs; + int trueone,falseone; + switch(f->t) { + case conj: + falseone = 0; + fs = f->juncts; + while(fs != NULL) { + simplifyfma(fs->hd); + if(fs->hd->t == FALSE) { falseone = 1; break; } + fs = fs->tl; + } + if(falseone) f->t = FALSE; + else { + f->juncts = allconjuncts(f->juncts,NULL); + if(f->juncts == NULL) f->t = TRUE; + } + break; + case disj: + trueone = 0; + fs = f->juncts; + while(fs != NULL) { + simplifyfma(fs->hd); + if(fs->hd->t == TRUE) { trueone = 1; break; } + fs = fs->tl; + } + if(trueone) f->t = TRUE; + else { + f->juncts = alldisjuncts(f->juncts,NULL); + if(f->juncts == NULL) f->t = FALSE; + } + break; + default: + break; + } +} + +/* Simplify operator set */ + +void simplifyoperators() { + int i,removed; + removed = 0; + i=0; + while(i < nOfActions) { + simplifyfma(actions[i].precon); + if(actions[i].precon->t == FALSE) { + actions[i] = actions[nOfActions-1]; + removed += 1; + nOfActions -= 1; + } + i += 1; + } + if(debugOutput > 1) + printf("Removed %i unapplicable actions.\n",removed); +} + +/* Test whether a formula can make literal true */ + +int canmaketrue(int op,int l) { + eff *effs; + int *ls; + effs = &(actions[op].effects); + while(effs != NULL) { + ls = effs->effectlits; + while(*ls != -1) { + if(*ls == l) return 1; + ls = ls + 1; + } + effs = effs->tl; + } + return 0; +} + +int occursin(int v,fma *f) { + fmalist *fs; + switch(f->t) { + case conj: + case disj: + fs = f->juncts; + while(fs != NULL) { + if(occursin(v,fs->hd)) return 1; + fs = fs->tl; + } + return 0; + case natom: + case patom: + if(f->a == v) return 1; + return 0; + default: + return 0; + } +} + +int Loccursin(int l,fma *f) { + fmalist *fs; + switch(f->t) { + case conj: + case disj: + fs = f->juncts; + while(fs != NULL) { + if(Loccursin(l,fs->hd)) return 1; + fs = fs->tl; + } + return 0; + case natom: + if(feNLIT(f->a) == l) return 1; + return 0; + case patom: + if(fePLIT(f->a) == l) return 1; + return 0; + default: + return 0; + } +} + +/* Test whether operator op is affected by literal l. */ + +int isaffectedby(int op,int l) { + eff *effs; + if(Loccursin(feNEG(l),actions[op].precon)) return 1; + effs = &(actions[op].effects); + while(effs != NULL) { + if(occursin(feVAR(l),effs->condition)) return 1; + effs = effs->tl; + } + return 0; +} + +/* Test whether one operator affects the other. + This is: + o1 has an effect that falsifies the precondition of o2 or + affects the lhs of a conditional effect of o2. +This must be in accordance with the computation of disabling graphs. */ + +int opaffects(int o1,int o2) { + eff *es; + // intlist *vs; + int *ls; + + es = &(actions[o1].effects); + + /* Go through all effects of o1. */ + while(es != NULL) { + + ls = es->effectlits; + while(*ls != -1) { + if(isaffectedby(o2,*ls)) return 1; + ls = ls + 1; + } + + es = es->tl; + } + + return 0; +} + +/* Test whether two operators can be concurrent, i.e. neither preconditions + nor effects contradict each other. */ + +inline int Amember(int i,int *a) { + while(*a != i) { + if(*a == -1) return 0; + a++; + } + return 1; +} + +int parallel(int op1,int op2) { + int *i,j; + + /* Preconditions contradict? */ + + i = AnecessarypreconP[op1]; + while(*i != -1) { /* Go through operators positive precons. */ + if(Amember(*(i++),AnecessarypreconN[op2])) return 0; /* Direct conflict. */ + } + + i = AnecessarypreconN[op1]; + while(*i != -1) { /* Go through operators negative precons. */ + if(Amember(*(i++),AnecessarypreconP[op2])) return 0; /* Direct conflict. */ + } + + /* Effects contradict? */ + + i = AforcedeffectsP[op1]; + while(*i != -1) { /* Go through operator's positive effects. */ + + if(Amember(*i,AforcedeffectsN[op2])) return 0; /* Direct conflict. */ + + /* Conflicts through a 2-literal invariant l1 | l2. */ + + jITstart(twolits[feNLIT(*i)]); + while(jITnext(&j)) { + if((j&1) && Amember(feVAR(j),AforcedeffectsP[op2])) return 0; + if((j&1) == 0 && Amember(feVAR(j),AforcedeffectsN[op2])) return 0; + } + + i++; + + } + + i = AforcedeffectsN[op1]; + while(*i != -1) { /* Go through operator's negative effects. */ + + if(Amember(*i,AforcedeffectsP[op2])) return 0; /* Direct conflict. */ + + /* Conflicts through a 2-literal invariant l1 | l2. */ + + jITstart(twolits[fePLIT(*i)]); + while(jITnext(&j)) { + if((j&1) && Amember(feVAR(j),AforcedeffectsP[op2])) return 0; + if((j&1) == 0 && Amember(feVAR(j),AforcedeffectsN[op2])) return 0; + } + + i++; + + } + + return 1; +} + + +/* Test whether an effect l can be concurrent with an operator, + i.e. whether l contradicts the effects of the operator. */ + +int Lparallel(int l,int op2) { + int j; + + if((l&1) == 0) { /* Literal is positive. */ + if(Amember(feVAR(l),AforcedeffectsN[op2])) { return 0; } /* Direct conflict. */ + + } else { /* Literal is negative. */ + + if(Amember(feVAR(l),AforcedeffectsP[op2])) { return 0; } /* Direct conflict. */ + + } + + /* Conflicts through a 2-literal invariant l1 | l2. */ + + jITstart(twolits[feNEG(l)]); + while(jITnext(&j)) { + if((j&1) && Amember(feVAR(j),AforcedeffectsP[op2])) { return 0; } + if((j&1) == 0 && Amember(feVAR(j),AforcedeffectsN[op2])) { return 0; } + } + + return 1; +} + +/* Store literals occurring in a formula or in the formulas of an action + in an ordintset. */ + +void Fcollectliterals(ordintset s,fma *f) { + fmalist *fs; + switch(f->t) { + case conj: + case disj: + fs = f->juncts; + while(fs != NULL) { + Fcollectliterals(s,fs->hd); + fs = fs->tl; + } + break; + case natom: + case patom: + OSinsert(fePLIT(f->a),s); + OSinsert(feNLIT(f->a),s); + break; + default: 1; + } +} + +void collectliterals(ordintset s,int op) { + eff *effs; + int *ls; + + Fcollectliterals(s,actions[op].precon); + + effs = &(actions[op].effects); + + while(effs != NULL) { + + Fcollectliterals(s,effs->condition); + + ls = effs->effectlits; + while(*ls != -1) { + OSinsert(*ls,s); + ls = ls + 1; + } + + effs = effs->tl; + } + +} + +/* Replace static variables with truth values */ + +fma *simplifyfmastatic(fma *f) { + fmalist *fs; + fmalist **prev; + int trueone,falseone; + switch(f->t) { + case conj: + falseone = 0; + fs = f->juncts; + prev = &(f->juncts); + while(fs != NULL) { + fs->hd = simplifyfmastatic(fs->hd); + if(fs->hd->t == FALSE) { falseone = 1; break; } + if(fs->hd->t == TRUE) { *prev = fs->tl; } /* TRUE conjunct: remove */ + else prev = &(fs->tl); + fs = fs->tl; + } + if(falseone) f->t = FALSE; + if(f->juncts == NULL) f->t = TRUE; + else if(f->juncts->tl == NULL) return f->juncts->hd; + break; + case disj: + trueone = 0; + fs = f->juncts; + prev = &(f->juncts); + while(fs != NULL) { + fs->hd = simplifyfmastatic(fs->hd); + if(fs->hd->t == TRUE) { trueone = 1; break; } + if(fs->hd->t == FALSE) { *prev = fs->tl; } /* FALSE disjunct: remove */ + else prev = &(fs->tl); + fs = fs->tl; + } + if(trueone) f->t = TRUE; + if(f->juncts == NULL) f->t = FALSE; + else if(f->juncts->tl == NULL) return f->juncts->hd; + break; + case patom: + switch(onelits[f->a]) { + case -1: break; + case 0: f->t = FALSE; break; + case 1: f->t = TRUE; break; + } + break; + case natom: + switch(onelits[f->a]) { + case -1: break; + case 1: f->t = FALSE; break; + case 0: f->t = TRUE; break; + } + break; + default: + break; + } + return f; +} + +/* Remove static effects from a list of effect literals. */ + +intlist *removeirrelevantlits(int *ls) { + int *wp,*rp; + wp = ls; + rp = ls; + while(1==1) { + *wp = *rp; + if(*wp == -1) break; + if(onelits[feVAR(*wp)] == -1) wp = wp + 1; /* Irrelevant if onelits[*wp] == -1. */ + rp = rp + 1; + } +} + +eff *simplifyeffstatic(eff *e) { + if(e == NULL) return NULL; + e->condition = simplifyfmastatic(e->condition); + if(e->condition->t == FALSE) return simplifyeffstatic(e->tl); + else { + removeirrelevantlits(e->effectlits); + e->tl = simplifyeffstatic(e->tl); + return e; + } +} + +#ifdef ASDFASDFASDFASDFASDFASDFASDFASDFASDFASDF +/* Check if a conjunction has two literals that conflict through a mutex. */ +/* This is to eliminate actions with always-false preconditions. */ + +int conjunctof(fmalist *fs,int l) { + int v; + v = l >> 1; + if(l&1) { /* Negative literal */ + while(fs != NULL) { + if((fs->hd->t == patom) && (fs->hd->a == v)) { +#ifdef DEBUG + printatomi(fs->hd->a); printf(" MUTEX CONTRADICTS WITH "); +#endif + return 1; + } + fs = fs->tl; + } + } else { /* Positive literal */ + while(fs != NULL) { + if((fs->hd->t == natom) && (fs->hd->a == v)) { +#ifdef DEBUG + printf("NOT "); printatomi(fs->hd->a); printf(" MUTEX CONTRADICTS WITH "); +#endif + return 1; + } + fs = fs->tl; + } + } + return 0; +} + +int conjunctof0(fmalist *fs,intset ls) { + int l; + jITstart(ls); + while(jITnext(&l)) { + if(conjunctof(fs,l)) return 1; + } + return 0; +} + +int mutexcontradict(fma *f) { + fmalist *fs; + if(f->t == conj) { + fs = f->juncts; + while(fs != NULL) { + switch(fs->hd->t) { + case patom: + if(conjunctof0(fs,twolits[feNLIT(fs->hd->a)])) { +#ifdef DEBUG + printatomi(fs->hd->a); printf("\n"); +#endif + return 1; + } + break; + case natom: + if(conjunctof0(fs,twolits[fePLIT(fs->hd->a)])) { +#ifdef DEBUG + printf("\n"); printatomi(fs->hd->a); printf("\n"); +#endif + return 1; + } + break; + default: break; + } + fs = fs->tl; + } + } + return 0; +} +#endif + +int mutcon2(int l1,int l2) { + int l; + jITstart(twolits[feNEG(l1)]); + while(jITnext(&l)) { + if(l==feNEG(l2)) return 1; + } + return 0; +} + +int mutcon(int l,fmalist *fs) { + while(fs != NULL) { + if(fs->hd->t == patom && mutcon2(l,fePLIT(fs->hd->a))) return 1; + if(fs->hd->t == natom && mutcon2(l,feNLIT(fs->hd->a))) return 1; + fs = fs->tl; + } + return 0; +} + +int mutexcontradict2(fma *f) { + fmalist *fs; + if(f->t == conj) { + fs = f->juncts; + while(fs != NULL) { + if(fs->hd->t == patom && mutcon(fePLIT(fs->hd->a),fs->tl)) return 1; + if(fs->hd->t == natom && mutcon(feNLIT(fs->hd->a),fs->tl)) return 1; + fs = fs->tl; + } + } + return 0; +} + + +/* Replace static variables by T of F. */ + +void simplifyoperatorsstatic() { + int i,removed; + removed = 0; + i=0; + while(i < nOfActions) { + simplifyeffstatic(&(actions[i].effects)); + actions[i].precon = simplifyfmastatic(actions[i].precon); + if(mutexcontradict2(actions[i].precon)) { +#ifdef DEBUG + printf("MUTEX precondition in action "); printaction(i); +#endif + actions[i].precon->t = FALSE; + } + if(actions[i].precon->t == FALSE || actions[i].effects.condition->t == FALSE) { + // printf("REMOVING "); printaction(i); + actions[i] = actions[nOfActions-1]; + removed += 1; + nOfActions -= 1; + } else i += 1; + } + if(debugOutput > 1 && removed) printf("Removed %i unapplicable actions.\n",removed); +} + +void findfmaoccurrences(int op,fma *f,int polarity) { + fmalist *fs; + switch(f->t) { + case conj: + case disj: + fs = f->juncts; + while(fs != NULL) { + findfmaoccurrences(op,fs->hd,polarity); + fs = fs->tl; + } + break; + case patom: + if(polarity == 2) { +#ifdef DEBUG + printatomi(f->a); printf(" occurs in "); + printaction(op); printf("\n"); +#endif + OSinsert(op,preconoccP[f->a]); + } else OSinsert(op,condocc[f->a]); + break; + case natom: + if(polarity == 2) OSinsert(op,preconoccN[f->a]); + else OSinsert(op,condocc[f->a]); + break; + default: + break; + } +} + +/* Compute literals that are necessarily true when formula f is true. +This also takes into account known 2-literal invariants. +*/ + +void findnecessaryprecons(int i,fma *f) { + int j; + fmalist *fs; + switch(f->t) { + case patom: + OSinsert(f->a,necessarypreconP[i]); + OSinsert(i,necessarypreconofP[f->a]); + jITstart(twolits[feNLIT(f->a)]); + while(jITnext(&j)) { + if(j&1) { + OSinsert(feVAR(j),necessarypreconN[i]); /* Problem with Blai's example */ + OSinsert(i,necessarypreconofN[feVAR(j)]); + } else { + OSinsert(feVAR(j),necessarypreconP[i]); /* Problem with Blai's example */ + OSinsert(i,necessarypreconofP[feVAR(j)]); + } + } + break; + case natom: + OSinsert(f->a,necessarypreconN[i]); + OSinsert(i,necessarypreconofN[f->a]); + jITstart(twolits[fePLIT(f->a)]); + while(jITnext(&j)) { + if(j&1) { + OSinsert(feVAR(j),necessarypreconN[i]); /* Problem with Blai's example */ + OSinsert(i,necessarypreconofN[feVAR(j)]); + } else { + OSinsert(feVAR(j),necessarypreconP[i]); /* Problem with Blai's example */ + OSinsert(i,necessarypreconofP[feVAR(j)]); + } + } + break; + case conj: + fs = f->juncts; + while(fs != NULL) { + findnecessaryprecons(i,fs->hd); + fs = fs->tl; + } + break; + case disj: + break; + case TRUE: + case FALSE: + break; + } +} + +void findoccurrences() { + int i; + eff *e; + int always; + + /* Which operators do a variable occur in positively/negatively ? */ + effectoccP = (ordintset *)statmalloc(300,nOfAtoms * sizeof(ordintset)); + effectoccN = (ordintset *)statmalloc(300,nOfAtoms * sizeof(ordintset)); + + preconoccP = (ordintset *)statmalloc(300,nOfAtoms * sizeof(ordintset)); + preconoccN = (ordintset *)statmalloc(300,nOfAtoms * sizeof(ordintset)); + + condocc = (ordintset *)statmalloc(300,nOfAtoms * sizeof(ordintset)); + + forcedeffectsP = (ordintset *)statmalloc(300,nOfActions * sizeof(ordintset)); + forcedeffectsN = (ordintset *)statmalloc(300,nOfActions * sizeof(ordintset)); + + forcedeffectoccP = (ordintset *)statmalloc(300,nOfAtoms * sizeof(ordintset)); + forcedeffectoccN = (ordintset *)statmalloc(300,nOfAtoms * sizeof(ordintset)); + + necessarypreconP = (ordintset *)statmalloc(300,nOfActions * sizeof(ordintset)); + necessarypreconN = (ordintset *)statmalloc(300,nOfActions * sizeof(ordintset)); + + necessarypreconofP = (ordintset *)statmalloc(300,nOfAtoms * sizeof(ordintset)); + necessarypreconofN = (ordintset *)statmalloc(300,nOfAtoms * sizeof(ordintset)); + + /* We use the ordintset data structure here because the sets + involving operators will be ordered without additional + ordering effort. + FIX: The lists of literals need effort to order. Should + these be represented by some other data structure for + additional efficiency? */ + + + for(i=0;i=0;i--) { + + /* Go through precondition */ + + findnecessaryprecons(i,actions[i].precon); + findfmaoccurrences(i,actions[i].precon,2); + + /* Go through effects and update effect occurrences */ + + e = &(actions[i].effects); + + while(e != NULL) { + int *l; + + findfmaoccurrences(i,e->condition,1); + + always = (e->condition->t == TRUE); + + l = e->effectlits; + while(*l != -1) { + if((*l)&1) { + OSinsert(i,effectoccN[feVAR(*l)]); + if(always) OSinsert(i,forcedeffectoccN[feVAR(*l)]); + if(always) OSinsert(feVAR(*l),forcedeffectsN[i]); + } else { + OSinsert(i,effectoccP[feVAR(*l)]); + if(always) OSinsert(i,forcedeffectoccP[feVAR(*l)]); + if(always) OSinsert(feVAR(*l),forcedeffectsP[i]); + } + l = l + 1; + } + + + e = e->tl; + } + + } + + constructoperatorarrays(); +} + +/* Sort actions alphabetically according to their name. */ + +int actionCmp(action *a1,action *a2) { + int v; + + int *n1,*n2; + n1 = a1->name; + n2 = a2->name; + while(*n1 != -1 && n2 != -1) { + v = strcmp(symbol(*n1),symbol(*n2)); + if(v != 0) return v; + n1 = n1 + 1; n2 = n2 + 1; + } + if(*n1 != -1) return 1; + if(*n2 != -1) return 1; + return 0; +} + +void sortactions() { + qsort(actions,nOfActions,sizeof(action),actionCmp); +} + +/**************************************************************************/ +/******************** Eliminate static variables **************************/ +/**************************************************************************/ + + +/* After detecting static variables, eliminate them so that the +variable numbering without the static variables is contiguous. */ + +void renamefma(fma *f,int *mapping) { + fmalist *fs; + switch(f->t) { + case patom: + case natom: + f->a = mapping[f->a]; break; + case conj: + case disj: + fs = f->juncts; + while(fs != NULL) { + renamefma(fs->hd,mapping); + fs = fs->tl; + } + break; + default: break; + } +} + +void renameeff(eff *e,int *mapping) { + int *ls; + while(e != NULL) { + renamefma(e->condition,mapping); + ls = e->effectlits; + while(*ls != -1) { + if((*ls)&1) *ls = feNLIT(mapping[feVAR(*ls)]); + else *ls = fePLIT(mapping[feVAR(*ls)]); + ls = ls + 1; + } + e = e->tl; + } +} + +void renameaction(action *a,int *mapping) { + renamefma(a->precon,mapping); + renameeff(&(a->effects),mapping); +} + +void renametwolits(intset is,int *mapping) { + int i; + for(i=0;inOfEls;i++) { + if(1&(is->elements[i])) { + is->elements[i] = feNLIT(mapping[feVAR(is->elements[i])]); + } else { + is->elements[i] = fePLIT(mapping[feVAR(is->elements[i])]); + } + } +} + +/* Remove static variables completely, to make the numbering of + variables contiguous. */ + +void eliminatestaticvariables() { + int i; + int from,to; + int NEWnOfAtoms; + int mapping[nOfAtoms]; + + /* Do the mapping: move a variable one step earlier if the preceding + variable is a static one. */ + + // for(i=0;iname symbol table + - twolits + Elimination happens after the actions and the goal formula have been + simplified (i.e. static variables have been replaced by T or F.) + */ + + for(i=0;i= 0); + // printf("mapping[%i] = %i.\n",i,mapping[i]); + twolits[fePLIT(mapping[i])] = twolits[fePLIT(i)]; + twolits[feNLIT(mapping[i])] = twolits[feNLIT(i)]; + } + } + + /* Fix initial state description. */ + + for(i=0;it) { + case patom: + if(mapping[f->a] != -1) { + if(mapping[f->a] & 1) f->t = natom; + f->a = (mapping[f->a] >> 1); + } + break; + case natom: + if(mapping[f->a] != -1) { + if(mapping[f->a] & 1) f->t = patom; + f->a = (mapping[f->a] >> 1); + } + break; + case conj: + case disj: + fs = f->juncts; + while(fs != NULL) { + renamefmaL(fs->hd,mapping); + fs = fs->tl; + } + break; + default: break; + } +} + +/* Here, instead of renaming, we will just remove the effect, as + the remaining variable will be changed anyway. + Seems to be wrong. +*/ + +void renameeffL(eff *e,int *mapping) { + int *readptr,*writeptr; + while(e != NULL) { + renamefmaL(e->condition,mapping); + readptr = e->effectlits; + writeptr = e->effectlits; + while(*readptr != -1) { + + *writeptr = *readptr; + + if(mapping[feVAR(*readptr)] != -1) { /* Eliminate */ + } else { /* Keep */ + writeptr = writeptr + 1; + } + + readptr = readptr + 1; + + } + *writeptr = -1; + e = e->tl; + } +} + +void eliminatefromtwolits(intset is,int *mapping) { + int i,iread,iwrite; + int removed; + removed = 0; + iread = 0; iwrite = 0; + + for(i=0;inOfEls;i++) { + + is->elements[iwrite] = is->elements[iread]; + + if(mapping[feVAR(is->elements[iread])] != -1) { /* Eliminate */ + removed = removed + 1; + } else { + iwrite = iwrite + 1; + } + + iread = iread + 1; + } + is->nOfEls = is->nOfEls-removed; +} + +void deletetwolits(int l) { + twolits[l]->nOfEls = 0; +} + +void renameactionL(action *a,int *mapping) { + renamefmaL(a->precon,mapping); + renameeffL(&(a->effects),mapping); +} + +/* Identify pairs of variables that always have the opposite truth value. */ + +void mergecontras() { + int l0,l,l2,cnt; + int i; + int mapping[nOfAtoms]; + + for(i=0;i> 1) > feVAR(l))) { + mapping[feVAR(l2)] = ((l&1) == (l2&1)) + (feVAR(l) << 1); + } + cnt += 1; + } + } + } + if(flagShowInput) { + printf("TOTAL OF %i CONVERSES FOR %i VARIABLES.\n",cnt,nOfAtoms); + for(i=0;i> 1); printf("\n"); } } + } + for(i=0;it) { + case disj: return 0; + case conj: + fs = f->juncts; + while(fs != NULL) { + if(!conjunctivep(fs->hd)) return 0; + fs = fs->tl; + } + default: return 1; + } +} + +/* Check if a formula has a fixed truth-value (TRUE or FALSE). + This is a simple syntactic test, not a full SAT/TAUT test. */ + +int constantp(fma *f) { + fmalist *fs; + switch(f->t) { + case patom: + case natom: + return 0; + case disj: + case conj: + fs = f->juncts; + while(fs != NULL) { + if(!constantp(fs->hd)) return 0; + fs = fs->tl; + } + return 1; + case TRUE: + case FALSE: + return 1; + } +} + +int STRIPSaction(int i) { + eff *e; + if(!conjunctivep(actions[i].precon)) return 0; + e = &(actions[i].effects); + while(e != NULL) { + if(!constantp(e->condition)) return 0; + e = e->tl; + } + return 1; +} + +int CONJUNCTIVEaction(int i) { + eff *e; + if(!conjunctivep(actions[i].precon)) return 0; + e = &(actions[i].effects); + while(e != NULL) { + if(!conjunctivep(e->condition)) return 0; + e = e->tl; + } + return 1; +} + +syntacticclass actionclass(int i) { + eff *e; + syntacticclass class; + + if(!conjunctivep(actions[i].precon)) return GeneralPDDL; + e = &(actions[i].effects); + + class = STRIPS; + while(e != NULL) { + if(!conjunctivep(e->condition)) return GeneralPDDL; + if(!constantp(e->condition)) class = Conjunctive; + e = e->tl; + } + return class; +} + +syntacticclass goalclass() { + if(!conjunctivep(goal)) return GeneralPDDL; + else return STRIPS; +} + + +/********************************************************************/ +/******************* Ordered integer sets ***************************/ +/********************************************************************/ + +intlist *freeels = NULL; + +inline intlist *OScons(int v,intlist *l) { + intlist *tmp; + if(freeels != NULL) { + tmp = freeels; + freeels = (intlist *)(freeels->tl); + } else { + tmp = (intlist *)statmalloc(200,sizeof(struct _intlist)); + } + tmp->hd = v; + tmp->tl = l; + return tmp; +} + +/* Free a cons pair to be used by OScons later. */ + +inline void OSfree(intlist *l) { + l->tl = freeels; + freeels = l; +} + +/* Really release all cons pairs allocated with OScons and freed by OSfree. */ + +void OSreleasefree() { + intlist *l,*tmp; + l = freeels; + while(l != NULL) { + tmp = l; + l = l->tl; + free(tmp); + } + freeels = NULL; +} + +void OSfreeset(ordintset s) { + OSfree(s->elements); + free(s); +} + +ordintset OScreate() { + ordintset tmp; + tmp = (ordintset)statmalloc(201,sizeof(struct _ordintset)); + tmp->nOfEls = 0; + tmp->elements = NULL; + return tmp; +} + +ordintset OScreateSize(int i) { return OScreate(); } + +inline int OScard(ordintset s) { + return s->nOfEls; +} + +inline int OSemptyp(ordintset s) { + return (s->nOfEls == 0); +} + +inline void OSmakeempty(ordintset s) { + intlist *l,*tmp; + s->nOfEls = 0; + l = s->elements; + s->elements = NULL; + while(l != NULL) { + tmp = l; + l = l->tl; + OSfree(tmp); + } +} + +inline void OSinsert(int v,ordintset s) { + intlist **prev,*l; + + prev = &(s->elements); + l = s->elements; + while(l != NULL && l->hd < v) { + prev = &(l->tl); + l = l->tl; + } + + if(l != NULL && l->hd == v) return; + + *prev = OScons(v,l); + s->nOfEls += 1; +} + +inline void OSremove(int v,ordintset s) { + printf("ERROR: not implemented\n"); + exit(1); +} + +inline void OSremoveSet(ordintset s1,ordintset s2) { + intlist *l1,*l2,**prev,*tmp; + +#ifdef DEBUG + printf("REMOVE "); OSprint(s1); + printf("FROM "); OSprint(s2); +#endif + + l1 = s1->elements; + l2 = s2->elements; + + prev = &(s2->elements); + + while(l1 != NULL) { + while(l2 != NULL && l1->hd > l2->hd) { /* Find location for element. */ + prev = &(l2->tl); + l2 = l2->tl; + } + + if(l2 == NULL) break; + if(l1->hd == l2->hd) { /* Something to remove */ + tmp = l2; + *prev = l2->tl; + s2->nOfEls -= 1; + l2 = l2->tl; + OSfree(tmp); + } + l1 = l1->tl; + } + +#ifdef DEBUG + printf("TO GET "); OSprint(s2); + printf("\n"); +#endif +} + +inline void OS2removeSet(ordintset s1,ordintset s2) { + intlist *l1,*l2,**prev,*tmp; + +#ifdef DEBUG + printf("REMOVE "); OSprint(s1); + printf("FROM "); OSprint(s2); +#endif + + l1 = s1->elements; + l2 = s2->elements; + + prev = &(s2->elements); + + while(l1 != NULL) { + while(l2 != NULL && l1->hd > l2->hd) { /* Find location for element. */ + prev = &(l2->tl); + l2 = l2->tl; + } + + if(l2 == NULL) break; + if(l1->hd == l2->hd) { + tmp = l2; + *prev = l2->tl; + s2->nOfEls -= 1; + l2 = l2->tl; + OSfree(tmp); + } + l1 = l1->tl; + } + +#ifdef DEBUG + printf("TO GET "); OSprint(s2); + printf("\n"); +#endif +} + +/* Intersect set s1 with s2: s1 := s1 /\ s2 */ + +inline void OSintersect(ordintset s1,ordintset s2) { + intlist *l1,*l2,**prev,*tmp; + +#ifdef DEBUG + printf("INTERSECT "); OSprint(s1); + printf("WITH "); OSprint(s2); +#endif + + l1 = s1->elements; + l2 = s2->elements; + + prev = &(s1->elements); + + while(l1 != NULL) { + while((l2 != NULL) && (l1->hd > l2->hd)) { /* Skip elements not in l1. */ + l2 = l2->tl; + } + + if((l2 != NULL) && (l1->hd == l2->hd)) { /* Retain element. */ + + prev = &(l1->tl); + l1 = l1->tl; + l2 = l2->tl; + + } else { /* Remove the first element of l1. */ + + tmp = l1; + *prev = l1->tl; + s1->nOfEls -= 1; + l1 = l1->tl; + OSfree(tmp); + + } + } + +#ifdef DEBUG + printf("TO GET "); OSprint(s1); + printf("\n"); +#endif +} + + +inline void OSaddelementsSTUPID(ordintset s1,ordintset s2) { + intlist *l1; + l1 = s1->elements; + while(l1 != NULL) { + OSinsert(l1->hd,s2); + l1 = l1->tl; + } +} + +inline void OSaddelements(ordintset s1,ordintset s2) { + intlist *l1,*l2,**prev,*tmp; + + // printf("ADD "); OSprint(s1); + // printf("TO "); OSprint(s2); + + l1 = s1->elements; + l2 = s2->elements; + + prev = &(s2->elements); + + while(l1 != NULL) { + + while(l2 != NULL && l1->hd > l2->hd) { /* Find location for element. */ + prev = &(l2->tl); + l2 = l2->tl; + } + + if(l2 == NULL || l1->hd < l2->hd) { + tmp = OScons(l1->hd,l2); + *prev = tmp; + prev = &(tmp->tl); + s2->nOfEls += 1; + } + l1 = l1->tl; + } + + // printf("TO GET "); OSprint(s2); + // printf("\n"); +} + +/* Iterator */ + +inline void OSstart(ordintset s,intlist **iterate) { + *iterate = s->elements; +} + +inline int OSnext(int *v,intlist **iterate) { + if(*iterate != NULL) { + *v = (*iterate)->hd; + *iterate = (*iterate)->tl; + return 1; + } else { + return 0; + } +} + + +inline void OSprint(ordintset s) { + intlist *l; + l = s->elements; + while(l != NULL) { + printf(" %i",l->hd); + l = l->tl; + } + printf("\n"); +} diff --git a/operators.h b/operators.h new file mode 100644 index 0000000..a391ff9 --- /dev/null +++ b/operators.h @@ -0,0 +1,167 @@ + +/* 2012 (C) Jussi Rintanen */ + +/**************** compact ground formulae */ + +#ifdef CFMA + +/* Compact formula representation: + Formula is a pointer. + If the lsb is 1, it is TRUE, FALSE or a literal. + If the lsb is 0, it is a pointer to an integer array for con/disjunction. + For conjunctions and disjunctions the first int is (length << 1) | cnj, + where cnj == 1 if it is a conjunction and cnj = 0 if it is a disjunction. +*/ + +typedef int **cfma; + +/* If the lsb == 1, the 3 lsbs represent the type. */ + +#define cTRUEtag 1 +#define cFALSEtag 3 +#define cPATOMtag 5 +#define cNATOMtag 7 + +/* Literals are represented as (var << 3) | c?ATOM. */ + +#define cPATOM(v) ((cfma)(((v) << 3) | cPATOMtag)) +#define cNATOM(v) ((cfma)(((v) << 3) | cNATOMtag)) +#define cTRUE ((cfma)cTRUEtag) +#define cFALSE ((cfma)cFALSEtag) + +#endif + +/**************** ground formulae */ + +typedef enum { patom, natom, conj, disj, TRUE, FALSE } fmatype; + +typedef struct _fma { + fmatype t; + union { + int a; + struct _fmalist0 { struct _fma *hd; struct _fmalist0 *tl; } *juncts; + }; +} fma; + + +/***************** ground effects */ + +typedef struct _eff { + fma *condition; +#ifdef CFMA + cfma ccondition; +#endif + int *effectlits; + struct _eff *tl; +} eff; + +typedef struct _fmalist { fma *hd; struct _fmalist* tl; } fmalist; + +fmalist *fmacons(fma *,fmalist *); + +fma *Fconj(fmalist *); +fma *Fdisj(fmalist *); +fma *Fconj2(fma *,fma *); +fma *Fdisj2(fma *,fma *); +fma *Fatom(int); +fma *Fnatom(int); +fma *Fneg(fma *); +fma *Fimpl(fma *,fma *); +fma *Ftrue(); +fma *Ffalse(); + +typedef struct _action { + int *name; + fma *precon; +#ifdef CFMA + cfma cprecon; +#endif + eff effects; + int cost; +} action; + +int nOfActions; +int maxActions; +action *actions; + +int disjunctivep(fma *); +void initactions(); + +int ptruep(fma *,int *); /* Test for truth of a formula in a state. */ +int execute(int,int *,int *); /* Execute an action. */ +void executeNOprecon(int,int *,int *); /* Execute an action without testin precondition. */ + +int fprintactionname(FILE *,int); +int printactionname(int); +int fprintactionnameIPC(FILE *,int); +int printactionnameIPC(int); +void printaction(int); +void printfma(fma *); + +typedef enum { STRIPS, Conjunctive, GeneralPDDL } syntacticclass; + +syntacticclass actionclass(int); + +syntacticclass goalclass(); + +int *initialstate; +fma *goal; +int goalisdisjunctive; + +void simplifyoperators(); +void simplifyoperatorsstatic(); + +ordintset *effectoccP; /* operators in which var is a positive effect */ +ordintset *effectoccN; /* operators in which var is a negative effect */ +ordintset *forcedeffectoccP; /* operators in which var is a positive effect */ +ordintset *forcedeffectoccN; /* operators in which var is a negative effect */ + + +ordintset *preconoccN; /* operators in which var is negative in precondition */ +ordintset *preconoccP; /* operators in which var is positive in precondition */ + +ordintset *condocc; /* operators in which var occurs in a condition for effect */ + +ordintset *forcedeffectsP; /* variables the operator always makes true */ +ordintset *forcedeffectsN; /* variables the operator always makes false */ + +ordintset *preconP; /* variable that must be true for operator */ +ordintset *preconN; /* variable that must be false for operator */ + +/* Same as preconP and preconN, but including lits inferred with invariants. */ +ordintset *necessarypreconP; /* variable that must be true for operator */ +ordintset *necessarypreconN; /* variable that must be false for operator */ + +ordintset *necessarypreconofP; /* operators in which atom is a nec precon */ +ordintset *necessarypreconofN; /* operators in which atom is a nec precon */ + +int canmaketrue(int,int); +int isaffectedby(int,int); +int opaffects(int,int); +int opaffectsinstate(int *,int,int); +int parallel(int,int); +int Lparallel(int,int); + +void findoccurrences(); + +void sortactions(); + +void collectliterals(ordintset,int); + +void eliminatestaticvariables(); + +void mergecontras(); + +int **AeffectoccP; /* operators in which var is a positive effect */ +int **AeffectoccN; /* operators in which var is a negative effect */ +int **ApreconP; /* variable that must be true for operator */ +int **ApreconN; /* variable that must be false for operator */ +int **AforcedeffectsP; /* variables the operator always makes true */ +int **AforcedeffectsN; /* variables the operator always makes false */ +int **AnecessarypreconP; /* variable that must be true for operator */ +int **AnecessarypreconN; /* variable that must be false for operator */ +int **ApreconoccN; /* operators in which var is negative in precondition */ +int **ApreconoccP; /* operators in which var is positive in precondition */ +int **Acondocc; /* operators in which var occurs in a condition for effect */ + +void constructoperatorarrays(); diff --git a/ordintsets.c b/ordintsets.c new file mode 100644 index 0000000..9aa4967 --- /dev/null +++ b/ordintsets.c @@ -0,0 +1,291 @@ + +/* 2010 (C) Jussi Rintanen */ + +#include "asyntax.h" +#include "ordintsets.h" + +#include +#include + +intlist *freeels = NULL; + +inline intlist *OScons(int v,intlist *l) { + intlist *tmp; + if(freeels != NULL) { + tmp = freeels; + freeels = (intlist *)(freeels->tl); + } else { + tmp = (intlist *)malloc(sizeof(struct _intlist)); + } + tmp->hd = v; + tmp->tl = l; + return tmp; +} + +/* Free a cons pair to be used by OScons later. */ + +inline void OSfree(intlist *l) { + l->tl = freeels; + freeels = l; +} + +/* Really release all cons pairs allocated with OScons and freed by OSfree. */ + +void OSreleasefree() { + intlist *l,*tmp; + l = freeels; + while(l != NULL) { + tmp = l; + l = l->tl; + free(tmp); + } + freeels = NULL; +} + +ordintset OScreate() { + ordintset tmp; + tmp = (ordintset)malloc(sizeof(struct _ordintset)); + tmp->nOfEls = 0; + tmp->elements = NULL; + return tmp; +} + +ordintset OScreateSize(int i) { return OScreate(); } + +inline int OScard(ordintset s) { + return s->nOfEls; +} + +inline int OSemptyp(ordintset s) { + return (s->nOfEls == 0); +} + +inline void OSmakeempty(ordintset s) { + intlist *l,*tmp; + s->nOfEls = 0; + l = s->elements; + s->elements = NULL; + while(l != NULL) { + tmp = l; + l = l->tl; + OSfree(tmp); + } +} + +inline void OSinsert(int v,ordintset s) { + intlist **prev,*l; + + prev = &(s->elements); + l = s->elements; + while(l != NULL && l->hd < v) { + prev = &(l->tl); + l = l->tl; + } + + if(l != NULL && l->hd == v) return; + + *prev = OScons(v,l); + s->nOfEls += 1; +} + +inline void OSremove(int v,ordintset s) { + printf("ERROR: not implemented\n"); + exit(1); +} + +inline void OSremoveSet(ordintset s1,ordintset s2) { + intlist *l1,*l2,**prev,*tmp; + +#ifdef DEBUG + printf("REMOVE "); OSprint(s1); + printf("FROM "); OSprint(s2); +#endif + + l1 = s1->elements; + l2 = s2->elements; + + prev = &(s2->elements); + + while(l1 != NULL) { + while(l2 != NULL && l1->hd > l2->hd) { /* Find location for element. */ + prev = &(l2->tl); + l2 = l2->tl; + } + + if(l2 == NULL) break; + if(l1->hd == l2->hd) { /* Something to remove */ + tmp = l2; + *prev = l2->tl; + s2->nOfEls -= 1; + l2 = l2->tl; + OSfree(tmp); + } + l1 = l1->tl; + } + +#ifdef DEBUG + printf("TO GET "); OSprint(s2); + printf("\n"); +#endif +} + +inline void OS2removeSet(ordintset s1,ordintset s2) { + intlist *l1,*l2,**prev,*tmp; + +#ifdef DEBUG + printf("REMOVE "); OSprint(s1); + printf("FROM "); OSprint(s2); +#endif + + l1 = s1->elements; + l2 = s2->elements; + + prev = &(s2->elements); + + while(l1 != NULL) { + while(l2 != NULL && l1->hd > l2->hd) { /* Find location for element. */ + prev = &(l2->tl); + l2 = l2->tl; + } + + if(l2 == NULL) break; + if(l1->hd == l2->hd) { + tmp = l2; + *prev = l2->tl; + s2->nOfEls -= 1; + l2 = l2->tl; + OSfree(tmp); + } + l1 = l1->tl; + } + +#ifdef DEBUG + printf("TO GET "); OSprint(s2); + printf("\n"); +#endif +} + +/* Intersect set s1 with s2: s1 := s1 /\ s2 */ + +inline void OSintersect(ordintset s1,ordintset s2) { + intlist *l1,*l2,**prev,*tmp; + +#ifdef DEBUG + printf("INTERSECT "); OSprint(s1); + printf("WITH "); OSprint(s2); +#endif + + l1 = s1->elements; + l2 = s2->elements; + + prev = &(s1->elements); + + while(l1 != NULL) { + while((l2 != NULL) && (l1->hd > l2->hd)) { /* Skip elements not in l1. */ + l2 = l2->tl; + } + + if((l2 != NULL) && (l1->hd == l2->hd)) { /* Retain element. */ + + prev = &(l1->tl); + l1 = l1->tl; + l2 = l2->tl; + + } else { /* Remove the first element of l1. */ + + tmp = l1; + *prev = l1->tl; + s1->nOfEls -= 1; + l1 = l1->tl; + OSfree(tmp); + + } + } + +#ifdef DEBUG + printf("TO GET "); OSprint(s1); + printf("\n"); +#endif +} + + +inline void OSaddelementsSTUPID(ordintset s1,ordintset s2) { + intlist *l1; + l1 = s1->elements; + while(l1 != NULL) { + OSinsert(l1->hd,s2); + l1 = l1->tl; + } +} + +inline void OSaddelements(ordintset s1,ordintset s2) { + intlist *l1,*l2,**prev,*tmp; + + // printf("ADD "); OSprint(s1); + // printf("TO "); OSprint(s2); + + l1 = s1->elements; + l2 = s2->elements; + + prev = &(s2->elements); + + while(l1 != NULL) { + + while(l2 != NULL && l1->hd > l2->hd) { /* Find location for element. */ + prev = &(l2->tl); + l2 = l2->tl; + } + + if(l2 == NULL || l1->hd < l2->hd) { + tmp = OScons(l1->hd,l2); + *prev = tmp; + prev = &(tmp->tl); + s2->nOfEls += 1; + } + l1 = l1->tl; + } + + // printf("TO GET "); OSprint(s2); + // printf("\n"); +} + +inline int OSmember(int v,ordintset s) { + intlist *l; + l = s->elements; + while(l != NULL) { + if(l->hd < v) { + l = l->tl; + } else { + if(l->hd == v) return 1; + return 0; + } + } + return 0; +} + +/* Iterator */ + +inline void OSstart(ordintset s,intlist **iterate) { + *iterate = s->elements; +} + +inline int OSnext(int *v,intlist **iterate) { + if(*iterate != NULL) { + *v = (*iterate)->hd; + *iterate = (*iterate)->tl; + return 1; + } else { + return 0; + } +} + + +inline void OSprint(ordintset s) { + intlist *l; + l = s->elements; + while(l != NULL) { + printf(" %i",l->hd); + l = l->tl; + } + printf("\n"); +} diff --git a/ordintsets.h b/ordintsets.h new file mode 100644 index 0000000..8db566b --- /dev/null +++ b/ordintsets.h @@ -0,0 +1,26 @@ + +/* 2010 (C) Jussi Rintanen */ + +typedef struct _ordintset { + int nOfEls; + intlist *elements; +} *ordintset; + +ordintset OScreate(); +ordintset OScreateSize(int); +int OScard(ordintset); +int OSemptyp(ordintset); +void OSmakeempty(); +void OSinsert(int,ordintset); +void OSremove(int,ordintset); +void OSremoveSet(ordintset,ordintset); +void OS2removeSet(ordintset,ordintset); +void OSaddelements(ordintset,ordintset); /* Add the elements of 1st to 2nd. */ +void OSintersect(ordintset,ordintset); +int OSmember(int,ordintset); +void OSreleasefree(); + +void OSstart(ordintset,intlist **); +int OSnext(int *,intlist **); + +void OSprint(ordintset); diff --git a/parser.y b/parser.y new file mode 100644 index 0000000..e843cc5 --- /dev/null +++ b/parser.y @@ -0,0 +1,211 @@ + + /* 2010 (C) Jussi Rintanen */ + +%{ + +#include "stdio.h" +#include "main.h" +#include "asyntax.h" + +#define YYERROR_VERBOSE + +void rparen(char *); + +int COST; + +%} + +%define parse.error verbose + +%union { + int i; + intlist *intlistp; + atomlist *atomlistp; + atom *atomp; + Sfma *Sfmap; + Sfmalist *Sfmalistp; + Seff *Seffp; + Sefflist *Sefflistp; + typedvarlist *typedvarlistp; +} + +/* all of the terminal grammar symbols (tokens recognized + by the lexical analyzer) */ + +%left RPAREN LPAREN DASH rwDEFINE rwACTION rwPARAMS rwEFFECT rwPRECOND rwPREDICATES rwREQUIREMENTS rwTYPES rwOBJECTS rwINIT rwGOAL rwDOMAIN rwTYPING rwAND rwOR rwWHEN rwNOT rwIMPLY rwFORALL rwPROBLEM EQUA rwEXISTS rwLENGTH rwCONSTANTS rwEITHER rwINCREASE rwMETRIC rwMINIMIZE + +%left ID VAR INT + +%term LPAREN RPAREN DASH EQUA rwAND rwOR rwNOT rwIMPLY rwPRECOND rwDEFINE rwDOMAIN rwPROBLEM rwPREDICATES rwFUNCTIONS rwREQUIREMENTS rwACTION rwPARAMS rwEFFECT rwOBJECTS rwTYPES rwWHEN rwFORALL rwEXISTS rwLENGTH rwGOAL rwINIT rwCONSTANTS + + +/* What nonterminals return? */ + +%type begin domain domaindefs domaindef actdef actdefs problem defs def typedvarlist typedatoms costexpr +%type atom +%type fma +%type fmas +%type effect +%type effects +%type idlist varlist varidlist +%type atomlist +%type varid +%type numexpr +%type opvars opvar opvarlist objectlist + +%start begin +%% + +begin : domain problem + ; + +idlist : ID idlist { $$ = intcons($1,$2); } + | { $$ = EMPTYLIST; } + ; + +costexpr : LPAREN EQUA numexpr numexpr RPAREN { } + ; + +atom : LPAREN ID varidlist { rparen("term"); } RPAREN { $$ = newatom($2,$3); } + ; + +atomlist : atomlist atom { $$ = atomcons($2,$1); } + | atomlist costexpr { $$ = $1; } + | { $$ = EMPTYLIST; } + ; + +varid : VAR { $$ = $1; } + | ID { $$ = $1; } + ; + +varidlist : varid varidlist { $$ = intcons($1,$2); } + | { $$ = EMPTYLIST; } + ; + + /* PDDL definitions start here. */ + +domain : LPAREN rwDEFINE LPAREN rwDOMAIN ID { rparen("domain"); } RPAREN domaindefs { rparen("domain body"); } RPAREN { storedomain($5); } + ; + +domaindefs : domaindefs domaindef + | { } + ; + +domaindef : LPAREN rwPREDICATES typedatoms { rparen(":predicates"); } RPAREN { storepredicates(); } + | LPAREN rwREQUIREMENTS idlist { rparen(":requirements"); } RPAREN { checkrequirements($3); } + | LPAREN rwCONSTANTS objectlist { rparen(":constants"); } RPAREN { storeconstants($3); } + | LPAREN rwFUNCTIONS functiondecls { rparen(":functions"); } RPAREN { } + | LPAREN rwTYPES objectlist { rparen(":types"); } RPAREN { storetypes($3); } + | LPAREN rwACTION { COST = 0; } ID actdefs { rparen(":action"); } RPAREN { addactioncost(COST); addnewaction($4); } + ; + +actdefs : actdef actdefs + | actdef + ; + +actdef : rwPARAMS LPAREN opvars { rparen(":action definitions"); } RPAREN { addactionparameters($3); } + | rwPRECOND fma { addactionprecond($2); } + | rwEFFECT effect { addactioneffect($2); } + ; + +opvars : varlist { $$ = withtype(UNIVTYPE,$1); } + | opvarlist { $$ = $1; } + | { $$ = EMPTYLIST; } + ; + +varlist : VAR varlist { $$ = intcons($1,$2); } + | VAR { $$ = intcons($1, EMPTYLIST); } + ; + +opvarlist : opvar opvarlist { $$ = TVappend($1,$2); } + | opvar { $$ = $1; } + ; + +opvar : varlist DASH ID { $$ = withtype($3,$1); } + ; + + +problem : LPAREN rwDEFINE LPAREN rwPROBLEM ID { rparen(":problem"); } RPAREN defs { rparen("problem definition"); } RPAREN { addproblem($5); } + ; + +defs : defs LPAREN def { rparen("problem definitions"); } RPAREN { } + | LPAREN def { rparen("problem definitions"); } RPAREN { } + ; + +def : rwDOMAIN ID { checkdomain($2); } + | rwOBJECTS objectlist { storeobjects($2); } + | rwINIT atomlist { storeinit($2); } + | rwGOAL fma { storegoal($2); } + | rwMETRIC rwMINIMIZE atomlist { } + ; + + +objectlist : idlist DASH ID objectlist { $$ = TVappend(withtype($3,$1),$4); } + | idlist { $$ = withtype(UNIVTYPE,$1); } + ; + +typedvarlist : VAR DASH ID typedvarlist { } + | VAR DASH LPAREN rwEITHER ID idlist { rparen("typed variable list"); } RPAREN typedvarlist { } + | VAR typedvarlist { } + | { } + ; + +typedatoms : typedatoms LPAREN ID typedvarlist { rparen("typed atom list"); } RPAREN { } + | { } + ; + +functiondecls : functiondecl functiondecls { } + | { } + ; + +functiondecl : tdecl DASH ID { } + | tdecl { } + ; + +tdecl : LPAREN ID typedvarlist { rparen("function list"); } RPAREN + ; + + + +fma : LPAREN rwAND { rparen("empty conjunction"); } RPAREN { $$ = Strue(); } + | LPAREN rwAND fmas { rparen("conjunction"); } RPAREN { $$ = Sconjunction($3); } + | LPAREN rwWHEN fma fma { rparen("when"); } RPAREN { $$ = Sconjunction(Sfmacons(Sneg($3),Sfmacons($4,EMPTYLIST))); } + | LPAREN rwOR fmas { rparen("disjunction"); } RPAREN { $$ = Sdisjunction($3); } + | LPAREN rwIMPLY fma fma { rparen("imply"); } RPAREN { $$ = Sdisjunction(Sfmacons(Sneg($3),Sfmacons($4,EMPTYLIST))); } + | LPAREN rwNOT fma { rparen("not"); } RPAREN { $$ = Sneg($3); } + | atom { $$ = Satom($1); } + | LPAREN EQUA varid varid { rparen("equality"); } RPAREN { $$ = SfmaEQ($3,$4); } + | LPAREN rwFORALL LPAREN opvars RPAREN fma { rparen("forall"); } RPAREN { $$ = Sfmaforall($4,$6); } + | LPAREN rwEXISTS LPAREN opvars RPAREN fma { rparen("exists"); } RPAREN { $$ = Sfmaforsome($4,$6); } + ; + +fmas : fmas fma { $$ = Sfmacons($2,$1); } + | fma { $$ = Sfmacons($1,EMPTYLIST); } + ; + +effects : effects effect { $$ = Seffcons($2,$1); } + | effect { $$ = Seffcons($1,EMPTYLIST); } + ; + +numexpr : atom { $$ = 0; } + | INT { $$ = $1; } + ; + +effect: LPAREN rwAND { rparen("empty conjunction"); } RPAREN { $$ = Seffconjunction(EMPTYLIST); } + | LPAREN rwAND effects { rparen("compound effect"); } RPAREN { $$ = Seffconjunction($3); } + | LPAREN rwWHEN fma effect { rparen("when"); } RPAREN { $$ = Seffwhen($3,$4); } + | LPAREN rwFORALL LPAREN opvars RPAREN effect { rparen("forall"); } RPAREN { $$ = Seffforall($4,$6); } + | atom { $$ = SPeffatom($1); } + | LPAREN rwNOT atom { rparen("not"); } RPAREN { $$ = SNeffatom($3); } + | LPAREN rwINCREASE atom numexpr { rparen("increase"); } RPAREN { $$ = Seffconjunction(NULL); COST = $4; } + ; + +%% + +void parseerror(char *s) { + errorstring = s; +} + +void rparen(char *s) { + errorstring = s; +} diff --git a/plan b/plan new file mode 100755 index 0000000..079209f --- /dev/null +++ b/plan @@ -0,0 +1 @@ +./nplan $1 $2 -o $3 -Q diff --git a/printplan.c b/printplan.c new file mode 100644 index 0000000..67796e7 --- /dev/null +++ b/printplan.c @@ -0,0 +1,291 @@ + +/* 2012 (C) Jussi Rintanen, jrintanen.jr@gmail.com */ + +#include +#include +#include + +#include "interface.h" +#include "main.h" +#include "asyntax.h" +#include "tables.h" +#include "ordintsets.h" +#include "operators.h" + +#define IPC 1 +#define FIELD 35 + +/* Print atoms true in a state. */ + +void printstate(satinstance sati,int *state) { + int i; + for(i=0;inOfSVars;i++) { + if(state[i]) { printf(" "); printatomi(i); } + } +} + +/* Print a tabular representation of the values of state variables and + operators at different time points. */ + +void printplanT(satinstance sati) { + int i,j,len; + for(j=0;jnOfTPoints;j++) printf("%i",j%10); + printf("\n"); + for(i=0;inOfTPoints;j++) { + switch(varvalue(sati,TVAR(i,j))) { + case 0: printf("."); break; + case 1: printf("T"); break; + default: printf(" "); break; + } + } + printf("\n"); + } + + for(i=0;inOfTPoints-1;j++) { + switch(varvalue(sati,TACT(i,j))) { + case 0: printf("."); break; + case 1: printf("T"); break; + default: printf(" "); break; + } + } + printf("\n"); + } +} + +/* Print a tabular representation of the values of state variables + at different time points. */ + +void printplanV(satinstance sati) { + int i,j,len; + for(j=0;jnOfTPoints;j++) printf("%i",j%10); + printf("\n"); + for(i=0;inOfTPoints;j++) { + switch(varvalue(sati,TVAR(i,j))) { + case 0: printf("."); break; + case 1: printf("T"); break; + default: printf(" "); break; + } + } + printf("\n"); + } +} + +/* Print the plan as a sequence of operators. + +(Test also that the plan actually is a solution to the planning problem.) + +*/ + +void copystate(satinstance sati,int *s1,int *s2) { + int i; + for(i=0;inOfSVars;i++) s2[i] = s1[i]; +} + +#define MAXSTEPSIZE 50000 + +void fprintplan(FILE *f,satinstance sati) { + int pactions[MAXSTEPSIZE]; + int sactions[MAXSTEPSIZE]; + int substepcnt; + int pcnt,toprint,round,naf,cnt; + int t,i,j,actionsinplan; + int state0[sati->nOfSVars],state1[sati->nOfSVars]; + int print_t; + int cost; +#ifdef IPC + int print_a; +#endif + + cost = 0; + actionsinplan = 0; + print_t = 0; +#ifdef IPC + print_a = 0; +#endif + + for(i=0;inOfSVars;i++) state0[i] = varvalue(sati,i); + + copystate(sati,state0,state1); + + for(t=0;tnOfTPoints-1;t++) { + + /* Get action indices to pactions. */ + + pcnt = 0; /* How many actions in the current time point. */ + +#ifdef DEBUG + fprintf(f,"Actions at STEP %i: ",t); +#endif + + for(i=0;i= MAXSTEPSIZE) { + fprintf(stderr,"ERROR: max. step size %i exceeded. Recompile with increased MAXSTEPSIZE.\n",MAXSTEPSIZE); + } +#ifdef DEBUG + fprintactionname(f,i); +#endif + actionsinplan += 1; + cost += actions[i].cost; + } + } + +#ifdef DEBUG + printf("\n"); +#endif + + toprint = pcnt; + round = 0; + + /* Find actions that don't affect any of the remaining actions. */ + + while(toprint) { + + copystate(sati,state0,state1); + + cnt = 0; + + substepcnt = 0; /* Number of actions currently in the substep */ + + for(i=0;i +#include +#include + +#include "asyntax.h" +#include "ordintsets.h" +#include "operators.h" + +#include "main.h" + +#include "scc.h" + +/**********************************************************************/ +/* Strong components of a graph */ +/**********************************************************************/ + +/* Compute strong components of the disabling graph. The arcs are not + constructed explicitly, as computing them is expensive and most arcs + would never be followed. + The starting node is node number 0. The set of all nodes is + {0,...,nOfNodes-1}. */ + +#define noDEBUG + +int *NNdfnumber; +int *NNstack; +unsigned char *NNinstack; +int *NNlowlink; + +int NNptr,NNdf; +int NNsingletons; + +int maxSCCsize; + +int nodecounter; + +#define min(a,b) (((a)<(b))?(a):(b)) + +#define likely(expr) (__builtin_expect((expr),1)) +#define unlikely(expr) (__builtin_expect((expr),0)) + +inline int getnext(int *el,eff **efs,int **e,int **as1,int **as2) { + + getfromas: + + if(**as1 != -1) { + *el = **as1; + (*as1)++; + return 1; + } + + if(**as2 != -1) { + *el = **as2; + (*as2)++; + return 1; + } + + getfrompene: + + if(**e != -1) { + if((**e)&1) { + *as1 = ApreconoccP[feVAR(**e)]; + } else { + *as1 = ApreconoccN[feVAR(**e)]; + } + *as2 = Acondocc[feVAR(**e)]; + *e = *e + 1; + goto getfromas; + } + + if(*efs != NULL) { + *e = (*efs)->effectlits; + *efs = (*efs)->tl; + goto getfrompene; + } + + return 0; +} + +sccs NNtraverse(int i,sccs ac) { + int j,current; + + eff *efs; + int *e; + int *as1,*as2; + int dummy; + int el; + + nodecounter = nodecounter + 1; + + if((10*nodecounter / nOfActions) != (10*(nodecounter-1) / nOfActions)) { + printf(" %i",(nodecounter * 10 / nOfActions)*10); fflush(stdout); + } + + NNdfnumber[i] = ++NNdf; + NNlowlink[i] = NNdf; + + NNstack[++NNptr] = i; + NNinstack[i] = 1; + + current = NNptr; + + efs = &(actions[i].effects); + + dummy = -1; + + e = &dummy; + + as1 = &dummy; + as2 = &dummy; + + /* Go through all neighbor CANDIDATES. */ + + while(getnext(&el,&efs,&e,&as1,&as2)) { + + if(NNdfnumber[el] == -1 && parallel(i,el)) { + ac = NNtraverse(el,ac); + NNlowlink[i] = min(NNlowlink[i],NNlowlink[el]); + } else { + if(NNinstack[el] == 1 && NNlowlink[i] > NNdfnumber[el] && parallel(i,el)) { + NNlowlink[i] = NNdfnumber[el]; + } + } + } + + if(NNlowlink[i] == NNdfnumber[i]) { /* Found an SCC */ + sccs oldac; + oldac = ac; + ac = (sccs)statmalloc(405,sizeof(struct _scc)); + ac->NofEls = NNptr-current+1; + ac->next = oldac; + ac->els = (int *)statmalloc(406,ac->NofEls * sizeof(int)); + + if(ac->NofEls > maxSCCsize) maxSCCsize = ac->NofEls; + + if(NNptr == current) NNsingletons += 1; + + for(j=current;j<=NNptr;j++) ac->els[j-current] = NNstack[j]; + + if(flagShowInput) { + printf("new SCC %i:",ac->NofEls); + for(j=current;j<=NNptr;j++) printactionname(NNstack[j]); // printf(" %i",NNstack[j]); + printf("\n"); + } else { + if(debugOutput > 0 && NNptr != current) printf(" %i",NNptr-current+1); + } + + for(j=current;j<=NNptr;j++) NNinstack[NNstack[j]] = 0; + NNptr = current-1; + } + return ac; +} + +int scc(int nOfNodes) { + int i; + sccs ac; + + nodecounter = 0; + + NNdf = -1; + NNptr = -1; + + if(debugOutput > 0) printf("Finding SCCs for %i nodes.\n",nOfNodes); + + NNdfnumber = (int *)statmalloc(407,nOfNodes * sizeof(int)); + NNstack = (int *)statmalloc(408,nOfNodes * sizeof(int)); + NNinstack = (unsigned char *)statmalloc(409,nOfNodes * sizeof(unsigned char)); + NNlowlink = (int *)statmalloc(410,nOfNodes * sizeof(int)); + + NNsingletons = 0; + + maxSCCsize = 0; + + for(i=0;i 0) printf(", %i singleton components\n",NNsingletons); + + SCCS = ac; + + free(NNdfnumber); + free(NNstack); + free(NNinstack); + free(NNlowlink); + + return maxSCCsize; +} diff --git a/scc.h b/scc.h new file mode 100644 index 0000000..a4b267d --- /dev/null +++ b/scc.h @@ -0,0 +1,12 @@ + +/* 2010 (C) Jussi Rintanen */ + +typedef struct _scc { + int NofEls; + int *els; + struct _scc *next; +} *sccs; + +int scc(int); + +sccs SCCS; diff --git a/shortcuts.c b/shortcuts.c new file mode 100644 index 0000000..98e688a --- /dev/null +++ b/shortcuts.c @@ -0,0 +1,123 @@ + +/* 2012 (C) Jussi Rintanen, jrintanen.jr@gmail.com */ + +/* For every literal l1, identify unit-propagation consequences l2 for which + the derivation involve non-binary clauses. These consequences l1 !-UP l2 + are useful for two reasons. + 1. It is not necessarily the case that -l2 !-UP -l1, and hence with + the new clause -l1 V l2 we get l2 !-UP l1 as a new consequence. + 2. The clause learning algorithm avoids the use of a potentially long + non-binary clauses, sometimes leading to much shorter learned clauses + and much faster learning and unit propagation. +*/ + +#define noHARDDEBUG +#define noSHOWIT + +void shortcutprobe(satinstance sati,int l) { + int i,l2; + PTRINT reason; + +#ifdef HARDDEBUG + printf("--------------------------------------------------------------\n"); +#endif + + for(i=0;inOfVars;i++) { + int flag; + flag=0; + if(!varunsetp(sati,i)) { + printf("INCORRECTLY ALREADY SET: %i",i); printTlit(sati,PLIT(i)); + flag = 1; + } + assert(flag==0); + } + + setUPstacktop(sati,-1); /* Drop the input unit clauses from the stack. */ + sati->dlevel = 0; + + sati->declevels[0] = 0; + +#ifdef HARDDEBUG + printf("Trying "); + printTlit(sati,l); + printf("\n"); +#endif + + simpleaddtoqueue(sati,l,REASON_DECISION,0); + + if(propagate(sati)) { + // Literal cannot be true. +#ifdef SHOWIT + printf("CONTRADICTION WITH "); + printTlit(sati,l); + printf("\n"); +#endif + undo_assignments_until_level_NOHEAP(sati,0); + return; + } + + // printf("PROPAGATED\n"); + + for(i=1;iendunitstack;i++) { // Go through inferred literals. + + l2 = sati->unitstack[i]; + + reason = LITREASON(l2); + +#ifdef HARDDEBUG + printf("Checking %i:",i); printTlit(sati,l2); + printf(" REASON: "); + if(reason == REASON_INPUT) printf("INPUT"); + else if(reason == REASON_DECISION) printf("DECISION"); + else if((reason&1)==0) printf(" LONG CLAUSE"); + else printTlit(sati,reason >> 1); + + printf("\n"); +#endif + + if((reason & 3) == 0 && clauselen((int *)reason) > 3) { // Reason is a long clause? + // Store the new binary literal for later use. + if(nofshortcutclauses+1 >= maxshortcutclauses) { + maxshortcutclauses = maxshortcutclauses * 2; + shortcutclauses = (shortcutclause *)realloc(shortcutclauses, + maxshortcutclauses * sizeof(shortcutclause)); + } + + shortcutclauses[nofshortcutclauses].l1 = NEG(l) % (2 * sati->nOfVarsPerTime); + shortcutclauses[nofshortcutclauses].l2 = l2 % (2 * sati->nOfVarsPerTime); + shortcutclauses[nofshortcutclauses++].tdiff = tvartime(sati,VAR(l2))-tvartime(sati,VAR(l)); + +#ifdef SHOWIT + printf("INFER CLAUSE: "); + printTlit(sati,shortcutclauses[nofshortcutclauses-1].l1); + printf(" V "); + printlit(shortcutclauses[nofshortcutclauses-1].l2); + printf("@%i (through length %i)\n",shortcutclauses[nofshortcutclauses-1].tdiff,clauselen((int *)reason)); +#endif + } + + } + undo_assignments_until_level_NOHEAP(sati,0); + + for(i=0;inOfVars;i++) + if(!varunsetp(sati,i)) { + printf("INCORRECTLY REMAINS SET: %i",i); printTlit(sati,PLIT(i)); + assert(1==0); + } +} + +void shortcuts(satinstance sati) { + int p; + + maxshortcutclauses = 100000; + nofshortcutclauses = 0; + shortcutclauses = (shortcutclause *)malloc(maxshortcutclauses * sizeof(shortcutclause)); + + for(p=0;pnOfSVars;p++) { + shortcutprobe(sati,PLIT(varwithtime(sati,p,flagShortCutHorizon))); + shortcutprobe(sati,NLIT(varwithtime(sati,p,flagShortCutHorizon))); + } +#ifdef SHOWIT + printf("INFERRED %i SHORTCUT CLAUSES.\n",nofshortcutclauses); +#endif +} diff --git a/tables.c b/tables.c new file mode 100644 index 0000000..893f776 --- /dev/null +++ b/tables.c @@ -0,0 +1,296 @@ + +/* 2012 (C) Jussi Rintanen */ + +/* Symboltable for IDs and VARs in lexer */ + +#include "asyntax.h" +#include "tables.h" +#include "main.h" + +#include +#include +#include +#include + +#define noASSERTS + +int maxSymbols; +int nOfSymbols; + +void initsymboltable() { + int i; + + maxSymbols = 50000; + nOfSymbols = 0; + for(i=0;inext != NULL && strcmp(s,ste->s) != 0) ste = ste->next; + + /* Found one that matches: return its index. */ + + if(strcmp(s,ste->s) == 0) return ste->index; + + /* New symbol. */ + + ns = (char *)statmalloc(51,strlen(s)+1); /* Make a new copy of the string */ + strcpy(ns,s); + + if(ste->index == -1) { + ste->s = ns; + ste->index = nOfSymbols++; + ste->staticpredicate = 1; + } else { + // printf("Hash collision\n"); + // printf("[%i/%i]\n",tmp,nOfSymbols); + ste->next = (stentry *)statmalloc(52,sizeof(stentry)); + ste->next->s = ns; + ste->next->index = nOfSymbols++; + ste->next->staticpredicate = 1; + ste->next->next = NULL; + ste = ste->next; + } + + // printf("New entry %i with has %i is %s\n",nOfSymbols-1,symbolhash(s),ns); + + if(nOfSymbols >= maxSymbols) { + maxSymbols = maxSymbols * 2; + index2stentry = (stentry **)realloc(index2stentry,maxSymbols * sizeof(stentry *)); + } + + index2stentry[nOfSymbols-1] = ste; + + return ste->index; + +} + +char *symbol(int i) { + switch(i) { + case -1: return "PARAM-0"; + case -2: return "PARAM-1"; + case -3: return "PARAM-2"; + case -4: return "PARAM-3"; + case -5: return "PARAM-4"; + case -6: return "PARAM-5"; + case -7: return "PARAM-6"; + case -8: return "PARAM-7"; + case -9: return "PARAM-8"; + case -10: return "PARAM-9"; + default: + if(i<0) return "PARAMn"; + else { + // printf("entry %i is %s\n",i,index2stentry[i]->s); + return index2stentry[i]->s; + } + } +} + +void setnonstatic(int i) { + index2stentry[i]->staticpredicate = 0; +} + +int isvar(int i) { + char *s; + s = index2stentry[i]->s; + return (*s == '?'); +} + +/* Symboltable for p(o1,...,on) atoms. */ + +#define ATABLESIZE 0x10000 +#define MAXARITY 100 + +typedef struct _atomhashelement{ /* Mapping from atoms to indices */ + int index; + intlist *a; + struct _atomhashelement *tl; +} atomhashelement; + +atomhashelement *atomhash[ATABLESIZE]; /* Mapping from atoms to indices */ + +intlist **atomtable; /* Mapping from indices to atoms (lists of strings) */ +int maxAtoms; + +void initatomtable() { + int i; + + nOfAtoms = 0; + maxAtoms = 50000; + + atomtable = (intlist **)statmalloc(53,sizeof(intlist *) * maxAtoms); + + for(i=0;iv != i) { +// p = p->tl; +// j += 1; +// assert(p != NULL); +// } +// return j; +//} + +/* silly auxiliary function */ + +int sameatom(int *i,intlist *j) { + while(j != NULL) { + if(*i != j->hd) return 0; + i+=1; + j = j->tl; + } + return 1; +} + +int bvalue(int i,int *b) { + if(i<0) { + return b[-1-i]; + } else { + return i; /* If not variable, it is already an object. */ + } +} + +/* Fetch the index of an atom from the hash table, or create new. */ + +int atomindex(atom a,int *b) { + atomhashelement *l,*ol; + int hash,n,i,j; + int syms[MAXARITY+1]; /* vector of symbols in the atom */ + + /* Compute a hash number for the atom */ + syms[0] = a[0]; + hash = a[0]; + j=1; + for(i=2;i<2+a[1];i++) { + /* Fetch from the current assignment */ + n = bvalue(a[i],b); + hash = (hash << 5)^n; +#ifdef ASSERTS + assert(j < MAXARITY); +#endif + syms[j] = n; + j += 1; + } + + hash = hash & (ATABLESIZE-1); + + l = atomhash[hash]; + + ol = NULL; + + while(l != NULL) { + /* printf("%i %i %i*\n",hash,(int)(l->tl),(int)(l->a)); */ + if(sameatom(syms,l->a)) return l->index; + ol = l; + l = l->tl; + } + + /* Was not in the list, create new. */ + + l = (atomhashelement *)statmalloc(54,sizeof(atomhashelement)); + + if(ol == NULL) { + atomhash[hash] = l; + } else { + ol->tl = l; + } + + l->index = nOfAtoms; + l->a = NULL; + l->tl = NULL; + + for(i=j-1;i>=0;i--) { + l->a = intcons(syms[i],l->a); + /* if(l->a == 1 && l->tl == 1) { printf("BINGO!!!\n"); exit(1); } */ + } + + nOfAtoms += 1; + + if(nOfAtoms >= maxAtoms) { + maxAtoms = maxAtoms * 3 / 2; + atomtable = (intlist **)realloc(atomtable,maxAtoms * sizeof(intlist *)); + } + + atomtable[nOfAtoms-1] = l->a; + +#ifdef DEBUG + printf("CREATED ATOM %i:",l->index); printatomi(l->index); printf("\n"); +#endif + + return l->index; + +} + +int printatomi(int i) { + int len; + intlist *a = atomtable[i]; + + assert(i >= 0); + assert(i < nOfAtoms); + + if(a == NULL) { + fprintf(stderr,"INTERNAL ERROR: symbol table 1244\n"); + assert(1==0); + } + printf("%s(",symbol(a->hd)); + len = 1+strlen(symbol(a->hd)); + a = a->tl; + while(a != NULL) { +#ifdef ASSERTS + assert(a->hd >= 0); +#endif + printf("%s",symbol(a->hd)); + len += strlen(symbol(a->hd)); + if(a->tl != NULL) { printf(","); len += 1; } + a = a->tl; + } + printf(")"); len += 1; + return len; +} + +void renameatomtable(int nOfAtoms,int *mapping) { + int i; + for(i=0;i +#include +#include + +#include "main.h" +#include "asyntax.h" +#include "tables.h" +#include "intsets.h" +#include "ordintsets.h" +#include "operators.h" +#include "dimacs.h" +#include "invariants.h" +#include "scc.h" + +#include "interface.h" +#include "clausedb.h" + +#include "translate2sat.h" + +#ifdef CP3 +# #include "libcp3c.h" +#endif + +#define noDEBUG + +#define OPtag 0x10000000 +#define VARtag 0x20000000 +#define AUXtag 0x30000000 +#define NEGtag 0x40000000 +#define NEXTtag 0x80000000 +#define TYPEtag 0x30000000 +#define INDEX 0x0FFFFFFF + +/* Tags for op, var, aux encoding */ + +#define OP(n) ((n)|OPtag) +#define SVAR(n) ((n)|VARtag) +#define AUX(n) ((n)|AUXtag) +#define NEXT(n) ((n)|NEXTtag) + +#define fmaOP(n) (Fatom(OP(n))) +#define fmaVAR(n) (Fatom(SVAR(n))) +#define fmaAUX(n) (Fatom(AUX(n))) + +#define VARINDEX(v) ((v)&INDEX) +#define VARNEXT(v) ((v)&NEXTtag) +#define VARTYPE(v) ((v)&TYPEtag) + +/* Tags for DIMACs clause encoding */ + +#define INITtag 0x20000000 +#define GOALtag 0x40000000 +#define TRtag 0x60000000 +#define TIMEtags 0x60000000 +#define LENBITS 0x0FFFFFFF + +void outputDIMACS(); +satinstance outputNSAT(int,int,int); + + +int nOfAux; +int nOfClauses; +int nOfTClauses; + +int allocAUX(int n) { + int temp; + temp = nOfAux; + nOfAux += n; + return temp; +} + +/* Functions for handling formula sets and translating them into CNF. */ + +typedef enum { inittime, goaltime, transition } formulaclass; + +typedef struct { + formulaclass cl; + fma *f; +} timedfma; + +int nOfFmas; +int maxFmas; + +timedfma *fmas; + +void initformuladb() { + nOfAux = 0; + nOfFmas = 0; + maxFmas = 500000; + fmas = (timedfma *)statmalloc(500,maxFmas * sizeof(timedfma)); +} + +void addformula(formulaclass c,fma *f) { + nOfFmas += 1; + + /* Table size exceeded */ + if(nOfFmas > maxFmas) { + maxFmas += 1000000; + fmas = (timedfma *)realloc(fmas,maxFmas * sizeof(timedfma)); + } + + fmas[nOfFmas-1].cl = c; + fmas[nOfFmas-1].f = f; + + // printFfma(f); +} + +/* Make a copy of a formula with each state variable tagged with + the StateVar tag (to distinguish it from the action and auxiliary variables. +*/ + +fma *makeVARfma(fma *f) { + fmalist *l; + fma *nf; + nf = (fma *)statmalloc(501,sizeof(fma)); + nf->t = f->t; + switch(f->t) { + case patom: + case natom: + nf->a = SVAR(f->a); break; + case disj: + case conj: + nf->juncts = NULL; + l = f->juncts; + while(l != NULL) { + nf->juncts = fmacons(makeVARfma(l->hd),nf->juncts); + l = l->tl; + } + break; + default: 1; + } + return nf; +} + +/* Make a copy of a formula with the NEXT version of each state variable. */ + +fma *fmaNEXT(fma *f) { + fmalist *l; + switch(f->t) { + case patom: + case natom: + f->a = NEXT(f->a); break; + case disj: + case conj: + l = f->juncts; + while(l != NULL) { + fmaNEXT(l->hd); + l = l->tl; + } + break; + default: 1; + } + return f; +} + + +/* How many bits are needed for expressing numbers from 1 to n? */ + +int bitsneeded(int n) { + int cnt; + cnt = 0; + while(n > 0) { + n = n >> 1; + cnt += 1; + } + return cnt; +} + +/* Return a conjunction of literals, with the positives in the first list + and the negatives in the second. */ + +//fma *effectsof(intlist *pos,intlist *neg) { +// fmalist *fs; +// +// fs = NULL; +// +// while(pos != NULL) { +// fs = fmacons(fmaVAR(NEXT(pos->hd)),fs); +// pos = pos->tl; +// } +// +// while(neg != NULL) { +// fs = fmacons(Fneg(fmaVAR(NEXT(neg->hd))),fs); +// neg = neg->tl; +// } +// return Fconj(fs); +//} + +fma *effectsofL(int *lits) { + fmalist *fs; + + fs = NULL; + + while(*lits != -1) { + if((*lits)&1) fs = fmacons(Fneg(fmaVAR(NEXT(feVAR(*lits)))),fs); + else fs = fmacons(fmaVAR(NEXT(feVAR(*lits))),fs); + lits = lits + 1; + } + + return Fconj(fs); +} + +/* Add a new action/effect to the data structure that enumerates for + each literal all the possible ways of making it true. */ + +void storeinCEsL(int *lits,int var,fma *precon) { + CEstruct *s; + int i; + for(;*lits != -1;lits = lits + 1) { + s = (CEstruct *)statmalloc(503,sizeof(CEstruct)); +#ifdef ASSERTS + assert(s != NULL); +#endif + i = *lits; + s->next = CEs[i]; + s->var = var; + s->condition = precon; + s->disjunctive = disjunctivep(precon); + CEs[i] = s; + } +} + +/* Count the number of ways a literal can be made true. */ + +int nOfCEs(CEstruct *ptr) { + int n; + n = 0; + while(ptr != NULL) { + n = n + 1; + ptr = ptr->next; + } + return n; +} + +/* Create a compact data structure with references to effect variables + and the associated (pre)conditions. This is used when the flagCEvariables + is true, and it is used for the computation of the heuristic. +*/ + +void compactCEs() { + int i,j; + int len; + CEstruct *ptr; + for(i=0;ivar); + cCEs[i][j].disjunctive = ptr->disjunctive; + cCEs[i][j].condition = ptr->condition; + ptr = ptr->next; + } + // printf("\n"); + cCEs[i][len].var = -1; + } +} + +/* Test whether action or conditional effect represented by variable v1 +can disable or affect the one represented by v2. +We dont' want to tabulate all pairs, as their number grows quadratically. +Instead, we tabulate the precondition literals and the possible effects +of each variable, and test whether the sets intersect. */ + +int actaffects(int v1,int v2) { + int *i,*j; + + i = actvars[v1].effectlits; + assert(i); + while(*i != -1) { + j = actvars[v2].conditionlits; + assert(j); + while(*j != -1) { + if(*j == NEG(*i)) return 1; + j = j + 1; + } + i = i + 1; + } + return 0; +} + +int countlits(fma *f) { + int cnt; + fmalist *fs; + + switch(f->t) { + case conj: + case disj: + cnt = 0; + fs = f->juncts; + while(fs != NULL) { + cnt = cnt + countlits(fs->hd); + fs = fs->tl; + } + return cnt; + case patom: + case natom: + return 1; + default: + return 0; + } + +} + +int *storelits(fma *f,int *ptr) { + fmalist *fs; + + switch(f->t) { + case conj: + case disj: + fs = f->juncts; + while(fs != NULL) { + ptr = storelits(fs->hd,ptr); + fs = fs->tl; + } + return ptr; + case patom: + *(ptr++) = PLIT(f->a); + return ptr; + case natom: + *(ptr++) = NLIT(f->a); + return ptr; + default: + return ptr; + } + +} + +void storeactvars(int var,int *effectlits,fma *preconlits) { + int len,*ptr; + + if(var >= maxactvars) { + int oldmax,i; + + oldmax = maxactvars; + maxactvars = var + 100000; + + actvars = (actvar *)realloc(actvars,sizeof(actvar) * maxactvars); + + for(i=oldmax;ieffectlits); + addformula(transition,Fimpl(fmaOP(i),Fimpl(makeVARfma(e->condition),ef))); + + cond = Fconj2(e->condition,actions[i].precon); + storeactvars(i+nOfAtoms,e->effectlits,cond); + e = e->tl; + } + + } else { /* Do the translation with variables for conditional effects. */ + + while(e != NULL) { + ef = effectsofL(e->effectlits); + if(e->condition->t == TRUE) { /* The condition is always true. */ + addformula(transition,Fimpl(fmaOP(i),ef)); + /* Store + - the action variable, to be used by the heuristic AND + - the associated precondition + */ + storeinCEsL(e->effectlits,OP(i),actions[i].precon); + storeactvars(i+nOfAtoms,e->effectlits,actions[i].precon); + } else { + fma *cond; + aux = allocAUX(1); + addformula(transition,Fimpl(fmaOP(i),Fimpl(makeVARfma(e->condition),fmaAUX(aux)))); + addformula(transition,Fimpl(fmaAUX(aux),ef)); + addformula(transition,Fimpl(fmaAUX(aux),makeVARfma(e->condition))); + addformula(transition,Fimpl(fmaAUX(aux),fmaOP(i))); + /* Store + - the auxiliary variable, to be used by the heuristic AND + - the associated condition and precondition + */ + cond = Fconj2(e->condition,actions[i].precon); + storeinCEsL(e->effectlits,AUX(aux),cond); + storeactvars(aux+nOfActions+nOfAtoms,e->effectlits,cond); + } + e = e->tl; + } + + } +} + +/* Print encoding */ + +void printvar(int v) { + if(v & NEGtag) printf("-"); + if(VARNEXT(v)) printf("*"); + switch(VARTYPE(v)) { + case AUXtag: printf("AUX%i",VARINDEX(v)); break; + case VARtag: printatomi(VARINDEX(v)); break; + case OPtag: printf("OP%i",VARINDEX(v)); break; + default: printf("(INCORRECT VAR TYPE %i",v); break; + } +} + +void printFfmalist(fmalist *,char *); +void printFfma(fma *f) { + switch(f->t) { + case patom: printvar(f->a); break; + case natom: printf("-"); printvar(f->a); break; + case conj: + printf("("); + printFfmalist(f->juncts,"&"); + printf(")"); + break; + case disj: + printf("("); + printFfmalist(f->juncts,"|"); + printf(")"); + break; + case TRUE: printf("TRUE"); break; + case FALSE: printf("FALSE"); break; + } +} + +void printFfmalist(fmalist *l,char *sep) { + if(l == NULL) return; + printFfma(l->hd); + if(l->tl != NULL) printf("%s",sep); + printFfmalist(l->tl,sep); +} + +/* Construct formula expressing conditions when var becomes + true or false in terms of an applied operator + additional conditions. */ + +int iamember(int n,int *l) { + while(*l != -1) { + if(*l == n) return 1; + l = l + 1; + } + return 0; +} + +fma *makes(int val,int var) { + int i; + fmalist *fs0,*fs; + eff *e; + int *ptr; + + fs = NULL; + + if(val == 1) ptr = AeffectoccP[var]; + else ptr = AeffectoccN[var]; + + while(*ptr != -1) { + +#ifdef ASSERTS + assert(*ptr >= 0); +#endif + + fs0 = NULL; /* Disjuncts of the condition for one operator */ + + e = &(actions[*ptr].effects); + + while(e != NULL) { + int *l; + + l = e->effectlits; + + // if((val && iamember(fePLIT(var),l)) || (!val && iamember(feNLIT(var),l))) { + if(iamember((val ? fePLIT(var) : feNLIT(var)),l)) { + if(e->condition->t == TRUE) { /* Becomes true unconditionally */ + fs = fmacons(fmaOP(*ptr),fs); + goto nextop; + } + fs0 = fmacons(makeVARfma(e->condition),fs0); /* Add one disjunct. */ + } + + e = e->tl; + } + + fs = fmacons(Fconj2(fmaOP(i),Fdisj(fs0)),fs); + + nextop: 1; + + ptr = ptr + 1; + + } + + return Fdisj(fs); + +} + +/**********************************************************************/ +/* */ +/**********************************************************************/ + +/* Computation of clauses that restrict the parallel execution of +operators for three forms of plans. +- sequential plans with (at most) one action per time point +- parallel plans with A-step semantics [Rintanen et al. 2006] +- parallel plans with E-step semantics [Rintanen et al. 2006] +*/ + +void SEQUmutexes() { + int i,j,bit; + int indexbits; + int firstindexbit; + /* Each action sets its index in log2 nOfActions auxiliary variables. */ + + /* Allocate auxiliary variables for index bits */ + indexbits = bitsneeded(nOfActions); + firstindexbit = allocAUX(indexbits); + + for(i=0;i -o' for every pair + o and o' such that + o < o' and o may affect o' + Effects are (may be) consistent. + Preconditions are (may be) consistent. + */ + +#define MAXNM 10000 +int auxM[MAXNM]; +int auxR[MAXNM]; + +int intCmp(int *a,int *b) { + if(*a > *b) return 1; + else return 0; +} + +/* Optimization to the chain encoding: + if few operators are included, generate binary mutexes. */ + +void ESTEPprod(int NM, int NR) { + int i,j,op1,op2; + for(i=0;i=0;j--) { + if(canmaketrue(j,i)) auxM[NM++] = j; + if(isaffectedby(j,i) && Lparallel(i,j)) auxR[NR++] = j; + } + break; + case 0: + for(j=0;jNofEls;j++) { + if(canmaketrue(s->els[j],i)) auxM[NM++] = s->els[j]; + if(isaffectedby(s->els[j],i) && Lparallel(i,s->els[j])) auxR[NR++] = s->els[j]; + } + + /* Both auxR and auxM are sorted to ascending order. */ + + qsort(auxR,NR,sizeof(int),intCmp); + qsort(auxM,NM,sizeof(int),intCmp); + break; + } + +#ifdef ASSERTS + assert(NM < MAXNM); + assert(NR < MAXNM); +#endif + + /* WARNING: The code that follows assumes that auxR and auxM are sorted + in an ascending order. ASTEPmutexes tries to use this in descending + order, and therefore produces non-A-step plans. */ + + if(NM == 0 || NR == 0) return; /* Nothing to do */ + + if(NM == 1 && NR == 1 && auxR[0] == auxM[0]) return; /* Nothing to do */ + + if(NM*NR <= (NM+NR)*3) { ESTEPprod(NM,NR); return; } + + if(NM*NR < 5000 && noparallels(NM,NR)) return; + + // printf("%i modify and %i require ",NM,NR); + // if(i&i) { printf("-"); printatomi(i >> 1); } + // else printatomi(i >> 1); + // printf("\n"); + +#ifdef DEBUG + printf("PARALLELISM AXIOMS %i %i for ",NM,NR); + printlit(i); printf("\n"); + + for(j=0;j= op1) return; + if(!parallel(op1,op2)) return; + for(i=0;it) { + + case conj: + case disj: + fs = f->juncts; + while(fs != NULL) { + ASTEPprecond(op,fs->hd,polarity); + fs = fs->tl; + } + break; + + case patom: + case natom: + + if(polarity == 0 || f->t == patom) { + ptr = AeffectoccN[f->a]; + while(*ptr != -1) { + ASTEPmutexCANDIDATE(op,*ptr); + ptr = ptr + 1; + } + } + + if(polarity == 0 || f->t == natom) { + ptr = AeffectoccP[f->a]; + while(*ptr != -1) { + ASTEPmutexCANDIDATE(op,*ptr); + ptr = ptr + 1; + } + } + + break; + + default: break; + + } +} + +void ASTEPmutexes() { + int i,j,op; + eff *es; + int *ptr,*ptr2; + + for(i=0;ieffectlits; + while(*ptr != -1) { + + if((*ptr)&1) ptr2 = ApreconoccP[feVAR(*ptr)]; + else ptr2 = ApreconoccN[feVAR(*ptr)]; + + while(*ptr2 != -1) { + ASTEPmutexCANDIDATE(i,*ptr2); + ptr2 = ptr2 + 1; + } + ptr2 = Acondocc[feVAR(*ptr)]; + while(*ptr2 != -1) { + ASTEPmutexCANDIDATE(i,*ptr2); + ptr2 = ptr2 + 1; + } + ptr = ptr + 1; + } + + ASTEPprecond(i,es->condition,1); + es = es->tl; + } + + /* Go through preconditions. */ + ASTEPprecond(i,actions[i].precon,0); + /* Emit parallelism constraints. */ + for(j=0;jNofEls == 1) goto NEXTSCC; + + if(s->NofEls == 2) { + addformula(transition,Fimpl(fmaOP(s->els[0]),Fneg(fmaOP(s->els[1])))); + goto NEXTSCC; + } + + /* Big SCCs are handled through linearization. */ + + if(s->NofEls > nOfActions / 3) { + // if(s->NofEls > 2) { +#ifdef DEBUG + printf("SCC of size %i\n",s->NofEls); +#endif + + for(i=0;i<2*nOfAtoms;i++) { /* Go through all literals */ + ESTEPchain(i,s,0); + } + + } else { /* Or slightly more cleverly. */ + + // printf("Doing SCC number N of size %i.\n",s->NofEls); + + for(i=0;iNofEls;i++) collectliterals(temp,s->els[i]); + + // printf("OUTPUTTING axioms: "); fflush(stdout); + + OSstart(temp,&iterate); + while(OSnext(&i,&iterate)) { + // printf("%i:",i); fflush(stdout); + // printatomi(i); + ESTEPchain(i,s,0); + } + + // printf("\n"); + + OSmakeempty(temp); + + } + NEXTSCC: + + s = s->next; + } +} + +int varsPerTime; + +/* Test whether l1 implies l2 directly or through invariants. */ + +int redundant(int l1,int l2) { + // printlit(l1); printf(" -> "); printlit(l2); + if(l1 == l2 || ISmember(l2,twolits[NEG(l1)])) { + // printf(" IS REDUNDANT\n"); + return 1; + } + // printf(" IS NOT\n"); + return 0; +} + +void printlit(int l) { + if(VALUE(l) == 0) printf("-"); + printatomi(VAR(l)); +} + +fma *fslit(int succ,int l) { + int v; + if(succ) v = NEXT(VAR(l)); else v = VAR(l); + if(VALUE(l)) return fmaVAR(v); else return Fneg(fmaVAR(v)); +} + + +#define SKIPFRAMECLAUSES +#ifdef SKIPFRAMECLAUSES + +/* Avoid using a a frame action (x@t & -x@t+1) -> a1 V ... V an + when all of a1,...,an are falsified by fact f, i.e. f != -a1&...&-an. + These frame axioms, with large n, lead to huge learned clauses. + We add the clause x@t & -x@t+1 -> -f. */ + +void skipframeclauses() { + +} +#endif + +void runalgorithmA(int,int); +void runalgorithmB(double,int); + +/**********************************************************************/ +/* Encoding a planning problem as a set of propositional formulae */ +/**********************************************************************/ + +int clauseptr,maxClauseEls; +int *clauseset; + +fma *osubstitute(fma *f,int *a) { + fma *new; + fmalist *l; + + switch(f->t) { + + case patom: return Fatom(a[f->a]); + case natom: return Fnatom(a[f->a]); + + case conj: + case disj: + new = (fma *)statmalloc(504,sizeof(struct _fma)); + + new->t = f->t; + + l = f->juncts; + new->juncts = NULL; + + while(l != NULL) { + new->juncts = fmacons(osubstitute(l->hd,a),new->juncts); + l = l->tl; + } + + return new; + + default: + return f; + } +} + +void encodingOgata() { + int i,j; + + int tempVars[nOfAtoms]; + int tempVarsNEW[nOfAtoms]; + int lastAffecting[nOfAtoms]; + int evars[nOfAtoms],evarcnt; + fma *epos[nOfAtoms]; + fma *eneg[nOfAtoms]; + + int *ls; + + /* The encoding in Ogata, Tsuchiya & Kikuno, "SAT-based verification + of safe Petri nets", ATVA 2004, LNCS 3299, 79-92, Springer 2004. + */ + + /* + Initialize an array A that shows which variable represents a given + state variable x. Initialize A[x] to x@t. + + Go through all actions sequentially. + + For the precondition have o@t -> phi[x] for precondition phi where + each x has been replaced by A[x]. + + For effects + IF phi1 THEN x := 1 + and + IF phi0 THEN x := 0 + we introduce new auxiliary variables aux (unless the action is + the last one affecting x, in which case we define aux = x@t+1.) + + The definition of aux is aux <-> (A[x] & -phi0) V phi1, where + variable y in phi0 and phi1 have been replaced by A[y]. + + Assign A[x] := aux. + + */ + + /* Initialize state variable array. */ + + for(i=0;i lastAffecting[i]) { + lastAffecting[i] = *ptr; + } + ptr++; + } + + ptr = AeffectoccN[i]; + + while(*ptr != -1) { + if(*ptr > lastAffecting[i]) { + lastAffecting[i] = *ptr; + } + ptr++; + } + + // printf("Last affecting %i is %i.\n",i,lastAffecting[i]); + } + + /* Go through all actions. */ + + for(i=0;ieffectlits; + + while(*ls != -1) { + + // printf("Positive effect "); printatomi(ls->hd); printf("\n"); + + j = 0; + while(j < evarcnt && evars[j] != *ls) { + j = j+1; + } + + if(j == evarcnt) { + + if((*ls)&1) { + eneg[j] = e->condition; + epos[j] = Ffalse(); + } else { + epos[j] = e->condition; + eneg[j] = Ffalse(); + } + + evars[j] = *ls; + + evarcnt += 1; + + } else { + + if((*ls)&1) { + eneg[j] = Fdisj2(eneg[j],e->condition); + } else { + epos[j] = Fdisj2(epos[j],e->condition); + } + } + + ls = ls + 1; + } + + e = e->tl; + } + + /* Create an equivalence tempVar[a]NEW <-> (OPi & epos[a]) V (tempvar[a] & -(OPi & eneg[a])) + for every effect a of the action. */ + + for(j=0;jnext) { +// fs = fmacons(Fatom(s->var),fs); +// } +// if(fs == NULL) return Ftrue(); +// else return Fconj(fs); +//} + +fma *disjofCEs(int i) { + ptrlist *fs; + CEstruct *s; + fs = NULL; + for(s=CEs[i];s!=NULL;s=s->next) { + fs = fmacons(Fatom(s->var),fs); + } + if(fs == NULL) return Ffalse(); + else return Fdisj(fs); +} + +void addshortcuts() { + satinstance tmp = outputNSAT(0,flagShortCutHorizon*2+1,1); + shortcuts(tmp); +} + + +/***************************************************************************/ +/* Management of the temporary clauseset. */ +/***************************************************************************/ + +int *tmpclauseset,tmpnOfClauses,tmpptr; + +/* Go through all clauses in the temporaryclauseset and emit them. */ + +void emitclause(int *,int,formulaclass); + +void emittemporarygoalinitclauses() { + int clen,class,cnt; + +#ifdef DEBUG + printf("Start moving init and goal clauses.\n"); +#endif + + cnt = 0; + tmpptr = 0; + while(cnt < tmpnOfClauses) { + switch(tmpclauseset[tmpptr] & TIMEtags) { + case INITtag: class = inittime; break; + case GOALtag: class = goaltime; break; + case TRtag: class = transition; break; + default: fprintf(stderr,"emittemporarygoalinitclauses"); exit(1); + } + clen = tmpclauseset[tmpptr] & LENBITS; + if(class != transition) /* Only copy non-transition clauses. */ + emitclause(&(tmpclauseset[tmpptr+1]),clen,class); + tmpptr += clen+1; + cnt += 1; + } +#ifdef DEBUG + printf("Finished moving init and goal clauses.\n"); +#endif +} + +/* PROBLEM ABOVE: goal formulas may be Tseitin-transformed, and if + the external preprocess has changed the variable numbering, then + we would have to rename the auxiliary variables at this point. + However, this is not necessary if the numbering only affects the + "next state" and auxiliary variables. +*/ + +/* Functions and variables for interfacing with the external preprocessor */ + +int ppclause[0x100000]; +int pplen; +int ppSVars,ppActions,ppAux,ppNewAux; + +void initializepprenaming(int nSVars,int nActions,int nAux,int newtotal) { + ppSVars = nSVars; + ppActions = nActions; + ppAux = nAux; + ppNewAux = newtotal-(ppSVars+ppActions+ppAux+ppSVars); // How many new aux? + varsPerTime = ppSVars+ppActions+ppNewAux+ppAux; + printf("SVars = %i Actions = %i Aux = %i newAux = %i\n", + nSVars,nActions,nAux,ppNewAux); +} + +int pprenamelit(int lit) { // Rename literal after using external preprocessor + int negated; + int index,newindex; + int NAUXBEGIN; + + if(lit < 0) { + negated = 1; + index = (0-lit)-1; + } else { + negated = 0; + index = lit-1; + } + + NAUXBEGIN = ppSVars+ppActions+ppAux+ppSVars; + + if(index < ppSVars+ppActions+ppAux) { // SVar, Action, Aux indexing unchanged + newindex = index; + } else if(index >= NAUXBEGIN) { // New auxiliaries will go after old auxiliaries. + newindex = index-ppSVars; + } else { // Next state variables will be shifted after new auxiliaries. + newindex = index+ppNewAux; + } + + return (negated ? 0-(newindex+1) : (newindex+1)); +} + +/******************************************************************************/ +/* CP3 interface */ +/******************************************************************************/ + +#ifdef CP3 + +void docp3preprocessing() { + + int freezeVar = 0, + cpClss = 0, + cpVars = 0, + cpTotalLits = 0, + lit = 0, + testLits = 0, + testClss = 0; + + int ptr,len; + int i,j; + + printf("c start CNF preprocessing\n"); + printf("1\n"); + void *preprocessor = CPinit(); + int myargc = 7; // 6 number of elements of parameters (so far, must be set manually) + /* + * Here, the actual interesting stuff can be done + * Could do experiments to extract the reduction without actually perform search for a plan at the beginning + * + * "-bve" does variable elimination. When action variables would not be freezed, that might become much more interesting (for-loop below) + * "-bva" does variable addition, independent of frozen variables. However, introduces fresh variables as new "high" variables, so that the order on the variables breaks + */ + const char * myargv [] = {"pseudobinary","-enabled_cp3","-up","-subsimp","-unhide","-bva","-bve"}; // configuration - bve, because important vars are freezed + printf("2\n"); + CPparseOptions( preprocessor, &myargc, myargv, 0 ); // parse the configuration! + + // add clauses to preprocessor + printf("3\n"); + printf("c send formula to Coprocessor (%d)\n",nOfClauses); + + // test the kind of clauses + testClss = 0;ptr = 0; + for(i=0;i lastTimePoint) { + printf("Check -F %i and -T %i: first time point > last\nExiting...",firstTimePoint,lastTimePoint); + exit(0); + } + + initformuladb(); + + for(i=0;ii); + assert(r=0;i--) translateaction(i); +#endif + + /* Frame axioms */ + + + if(flagCEvariables == 0) { /* The base encoding. */ + + for(i=0;i(B) ? (A) : (B)) +#define min(A,B) ((A)<(B) ? (A) : (B)) + +void startlength(int i,int len) { + seqs[i].sati = outputNSAT(i,len+1,0); + + printf("Horizon %i:",len); + printf(" %i variables\n",seqs[i].sati->nOfVars); + + seqs[i].restart = 0; + seqs[i].callsleft = 0; + seqs[i].effort = 0; + // The following test was i > 1. Was it redundant? See outputNSAT. + if(i > 0) seqs[i].sati->al2its = seqs[0].sati->al2its; +} + +int gcinterval; /* How often will GC be performed. */ +int gccounter; /* Counter to see if gccinterval has been reached. */ +int notstart; /* Instance length for which no-start has been notified. */ + +void init_gc() { + gcinterval = 20000; + gccounter = gcinterval; + notstart = 0; +} + +void reset_gccounter(int freed) { + gccounter = gcinterval; + if(GCaggressiveness == 0) gcinterval += 500; +} + +/* + Luby series: + t_i = 2^{k-1} if i = 2^k-1 + t_i = t_{i-2^{k-1}+1} if 2^{k-1} <= i < 2^k - 1 + + Jinbo Huang (2007?) proposed the Luby series as a restart strategy. + (Or was it already used in SATZ_rand by Selman and others before?) + + Warning: luby is not defined for 0, but for all i >= 1. +*/ + +int luby(int i) { + int k,p; + k = 1; + p = 2; + while (p < (i+1)) { + k += 1; + p *= 2; + } + if (p == (i+1)) return (p/2); + return (luby(i - (p/2) + 1)); +} + + +/* How many steps per ith restart? */ + +inline int RESTART(int i) { + switch(flagRestartScheme) { + case 0: return 1; + case 1: return luby(i+1); + default: return 1; + } +} + + +int instancelength(int i) { + return i*outputTimeStep+firstTimePoint; +} + +void testtimeout() { + if(flagTimeout && (timefromstart() > (float)flagTimeout)) { + printf("Timeout after %i seconds of CPU time.\n",flagTimeout); + givememorystatistics(); + exit(0); + } +} + +int actives; + +/* Make one SAT call, and update the seqs[] data structure according + to the result. Return TRUE if a satisfying assignment was found. */ + +int computeonestep(int i,int forcedrestart) { + int j; + + /* Do restart now? Yes, if there is only one call left. */ + int restart; + + /* If all calls for the preivous restart were done, start a new restart. */ + + if(seqs[i].callsleft == 0) { + seqs[i].restart += 1; + seqs[i].callsleft = RESTART(seqs[i].restart); + } + + restart = (seqs[i].callsleft == 1) || forcedrestart; + + /* The number of clauses learned is determined by flagRestartInterval. */ + solve0(seqs[i].sati,flagRestartInterval,restart); + + seqs[i].effort += 1; + seqs[i].callsleft -= 1; + + /* If instance turned out to be TRUE. */ + if(seqs[i].sati->value == 1) { +#ifdef MULTICORE +#pragma omp critical +#endif + { + actives -= 1; // printf("actives = %i\n",actives); + printf("PLAN FOUND: %i steps\n",seqs[i].sati->nOfTPoints-1); + callprintplan(seqs[i].sati); + } + return 1; + } + +#ifdef MULTICORE +#pragma omp critical +#endif + { + /* If instance turned out to be FALSE. */ + if(seqs[i].sati->value == 0) { + actives -= 1; // printf("actives = %i\n",actives); + printf("%i UNSAT (%i decisions %i conflicts)\n",seqs[i].sati->nOfTPoints-1,seqs[i].sati->decisions,seqs[i].sati->conflicts); + for(j=0;jvalue == -1) { /* Formulas that must be UNSAT. */ + seqs[j].sati->value = 0; + printf("%i must be UNSAT (%i decisions %i conflicts)\n",seqs[j].sati->nOfTPoints-1,seqs[j].sati->decisions,seqs[j].sati->conflicts); + freeinstance(seqs[j].sati); + } + } + freeinstance(seqs[i].sati); + } + } + return 0; +} + +/* Can start a new instance without exhausting memory? */ + +int instancefitsmemory(int new) { + return (memoryused() + estimateinstancesize(new,nOfActions*3,nOfActions) < flagMemoryLimit); +} + +/* If memory exhausted, reduce GC interval and stop increasing it. */ + +void testmemoryexhaustion() { + if(GCaggressiveness == 0 && memoryused() > flagMemoryLimit) { + printf("ATTENTION: Memory bound %.2f MB reached, %.2f MB allocated\n",flagMemoryLimit,memoryused()); + GCaggressiveness = 1; + gcinterval = gcinterval / 2; + gccounter = -1; + } +} + + +/* With one restart split to several pieces (as with Luby), we must +delay clause deletion / garbage collection to when all SAT instances +are restarted. This may involve delaying some of the restarts. +Alternatively, we immediately terminate the current restarts when we want +to collect garbage. */ + +void runalgorithmA(int n,int step) { + int last; + int i,j; + int restart; + + initclausedb(); + + actives = 0; + last = -1; + + init_gc(); + + do { + + testtimeout(); + + /* Start new lengths if there are not enough. */ + + while(actives < n && instancelength(last+1) <= lastTimePoint && instancefitsmemory(instancelength(last+1))) { + last += 1; + startlength(last,instancelength(last)); + if(seqs[last].sati->value != 0) actives += 1; + } + + // printf("solving ..%i with %i active\n",last,actives); + + for(i=0;i<=last;i++) { + + testmemoryexhaustion(); + + if(seqs[i].sati->value == -1) { + + if(computeonestep(i,0)) return; + gccounter -= flagRestartInterval; + + } + + } + + if(gccounter < 0) { + /* Must initiate a restart at this point: GC will move clauses, and + we would otherwise need to redirect pointers in the decision stack. */ + for(j=0;j<=last;j++) if(seqs[j].sati->value == -1 && seqs[j].callsleft && computeonestep(j,1)) return; + reset_gccounter(garbagecollection()); + } + + } while((instancelength(last+1) <= lastTimePoint) || (seqs[last].sati->value == -1)); + + printf("PLAN NOT FOUND: steps %i..%i tested\n",firstTimePoint,lastTimePoint); + return; +} + +void MULTICORErunalgorithmA(int n,int step) { + int PLANFOUND,DOGC,NOPLAN; + int first,last; + int nextinst,i,j; + int currentThread; + + initclausedb(); + + actives = 0; + + nextinst = -1; + first = 0; + last = -1; + + init_gc(); + + while(actives < n && instancelength(last+1) <= lastTimePoint) { + startlength(last+1,instancelength(last+1)); + last += 1; + if(seqs[last].sati->value != 0) actives += 1; + } + +#ifdef MULTICORE +#pragma omp parallel private(i,j,currentThread) +#endif + { +#ifdef MULTICORE + currentThread = omp_get_thread_num(); +#else + currentThread = 0; +#endif + + DOGC = 0; + NOPLAN = 0; + PLANFOUND = 0; + + do { + +#ifdef MULTICORE +#pragma omp master + testtimeout(); +#endif + + do { + + /* Start new lengths if there are not enough. */ + +#pragma omp master + { + while(actives < n && instancelength(last+1) <= lastTimePoint) { + startlength(last+1,instancelength(last+1)); + last += 1; + if(seqs[last].sati->value != 0) actives += 1; + } + } + +#pragma omp critical + { + + /* Find next SAT instance to solve. */ + + do { + nextinst += 1; + printf("NEXTINST = %i for thread %i\n",nextinst,currentThread); fflush(stdout); + if(nextinst > last) nextinst = first; + + } while(seqs[nextinst].sati->thread != -1 || seqs[nextinst].sati->value != -1); + + /* nextinst is an instance that has not been and is not being solved. */ + + i = nextinst; + seqs[i].sati->thread = currentThread; /* Record running thread. */ + + printf("Computing length %i in thread %i.\n",seqs[i].sati->nOfTPoints,currentThread); fflush(stdout); + + } + + if(computeonestep(i,0)) { + PLANFOUND = 1; + } + seqs[i].sati->thread = -1; /* Not running any more. */ + +#pragma omp atomic + gccounter -= flagRestartInterval; + + if(gccounter < 0) { + DOGC = 1; + printf("DOING GC!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"); + /* Must initiate a restart at this point: GC will move clauses, and + we would otherwise need to redirect pointers in the decision stack. */ + for(j=0;j<=last;j++) if(seqs[j].sati->value == -1 && seqs[j].callsleft && computeonestep(j,1)) PLANFOUND = 1; + } + + if((instancelength(last+1) > lastTimePoint) && (seqs[last].sati->value != -1)) NOPLAN = 1; + + + } while(!PLANFOUND && ! NOPLAN && !DOGC); + +#pragma omp barrier + +#pragma omp master + { + if(DOGC) { + reset_gccounter(garbagecollection()); + DOGC = 0; + } + } + +#pragma omp barrier + + } while(!PLANFOUND && !NOPLAN); + + } + + if(NOPLAN) { + printf("PLAN NOT FOUND: steps %i..%i tested\n",firstTimePoint,lastTimePoint); + } + return; +} + +double power(double r,int i) { + int j; + double value; + value = 1.0; + for(j=0;jvalue == -1) { + + if(firstactive == -1) { + firstactive = i; + + /* The lowest active horizon length is always computed. */ + + seqs[i].sati->thread = 0; + if(computeonestep(i,0)) return; + + gccounter -= flagRestartInterval; + + } else { + + threshold = ((float)(seqs[firstactive].effort))*power(r,i-firstactive)+0.5; + if(((float)(seqs[i].effort)) < threshold) { + + seqs[i].sati->thread = 0; + if(computeonestep(i,0)) return; + + gccounter -= flagRestartInterval; + } + } + + // if(i==5) printplanT(seqs[i].sati); + + } + + testmemoryexhaustion(); + + } + + /* Check whether to start new length. */ + + if(last > -1) threshold = ((float)(seqs[firstactive].effort))*power(r,last+1-firstactive); + + if((instancelength(last) < lastTimePoint) && (actives < paramM) && (firstactive == -1 || threshold > 0.5)) { + + if(instancefitsmemory(instancelength(last+1))) { + startlength(last+1,instancelength(last+1)); + last += 1; + actives += 1; // printf("ADD: actives = %i %i\n",actives,paramM); + } else { + if(notstart < instancelength(last+1)) + printf("ATTENTION: Horizon %i will not be started: memory allocated %.2f MB limit %.2f MB\n",instancelength(last+1),memoryused(),flagMemoryLimit); + notstart = instancelength(last+1); + } + } + + if(gccounter < 0) { + /* Must initiate a restart at this point: GC will move clauses, and + we would otherwise need to redirect pointers in the decision stack. */ + for(j=0;j<=last;j++) if(seqs[j].sati->value == -1 && seqs[j].callsleft && computeonestep(j,1)) return; + reset_gccounter(garbagecollection()); + } + + + } while((instancelength(last+1) <= lastTimePoint) || (seqs[last].sati->value == -1)); + + printf("PLAN NOT FOUND: %i steps tested\n",lastTimePoint); +} + +/* Algorithm C: consider horizon lengths r^0, r^1, r^2, ... */ + +int Clength(int i) { + return (int)(5.0*power(paramC,(float)i)); +} + +void runalgorithmC() { + int last; + int i,j; + + initclausedb(); + + actives = 0; + last = -1; + + init_gc(); + + do { + + /* Start new lengths if there are not enough. */ + + if(actives < paramM && Clength(last+1) <= lastTimePoint && instancefitsmemory(Clength(last+1))) { + startlength(last+1,Clength(last+1)); + last += 1; + if(seqs[last].sati->value != 0) actives += 1; + } + // printf("instancesizeestimate is %.2f (len %i vars %i actions %i\n",estimateinstancesize(Clength(last+1),varsPerTime,nOfActions),Clength(last+1),varsPerTime,nOfActions); + + if(actives == 0) { + printf("Was not allowed to increase horizon length. Exiting..\n"); + exit(1); + } + + // printf("solving ..%i with %i active\n",last,actives); + + for(i=0;i<=last;i++) { + + if(seqs[i].sati->value == -1) { + + if(computeonestep(i,0)) return; + gccounter -= flagRestartInterval; + + } + + testmemoryexhaustion(); + + } + + if(gccounter < 0) { + /* Must initiate a restart at this point: GC will move clauses, and + we would otherwise need to redirect pointers in the decision stack. */ + for(j=0;j<=last;j++) if(seqs[j].sati->value == -1 && seqs[j].callsleft && computeonestep(j,1)) return; + reset_gccounter(garbagecollection()); + } + + } while((Clength(last+1) <= lastTimePoint) || (seqs[last].sati->value == -1)); + + printf("PLAN NOT FOUND: steps %i..%i tested\n",firstTimePoint,lastTimePoint); + return; +} + + +/*******************************************************************/ +/* DIMACS output */ +/*******************************************************************/ + +inline int final(int i,int time) { + int j; + switch(i&TYPEtag) { + case AUXtag: j = nOfAtoms+nOfActions; break; + case VARtag: j = 0; break; + case OPtag: j = nOfAtoms; break; + default: fprintf(stderr,"ERROR: 43346 %i %i\n",i%TYPEtag,i); exit(1); break; + } + if(i&NEXTtag) j += varsPerTime; + j += VARINDEX(i)+time*varsPerTime; + if(i&NEGtag) return -(j+1); else return j+1; +} + +inline int finalNOTIME(int i) { + int j; + switch(i&TYPEtag) { + case AUXtag: j = nOfAtoms+nOfActions; break; + case VARtag: j = 0; break; + case OPtag: j = nOfAtoms; break; + default: assert(1 == 0); // fprintf(stderr,"ERROR: 43346\n"); exit(1); break; + } + return j+VARINDEX(i); +} + +void initclauseset() { + nOfClauses = 0; + nOfTClauses = 0; + clauseptr = 0; + maxClauseEls = 0x40000; + clauseset = (int *)malloc(maxClauseEls * sizeof(int)); +} + +void reallocclauseset(int minsize) { + maxClauseEls = max(maxClauseEls * 2,minsize); + clauseset = (int *)realloc(clauseset,maxClauseEls * sizeof(int)); +} + +void emitclause(int *vector,int cnt,formulaclass class) { + int i,j,tmp,realcnt,*tag; + nOfClauses += 1; + if(class == transition) nOfTClauses += 1; + if(clauseptr + cnt + 1 > maxClauseEls) reallocclauseset(clauseptr+cnt+1); + realcnt = 0; + tag = &(clauseset[clauseptr++]); +#ifdef DEBUG + printf("EMIT: "); +#endif + for(i=0;it) { + case conj: + fs = f->juncts; + while(fs != NULL) { + produceclauses(fs->hd,class); + fs = fs->tl; + } + break; + case disj: + /* Find all disjuncts, get a literal representing each, and output a clause. + For non-atomic disjuncts, do the same recursively. */ + if(!biggerthan(f,200)) { +#ifdef DEBUG + printf("Calling produceclausesENUM with: "); + printFfma(f); + printf("\n"); +#endif + produceclausesENUMERATIVE(f,class); + } else { + xstackptr = -1; + xclauselen = 0; + produceclausesDD(f,class); + emitclause(xclause,xclauselen,class); + produceclausesTseitin(class); + } + break; + case patom: + xclause[0] = f->a; + emitclause(xclause,1,class); + break; + case natom: + xclause[0] = (f->a)|NEGtag; + emitclause(xclause,1,class); + case TRUE: break; + case FALSE: + printf("WARNING: Emitting top-level constant FALSE.\n"); + xclause[0] = 0|VARtag; + emitclause(xclause,1,class); + xclause[0] = 0|NEGtag|VARtag; + emitclause(xclause,1,class); + /* There must be at least one state variable. */ + if(nOfAtoms == 0) nOfAtoms = 1; + /* Sometimes all vars are eliminated, and we would get errors elsewhere. */ + break; + } +} + +/* Identify the disjuncts of a clause, and put them in the xclause + array. Disjuncts that are conjunctions are represented by a new + auxiliary literal, and for each such literal an appropriate equivalence + is later generated by the produceclausesTseitin procedure. +*/ + +void produceclausesDD(fma *f,formulaclass class) { + fmalist *fs; + int aux; + + switch(f->t) { + case disj: + fs = f->juncts; + while(fs != NULL) { + produceclausesDD(fs->hd,class); + fs = fs->tl; + } + break; + case conj: + aux = allocAUX(1); + xclause[xclauselen++] = AUX(aux); + xstack[++xstackptr] = f; + xstackv[xstackptr] = AUX(aux); + break; + case patom: + xclause[xclauselen++] = f->a; + break; + case natom: + xclause[xclauselen++] = (f->a)|NEGtag; + break; + case TRUE: + /* Clause is TRUE: don't generate it!!!!!!!!!!!!!!!!!!!!!!!! */ +#ifdef ASSERTS + assert(1 == 0); +#endif + break; + case FALSE: + /* No literal in the clause. */ + break; + } +} + +void produceclausesTseitin(formulaclass class) { + int type; + fma *f; + int aux; + +#ifdef ASSERTS + assert(xstackptr >= -1); + assert(xclauselen >= 0); + assert(xclauselen < MAXXCLAUSELEN); + assert(xstackptr < MAXXSTACK); +#endif + + while(xstackptr >= 0) { + /* Pop x <-> formula from stack and generate clauses. */ + aux = xstackv[xstackptr]; + f = xstack[xstackptr--]; + + xclauselen = 0; + + type = f->t; + + /* First disjunct to The Long Clause. */ + + switch(type) { + case disj: + xclause[xclauselen++] = aux|NEGtag; /* aux -> l1 V .. V ln */ + break; + case conj: + xclause[xclauselen++] = aux; /* l1 & .. & ln -> aux */ + break; + default: + assert(1 == 0); + } + + /* Generate aux <-> (lit) clauses, and add literals to The Long Clause. */ + + pcTseitinRecurse(class,type,aux,f->juncts); + + /* Emit The Long Clause. */ + + emitclause(xclause,xclauselen,class); + +#ifdef ASSERTS + assert(xclauselen < MAXXCLAUSELEN); + assert(xstackptr < MAXXSTACK); +#endif + + } +} + +void pcTseitinRecurse(int class,int type, int aux, fmalist *fs) { + fma *f; + int aux2; + int c2lause[2]; + + while(fs != NULL) { + +#ifdef ASSERTS + assert(xclauselen < MAXXCLAUSELEN); + assert(xstackptr < MAXXSTACK); +#endif + + f = fs->hd; + + switch(f->t) { + + case conj: + + if(type == conj) pcTseitinRecurse(class,type,aux,f->juncts); + else { + aux2 = allocAUX(1); + + xclause[xclauselen++] = AUX(aux2); + + c2lause[0] = aux; + c2lause[1] = AUX(aux2)|NEGtag; + emitclause(c2lause,2,class); + + xstack[++xstackptr] = f; + xstackv[xstackptr] = AUX(aux2); + } + break; + + case disj: + + if(type == disj) pcTseitinRecurse(class,type,aux,f->juncts); + else { + aux2 = allocAUX(1); + + xclause[xclauselen++] = AUX(aux2)|NEGtag; + + c2lause[0] = aux|NEGtag; + c2lause[1] = AUX(aux2); + emitclause(c2lause,2,class); + + xstack[++xstackptr] = f; + xstackv[xstackptr] = AUX(aux2); + } + break; + + case patom: + + if(type == disj) { + + xclause[xclauselen++] = f->a; + + c2lause[0] = aux; + c2lause[1] = f->a|NEGtag; + + } else { + + xclause[xclauselen++] = (f->a)|NEGtag; + + c2lause[0] = aux|NEGtag; + c2lause[1] = f->a; + + } + + emitclause(c2lause,2,class); + + break; + + case natom: + + if(type == disj) { + + xclause[xclauselen++] = (f->a)|NEGtag; + + c2lause[0] = aux; + c2lause[1] = f->a; + + } else { + + xclause[xclauselen++] = f->a; + + c2lause[0] = aux|NEGtag; + c2lause[1] = f->a|NEGtag; + + } + + emitclause(c2lause,2,class); + + break; + + case TRUE: + /* Clause is TRUE: don't generate it!!!!!!!!!!!!!!!!!!!!!!!! */ + assert(1 == 0); + break; + case FALSE: break; + assert(1 == 0); + } + + fs = fs->tl; + + } + + +} + +/* Count the size of the CNF (# of clauses) with the trivial + transformation based on associativity laws and no auxiliary + variables. +THIS IS USELESS BECAUSE, WITH 32 BIT INTEGERS, IT OVERFLOWS WITH +MANY NON-STRIPS PROBLEMS, ESPECIALLY ONES THAT CONTAIN QUANTIFICATION. +*/ + +//int trivialsize(fma *f) { +// fmalist *fs; +// int c; +// if(f==NULL) return 1; +// switch(f->t) { +// case TRUE: +// case FALSE: +// return 1; +// case patom: +// case natom: +// return 1; +// case conj: +// fs = f->juncts; +// c = 1; +// while(fs != NULL) { +// c += trivialsize(fs->hd); +// fs = fs->tl; +// } +// return c; +// case disj: +// fs = f->juncts; +// if(fs == NULL) return 1; +// c = 1; +// while(fs != NULL) { +// c = c * trivialsize(fs->hd); +// fs = fs->tl; +// } +// return c; +// } +//} + +/* Test whether formula is likely to lead clause sets bigger than bound. */ + +int biggerthan0(fma *f,int bound,int *size) { + fmalist *fs; + int size0; + + if(f==NULL) { + *size = 1; + return 1; + } + + switch(f->t) { + + case TRUE: + case FALSE: + case patom: + case natom: + *size = 1; + return 0; + + case conj: + + fs = f->juncts; + *size = 0; + while(fs != NULL) { + if(biggerthan0(fs->hd,bound,&size0)) return 1; + *size += size0; + if(*size > bound) return 1; + fs = fs->tl; + } + return 0; + + case disj: + + fs = f->juncts; + *size = 1; + while(fs != NULL) { + if(biggerthan0(fs->hd,bound,&size0)) return 1; + *size *= size0; + if(*size > bound) return 1; + fs = fs->tl; + } + return 0; + } + + return 0; +} + +int biggerthan(fma *f,int bound) { + int guesstimate; + if(biggerthan0(f,bound,&guesstimate) || + (guesstimate > bound)) return 1; + else return 0; +} + + +#define MAXLITERALSCL 2000000 +int clauselist[MAXLITERALSCL]; +int clausealloc; + +/* Trivial CNF transformation by recursively translating subformulas +to clauses, and then recursively combining the clause sets. +For a conjunction, the clauseset is simply the union of the constituent +clause sets. +For a disjunction, the clauseset is the "Cartesian product" of the +clause sets. +*/ + +void csproduct(int f0,int l0,int f1,int l1,int *f2,int *l2) { + int i,j,k; + *f2 = clausealloc; + *l2 = clausealloc-1; + i = f0; + while(i <= l0) { + j = f1; + while(j <= l1) { + /* New clause obtained by concatenation. */ + *l2 = clausealloc; /* Index of the last clause generated */ + clauselist[clausealloc++] = clauselist[i]+clauselist[j]; + for(k=1;k<=clauselist[i];k++) clauselist[clausealloc++] = clauselist[i+k]; + for(k=1;k<=clauselist[j];k++) clauselist[clausealloc++] = clauselist[j+k]; + j += clauselist[j]+1; + } + i += clauselist[i]+1; + } +#ifdef ASSERTS + assert(clausealloc < MAXLITERALSCL); +#endif +} + +int copyclauses(int first,int last) { + int i,tmp; + tmp = clausealloc; + i = first; + while(i <= last+clauselist[last]) { + clauselist[clausealloc++] = clauselist[i++]; +#ifdef ASSERTS + assert(clausealloc < MAXLITERALSCL); +#endif + } + return tmp+(last-first); +} + +void csconcatenate(int f0,int l0,int f1,int l1,int *f2,int *l2) { + *f2 = clausealloc; + copyclauses(f0,l0); + *l2 = copyclauses(f1,l1); + return; +} + +int onlyliterals(fmalist *fs) { + while(fs != NULL) { + switch(fs->hd->t) { + case patom: + case natom: + break; + default: + return 0; + } + fs = fs->tl; + } + return 1; +} + +/* Translation from circuits to CNF */ + +void pc30(fma *f,formulaclass cl,int *first,int *last) { + fmalist *fs; + int f0,l0,f1,l1,f2,l2,len; + switch(f->t) { + case disj: + fs = f->juncts; + if(onlyliterals(fs)) { + *first = clausealloc; + *last = clausealloc; + clausealloc += 1; + len = 0; + while(fs != NULL) { + len += 1; + switch(fs->hd->t) { + case patom: + clauselist[clausealloc++] = fs->hd->a; + break; + case natom: + clauselist[clausealloc++] = fs->hd->a|NEGtag; + break; + default: + assert(1 == 0); + } + fs = fs->tl; + } + clauselist[*first] = len; + } else { + pc30(fs->hd,cl,&f0,&l0); + fs = fs->tl; + while(fs != NULL) { /* Repeatedly construct the product. */ + pc30(fs->hd,cl,&f1,&l1); + csproduct(f0,l0,f1,l1,&f2,&l2); + f0 = f2; + l0 = l2; + fs = fs->tl; + } + *first = f0; + *last = l0; + } + return; + case conj: + fs = f->juncts; + if(fs == NULL) { /* Empty conjunction is the empty clause set. */ + *first = 0; + *last = -1; + return; + } + pc30(fs->hd,cl,&f0,&l0); + fs = fs->tl; + while(fs != NULL) { /* Repeatedly concatenate. */ + pc30(fs->hd,cl,&f1,&l1); + csconcatenate(f0,l0,f1,l1,&f2,&l2); + f0 = f2; + l0 = l2; + fs = fs->tl; + } + *first = f0; + *last = l0; + return; + case patom: /* Clause with one positive literal */ + *first = clausealloc; + *last = clausealloc; + clauselist[clausealloc] = 1; + clauselist[clausealloc+1] = f->a; + clausealloc += 2; +#ifdef ASSERTS + assert(clausealloc < MAXLITERALSCL); +#endif + break; + case natom: /* Clause with one negative literal */ + *first = clausealloc; + *last = clausealloc; + clauselist[clausealloc] = 1; + clauselist[clausealloc+1] = f->a|NEGtag; + clausealloc += 2; +#ifdef ASSERTS + assert(clausealloc < MAXLITERALSCL); +#endif + break; + case TRUE: /* No clauses. */ + *first = 0; + *last = -1; + break; + case FALSE: /* One empty clause */ + *first = clausealloc; + *last = clausealloc; + clauselist[clausealloc++] = 0; +#ifdef ASSERTS + assert(clausealloc < MAXLITERALSCL); +#endif + break; + } +} + +void produceclausesENUMERATIVE(fma *f,formulaclass cl) { + int first,last,c,len; + clausealloc = 0; + pc30(f,cl,&first,&last); + c = first; + while(c <= last) { + len = clauselist[c]; + emitclause(clauselist+c+1,len,cl); + c += len+1; + } +} + +/*******************************************************************/ +/* DIMACS interface */ +/*******************************************************************/ + +void outputDIMACS() { + int i,j,k,ptr,h,with,len,bias; + int nOfInvariants; + FILE *F; + char filename[1000]; + + printf("DIMACS output\n"); + + /* Count how many invariant clauses will be output later. */ + + nOfInvariants = 0; + + for(k=0;k0) { + for(k=0;k 0); + setheuristic(sati,SATheuristic); + setpheuristic(sati,PLANheuristic); + + ptr = 0; + + for(k=0;k= 0) { + add2clause(sati,shortcutclauses[k].l1,shortcutclauses[k].l2+2*sati->nOfVarsPerTime*shortcutclauses[k].tdiff,TransC); + } else { + add2clause(sati,shortcutclauses[k].l2,shortcutclauses[k].l1-2*sati->nOfVarsPerTime*shortcutclauses[k].tdiff,TransC); + } + } + + // printf("Total of %i clauses.\n",clausecount); + +#ifdef COSTS + // Add action costs to the cost vector + for(j=0;jal2its = seqs[id-1].sati->al2its; + + return sati; +} diff --git a/translate2sat.h b/translate2sat.h new file mode 100644 index 0000000..a956189 --- /dev/null +++ b/translate2sat.h @@ -0,0 +1,40 @@ + +/* 2012 (C) Jussi Rintanen, jrintanen.jr@gmail.com */ + +typedef struct _seq { + satinstance sati; + int restart; + int callsleft; + int effort; +} seq; + +seq seqs[10000]; + +void encoding(); + +typedef struct _CEstruct { + int var; + fma *condition; + char disjunctive; + struct _CEstruct *next; +} CEstruct; + +CEstruct **CEs; + +typedef struct _compactCEstruct { + int var; + fma *condition; + char disjunctive; +} compactCEstruct; + +compactCEstruct **cCEs; + +typedef struct _actvar { + int *effectlits; + int *conditionlits; +} actvar; + +int maxactvars; +actvar *actvars; + +int actaffects(int,int); diff --git a/varvals.c b/varvals.c new file mode 100644 index 0000000..b80cf71 --- /dev/null +++ b/varvals.c @@ -0,0 +1,364 @@ +/* 2012 (C) Jussi Rintanen, jrintanen.jr@gmail.com */ + +/* Functions to set literals and variables true and false, and to + read their values. + setlittrue + setlitfalse + unsetlit + setvartrue + setvarfalse + unsetvar + littruep + litfalsep + litunsetp + vartruep + varfalsep + varunsetp +*/ + +/*************************************************************************/ +/************************** one byte per variable ************************/ +/*************************************************************************/ + +#ifdef REPRONE + +#define VARVALUE(v) (sati->variableval[(v)]) + +inline int varunset(satinstance sati,int i) { return (VARVALUE(i) = UNASS); } +inline int varunsetp(satinstance sati,int i) { return (VARVALUE(i) == UNASS); } + +inline void litsettrue(satinstance sati,int l) { VARVALUE(VAR(l)) = VALUE(l); } +inline void litunset(satinstance sati,int l) { VARVALUE(VAR(l)) = UNASS; } +inline int litunsetp(satinstance sati,int l) { return varunsetp(sati,VAR(l)); } + +inline int littruep(satinstance sati,int l) { return (VARVALUE(VAR(l)) == VALUE(l)); } +inline int litfalsep(satinstance sati,int l) { return (VARVALUE(VAR(l)) == 1-VALUE(l)); } + +/* Value of a state variable. */ + +inline int varvalue(satinstance sati,int v) { return VARVALUE(v); } +inline int vartruep(satinstance sati,int i) { return (VARVALUE(i) == 1); } +inline int varfalsep(satinstance sati,int i) { return (VARVALUE(i) == 0); } + +#endif + + +/*************************************************************************/ +/************************ 2+2 bits in a 32 bit word **********************/ +/*************************************************************************/ + +#ifdef REPRTWO + +/* + Each literal has 2 bits. 1 = TRUE, 2 = FALSE, 0 = UNDEFINED + This is quite a bit slower than representation 3. With DriverLog-16 + REPRTHREE total runtime is 80 per cent of REPRTWO. + */ + +inline void setII(satinstance sati,int v,int val) { + unsigned int index,slot,word,mask,b; + index = v >> 3; + slot = (v & 7) * 4; + word = sati->variableval[index]; + mask = 15 << slot; + b = val << slot; + sati->variableval[index] = (word&(0xffffffff^mask))|b; +} + +inline int getII(satinstance sati,int l) { + unsigned int index,slot,word; + index = l >> 4; + slot = (l & 15) * 2; + word = sati->variableval[index]; + return (word >> slot) & 3; +} + +inline void litsettrue(satinstance sati,int l) { + int val; + val = 9-(l&1)*3; + setII(sati,l >> 1,val); +} + +inline void litsetfalse(satinstance sati,int l) { + int val; + val = 6+(l&1)*3; + setII(sati,l >> 1,val); +} + +inline void varsetfalse(satinstance sati,int v) { + setII(sati,v,6); // 2 + (1 << 2) +} + +inline void varsettrue(satinstance sati,int v) { + setII(sati,v,9); // 1 + (2 << 2) +} + +inline void litunset(satinstance sati,int l) { + setII(sati,l >> 1,0); +} + +inline void varunset(satinstance sati,int v) { + setII(sati,v,0); +} + +inline int littruep(satinstance sati,int l) { + return (getII(sati,l) == 1); +} + +inline int litfalsep(satinstance sati,int l) { + return (getII(sati,l) == 2); +} + +inline int litunsetp(satinstance sati,int l) { + return (getII(sati,l) == 0); +} + +inline int vartruep(satinstance sati,int v) { + return (getII(sati,2*v) == 1); +} + +inline int varfalsep(satinstance sati,int v) { + return (getII(sati,2*v) == 2); +} + +inline int varunsetp(satinstance sati,int v) { + return (getII(sati,2*v) == 0); +} + +inline int varvalue(satinstance sati,int v) { + switch(getII(sati,2*v)) { + case 1: return 1; + case 2: return 0; + default: return -1; + }; + return -1; +} + +#endif + +/*************************************************************************/ +/************** two bytes per variable, one for each literal *************/ +/*************************************************************************/ + +#ifdef REPRTHREE + +inline void litsettrue(satinstance sati,int l) { + sati->variableval[l] = 1; + sati->variableval[l^1] = 0; +} + +inline void litsetfalse(satinstance sati,int l) { + sati->variableval[l] = 0; + sati->variableval[l^1] = 1; +} + +inline void varsetfalse(satinstance sati,int v) { + sati->variableval[v*2] = 0; + sati->variableval[v*2+1] = 1; +} + +inline void varsettrue(satinstance sati,int v) { + sati->variableval[v*2] = 1; + sati->variableval[v*2+1] = 0; +} + +inline void litunset(satinstance sati,int l) { + // printf("UNSET: "); printTlit(sati,l); printf("\n"); + sati->variableval[l] = -1; + sati->variableval[l^1] = -1; +} + +inline void varunset(satinstance sati,int v) { + // printf("UNSET: "); printTlit(sati,PLIT(v)); printf("\n"); + sati->variableval[v*2] = -1; + sati->variableval[v*2+1] = -1; +} + +inline int littruep(satinstance sati,int l) { + return (sati->variableval[l] == 1); +} + +inline int litfalsep(satinstance sati,int l) { + return (sati->variableval[l] == 0); +} + +inline int litunsetp(satinstance sati,int l) { + return (sati->variableval[l] == -1); +} + +inline int vartruep(satinstance sati,int v) { + return (sati->variableval[2*v] == 1); +} + +inline int varfalsep(satinstance sati,int v) { + return (sati->variableval[2*v] == 0); +} + +inline int varunsetp(satinstance sati,int v) { + return (sati->variableval[2*v] == -1); +} + +inline int varvalue(satinstance sati,int v) { + return (sati->variableval[2*v]); +} + +#endif + +#ifdef REPRFOUR + +/* + Each literal has 1 bit, indicating that it is true. If l and -l are both + not true, then the literal is unassigned. + */ + +/* Set bit true. */ + +inline void setI(satinstance sati,int l) { + unsigned int index,slot,word; + index = l >> 5; + slot = l & 31; + word = sati->variableval[index]; + sati->variableval[index] = word|(1 << slot); +} + +/* Zero two bits. */ + +inline void unsetII(satinstance sati,int l) { + unsigned int index,slot,word,mask,l0; + l0 = l&0xfffffffe; + index = l0 >> 5; + slot = l0 & 31; + word = sati->variableval[index]; + mask = 3 << slot; + sati->variableval[index] = word&(0xffffffff^mask); +} + +inline int getI(satinstance sati,int l) { + unsigned int index,slot,word; + index = l >> 5; + slot = l & 31; + word = sati->variableval[index]; + return word&(1 << slot); +} + +inline int getII(satinstance sati,int l) { + unsigned int index,slot,word; + index = l >> 5; + slot = l & 31; + word = sati->variableval[index]; + return (word&(3 << slot)) >> slot; +} + +/* If not set, set true and return 1. */ + +inline int litunset2true(satinstance sati,int l) { + unsigned int index,slot,word,mask,l0,b; + l0 = l&0xfffffffe; + index = l0 >> 5; + slot = l0 & 31; + word = sati->variableval[index]; + mask = 3 << slot; + if(word & mask) return 0; + b = (l&1)+1; + // b = 1 << (l&1)+1; + sati->variableval[index] = word|(b << slot); + return 1; +} + +inline void litsettrue(satinstance sati,int l) { + setI(sati,l); +} + +inline void litsetfalse(satinstance sati,int l) { + setI(sati,l^1); +} + +inline void varsetfalse(satinstance sati,int v) { + setI(sati,2*v+1); +} + +inline void varsettrue(satinstance sati,int v) { + setI(sati,2*v); +} + +inline void litunset(satinstance sati,int l) { + unsetII(sati,l); +} + +inline void varunset(satinstance sati,int v) { + unsetII(sati,2*v); +} + +inline int littruep(satinstance sati,int l) { + return getI(sati,l); +} + +inline int litfalsep(satinstance sati,int l) { + return getI(sati,l^1); +} + +inline int litunsetp(satinstance sati,int l) { + return (getII(sati,l&0xfffffffe) == 0); +} + +inline int vartruep(satinstance sati,int v) { + return getI(sati,2*v); +} + +inline int varfalsep(satinstance sati,int v) { + return getI(sati,2*v+1); +} + +inline int varunsetp(satinstance sati,int v) { + return (getII(sati,2*v) == 0); +} + +inline int varvalue(satinstance sati,int v) { + switch(getII(sati,2*v)) { + case 0: return -1; + case 1: return 1; + default: return 0; + }; + return -1; +} + +#endif + +inline int tvarvalue(satinstance sati,int v,int t) { return varvalue(sati,TVAR(v,t)); } +inline int tvartime(satinstance sati,int vt) { return vt/sati->nOfVarsPerTime; } +inline int tvarvar(satinstance sati,int vt) { return vt%sati->nOfVarsPerTime; } + +inline int untimevar(satinstance sati,int v) { return (v%(sati->nOfVarsPerTime)); } +inline int litwithtime(satinstance sati,int l,int t) { + // return (((l >> 1) + sati->nOfVarsPerTime * t) << 1) | (l&1); + return l + 2 * sati->nOfVarsPerTime * t; +} +inline int varwithtime(satinstance sati,int v,int t) { + return v + sati->nOfVarsPerTime * t; +} + + +inline int tvartruep(satinstance sati,int v,int t) { + return vartruep(sati,varwithtime(sati,v,t)); +} + +inline int tvarfalsep(satinstance sati,int v,int t) { + return varfalsep(sati,varwithtime(sati,v,t)); +} + +inline int tvarunsetp(satinstance sati,int v,int t) { + return varunsetp(sati,varwithtime(sati,v,t)); +} + + +inline int tlittruep(satinstance sati,int l,int t) { + return littruep(sati,litwithtime(sati,l,t)); +} + +inline int tlitfalsep(satinstance sati,int l,int t) { + return litfalsep(sati,litwithtime(sati,l,t)); +} + +inline int tlitunsetp(satinstance sati,int l,int t) { + return litunsetp(sati,litwithtime(sati,l,t)); +} diff --git a/zPOSTF b/zPOSTF new file mode 100644 index 0000000..5f2fcb6 --- /dev/null +++ b/zPOSTF @@ -0,0 +1 @@ +"); diff --git a/zPREF b/zPREF new file mode 100644 index 0000000..e43bd09 --- /dev/null +++ b/zPREF @@ -0,0 +1 @@ +printf("Madagascar 0.99999 \ No newline at end of file