madagascar/operators.c

1868 lines
40 KiB
C

/* 2012 (C) Jussi Rintanen jrintanen.jr@gmail.com */
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#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<nOfAtoms;i++) {
effectoccP[i] = OScreateSize(20);
effectoccN[i] = OScreateSize(20);
preconoccP[i] = OScreateSize(20);
preconoccN[i] = OScreateSize(20);
condocc[i] = OScreateSize(20);
}
for(i=0;i<nOfActions;i++) {
forcedeffectsP[i] = OScreateSize(10);
forcedeffectsN[i] = OScreateSize(10);
necessarypreconP[i] = OScreateSize(30);
necessarypreconN[i] = OScreateSize(30);
}
for(i=0;i<nOfAtoms;i++) {
forcedeffectoccP[i] = OScreateSize(10);
forcedeffectoccN[i] = OScreateSize(10);
necessarypreconofP[i] = OScreateSize(30);
necessarypreconofN[i] = OScreateSize(30);
}
for(i=nOfActions-1;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;i<is->nOfEls;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;i<nOfAtoms;i++) mapping[i] = i;
to = 0;
for(from = 0;from<nOfAtoms;from++) {
if(onelits[from] == -1) { /* Variable is not static. */
mapping[from] = to;
to += 1;
} else {
mapping[from] = -1;
}
}
NEWnOfAtoms = to;
/* Elimination requires
- renaming of the variables in actions
- restructuring the index->name 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<nOfActions;i++) renameaction(&(actions[i]),mapping);
for(i=0;i<nOfAtoms;i++) {
renametwolits(twolits[fePLIT(i)],mapping);
renametwolits(twolits[feNLIT(i)],mapping);
}
goal = simplifyfmastatic(goal);
goalisdisjunctive = disjunctivep(goal);
if(goalisdisjunctive) printf("Goal: disjunctive\n");
else printf("Goal: conjunctive\n");
renamefma(goal,mapping);
/* Move twolits' contents into place. */
for(i=0;i<nOfAtoms;i++) {
if(mapping[i] != -1) {
// assert(mapping[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;i<nOfAtoms;i++) {
if(mapping[i] != -1) initialstate[mapping[i]] = initialstate[i];
}
/* Fix symbol table: state vars' indices have changed! */
renameatomtable(nOfAtoms,mapping);
// printf("WAS %i vars and IS %i vars.\n",nOfAtoms,NEWnOfAtoms);
nOfAtoms = NEWnOfAtoms;
}
/**************************************************************************/
/******************* Eliminate converse literals **************************/
/**************************************************************************/
void renamefmaL(fma *f,int *mapping) {
fmalist *fs;
switch(f->t) {
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;i<is->nOfEls;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<nOfAtoms;i++) mapping[i] = -1;
cnt = 0;
for(l0=0;l0<nOfAtoms;l0++) {
l = fePLIT(l0);
jITstart(twolits[l]);
while(jITnext(&l2)) {
if(feVAR(l) < feVAR(l2) && ISmember(feNEG(l),twolits[feNEG(l2)])) {
// if(flagShowInput) {
// if(l&1) printf("NOT ");
// printatomi(feVAR(l));
// printf(" and ");
// if(l2&1) printf("NOT ");
// printatomi(feVAR(l2));
// printf(" are converses.\n");
// }
if((mapping[feVAR(l2)] == -1) ||
((mapping[feVAR(l2)] >> 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<nOfAtoms;i++) { if(mapping[i] != -1) { printatomi(i); printf(" will be replaced by "); if(mapping[i] & 1) printf("NOT "); printatomi(mapping[i] >> 1); printf("\n"); } }
}
for(i=0;i<nOfActions;i++) renameactionL(&(actions[i]),mapping);
for(i=0;i<nOfAtoms;i++) {
if(mapping[i] != -1) { deletetwolits(fePLIT(i)); deletetwolits(feNLIT(i)); }
eliminatefromtwolits(twolits[fePLIT(i)],mapping);
eliminatefromtwolits(twolits[feNLIT(i)],mapping);
}
renamefmaL(goal,mapping);
}
/***************************************************************************/
/* Generate linear array representation of the main data structures here. */
/***************************************************************************/
/* We will have an array representation of many of the lists in operators.h
which were first constructed as linked lists. Linked lists have poor
cache locality and using them has a relatively high performance penalty
in many cases.
*/
void movearraydata(int index,ordintset *sourceset,int **destarray,int **fillptr) {
int item;
intlist *iterate;
destarray[index] = *fillptr;
OSstart(sourceset[index],&iterate);
while(OSnext(&item,&iterate)) {
*((*fillptr)++) = item;
}
*((*fillptr)++) = -1;
OSmakeempty(sourceset[index]);
}
void constructoperatorarrays() {
int allocsize;
int i;
int *fill;
int *arrayfordata;
/* Calculate the size of the array that is needed. */
allocsize = 0;
for(i=0;i<nOfAtoms;i++) { /* Go through state variable -indexed lists. */
allocsize += OScard(effectoccP[i]);
allocsize += OScard(effectoccN[i]);
allocsize += OScard(condocc[i]);
allocsize += OScard(preconoccP[i]);
allocsize += OScard(preconoccN[i]);
}
allocsize += 5*nOfAtoms; /* space for end-of-array markers -1 */
for(i=0;i<nOfActions;i++) { /* Go through action-indexed lists. */
allocsize += OScard(necessarypreconP[i]);
allocsize += OScard(necessarypreconN[i]);
allocsize += OScard(forcedeffectsP[i]);
allocsize += OScard(forcedeffectsN[i]);
}
allocsize += 6*nOfActions; /* space for end-of-array markers -1 */
/* Allocate pointer arrays for actions and state variables. */
AnecessarypreconP = (int **)statmalloc(300,nOfActions * sizeof(int *));
AnecessarypreconN = (int **)statmalloc(301,nOfActions * sizeof(int *));
AforcedeffectsP = (int **)statmalloc(302,nOfActions * sizeof(int *));
AforcedeffectsN = (int **)statmalloc(303,nOfActions * sizeof(int *));
AeffectoccP = (int **)statmalloc(304,nOfAtoms * sizeof(int *));
AeffectoccN = (int **)statmalloc(305,nOfAtoms * sizeof(int *));
ApreconoccP = (int **)statmalloc(306,nOfAtoms * sizeof(int *));
ApreconoccN = (int **)statmalloc(307,nOfAtoms * sizeof(int *));
Acondocc = (int **)statmalloc(308,nOfAtoms * sizeof(int *));
arrayfordata = (int *)statmalloc(309,allocsize * sizeof(int));
#ifdef ASSERTS
assert(arrayfordata != NULL);
#endif
fill = arrayfordata;
/* Fill the massive array, and put pointers to the individual atom's
and actions's arrays. */
for(i=0;i<nOfActions;i++) {
movearraydata(i,necessarypreconP,AnecessarypreconP,&fill);
movearraydata(i,necessarypreconN,AnecessarypreconN,&fill);
movearraydata(i,forcedeffectsP,AforcedeffectsP,&fill);
movearraydata(i,forcedeffectsN,AforcedeffectsN,&fill);
}
free(necessarypreconP);
free(necessarypreconN);
free(forcedeffectsP);
free(forcedeffectsN);
for(i=0;i<nOfAtoms;i++) {
movearraydata(i,effectoccP,AeffectoccP,&fill);
movearraydata(i,effectoccN,AeffectoccN,&fill);
movearraydata(i,preconoccP,ApreconoccP,&fill);
movearraydata(i,preconoccN,ApreconoccN,&fill);
movearraydata(i,condocc,Acondocc,&fill);
}
free(effectoccP);
free(effectoccN);
free(preconoccP);
free(preconoccN);
free(condocc);
// for(i=0;i<nOfAtoms*2;i++) {
// movearraydata(i,preconocc,Apreconocc,&fill);
// }
}
/* Check if a formula is a conjunction of 1 or more atomic formulas. */
int conjunctivep(fma *f) {
fmalist *fs;
switch(f->t) {
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");
}