madagascar/ground.c

813 lines
18 KiB
C

/* 2012 (C) Jussi Rintanen jrintanen.jr@gmail.com */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#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;i<nOfSActions;i++) {
#ifdef DEBUG
printf("BEFORE:\n");
if(flagShowInput) printSaction(&Sactions[i]);
#endif
qdepth = 0;
ps = Sactions[i].params;
while(ps != NULL) {
#ifdef DEBUG
printf("scope[%i] = %s\n",qdepth,symbol(ps->v));
#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;j<a[1]+2;j++) { /* Go through parameters. */
/* Is it unassigned or a match. */
if(assignedvar(a[j],i) && ((*as)[j] != binding[-1-a[j]])) {
goto nextinitatom; /* Did not match. */
}
}
#ifdef DEBUG
printf("MATCH!\n");
#endif
return 1;
}
nextinitatom:
as = as + 1;
}
#ifdef DEBUG
printf("NO MATCH!\n");
#endif
return 0;
}
int legalstaticbinding(int i,Sfma *f) {
Sfmalist *fs;
switch(f->t) {
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;j<f->a[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<initlit[1];i++) {
if(assignedvar(patom[i+2],param-1) && (binding[-1-patom[i+2]] != initlit[i+2])) return 0;
if(patom[i+2] == -1-param) *value = initlit[i+2];
}
assert(*value != -1);
return 1;
}
void findrelevantbindings(int i,Sfma *f) {
int cnt,j;
int value;
atom *as;
litcnt = 0;
cnt = 0;
/* Identify literals that have to be matched. */
printf("Positive literals with parameter %i are:",i);
identifyposlits(i,f);
assert(litcnt > 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;j<cnt;j++) {
if(relevantbindings[j] == value) goto hadalready;
}
relevantbindings[cnt++] = value;
printf(" %s OK",symbol(relevantbindings[cnt-1]));
}
hadalready:
printf("\n");
as = as + 1;
}
printf("\n");
relevantbindings[cnt] = -1; /* The list is terminated with -1. */
}
#endif
/* produce list with parameter values */
void copybindings(int *dest,int *binding,int bindings) {
int i;
for(i=0;i<bindings;i++) dest[i] = binding[i];
dest[bindings] = -1;
}
/* Go through all bindings.
i which variable to bind (0..nOfBindings-1)
sc which schema are we instantiating
domains[] the values for each of the variables 0..nOfBindings-1
staticrestriction whether variable i is restricted by a static fact
*/
void NEWgothrough(int i,int sc,int **domains,int *staticrestriction) {
if(i < nOfBindings) { /* base case, instantiate */
int *l = domains[i]; /* Values in the domain for the ith variable. */
/* Some of the variables are limited by their occurrence in a static
predicate that is a necessary precondition. In those cases go
only through the allowed values of the variable. */
if(staticrestriction[i]) { /* Restricted by a static predicate. */
#ifdef NEWSTATICB
/* Find relevant bindings by one traversal of the initial literals. */
findrelevantbindings(i,Sactions[sc].precon);
l = &relevantbindings;
#endif
/* PROBLEM: This can be really bad. Why don't you just generate
sensible bindings by going through the initial state, rather
than go through all possible domain values and test for each
whether it is sanctioned by the initial state? */
while(*l != -1) {
binding[i] = *l;
// printf("(%s)",symbol(l->hd));
#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;j<f->a[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;i<nOfSActions;i++) {
typedvarlist *params = Sactions[i].params;
typedvarlist *l = params;
if(flagShowInput) {
printf("Grounding schema %i:%s\n",i,symbol(Sactions[i].name));
printSaction(&Sactions[i]);
}
/* Fetch domains of the parameters */
nOfBindings = 0;
while(l != NULL) {
staticrestriction[nOfBindings] = occursinstatic(nOfBindings,Sactions[i].precon);
#ifdef DEBUG
if(staticrestriction[nOfBindings]) {
printf("Parameter %i is static.\n",nOfBindings);
printSaction(&Sactions[i]);
} else { printf("."); }
#endif
#ifdef ASSERTS
assert(isvar(l->v));
#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<nOfAtoms;i++) initialstate[i] = 0;
al = Sinit;
while(*al != NULL) {
j = atomindex(*al,NULL);
initialstate[j] = 1;
#ifdef ASSERTS
assert(j>=0); assert(j<nOfAtoms);
#endif
al = al + 1;
}
}