Improve precision of interference analysis. Allow sizeof(v.r1.r2) expressions.
[repair.git] / Repair / RepairInterpreter / processobject.cc
1 // evaluates constraints in the ICL
2
3 #include <stdlib.h>
4 #include "processobject.h"
5 #include "processabstract.h"
6 #include "omodel.h"
7 #include "Hashtable.h"
8 #include "element.h"
9 #include "model.h"
10 #include "dmodel.h"
11 #include "set.h"
12 #include "Relation.h"
13 #include "repair.h"
14 #include "normalizer.h"
15 #include "Action.h"
16
17 static int modelcheck=0;
18 static int modeltrigger=0;
19
20 processobject::processobject(model *m) {
21   globalmodel=m;
22   repair=m->getrepair();
23 }
24
25 void processobject::printstats() {
26   printf("Models Rules Checked: %d Triggered: %d\n",modelcheck,modeltrigger);
27 }
28
29 // evaluates the truth value of the given predicate
30 int processobject::processpredicate(Predicate *p, Hashtable *env) {
31   switch(p->gettype()) {
32   case PREDICATE_LT: {
33     Element *left=evaluatevalueexpr(p->getvalueexpr(),env,globalmodel);
34     Element *right=evaluateexpr(p->geteleexpr(),env,globalmodel);
35     if (right==NULL) {
36       return PFAIL;
37     }
38     if (left==NULL) {
39       delete(right);
40       return false;
41     }
42     int t=left->intvalue()<right->intvalue();
43     delete(right);
44     return t;
45   }
46   case PREDICATE_LTE: {
47     Element *left=evaluatevalueexpr(p->getvalueexpr(),env,globalmodel);
48     Element *right=evaluateexpr(p->geteleexpr(),env,globalmodel);
49     if (right==NULL) {return PFAIL;}
50     if (left==NULL) {
51       delete(right);
52       return false;
53     }
54     bool t=left->intvalue()<=right->intvalue();
55     delete(right);
56     return t;
57   }
58   case PREDICATE_EQUALS: {
59     Element *left=evaluatevalueexpr(p->getvalueexpr(),env,globalmodel);
60     Element *right=evaluateexpr(p->geteleexpr(),env,globalmodel);
61     if (right==NULL) {return PFAIL;}
62     if (left==NULL) {
63       delete(right);
64       return false;
65     }
66     /* Can have more than just int's here */
67     bool t=left->equals(right); /*Just ask the equals method*/
68     delete(right);
69     return t;
70   }
71   case PREDICATE_GTE: {
72     Element *left=evaluatevalueexpr(p->getvalueexpr(),env,globalmodel);
73     Element *right=evaluateexpr(p->geteleexpr(),env,globalmodel);
74     if (right==NULL) {return PFAIL;}
75     if (left==NULL) {
76       delete(right);
77       return false;
78     }
79     bool t=left->intvalue()>=right->intvalue();
80     delete(right);
81     return t;
82   }
83   case PREDICATE_GT: {
84     Element *left=evaluatevalueexpr(p->getvalueexpr(),env,globalmodel);
85     Element *right=evaluateexpr(p->geteleexpr(),env,globalmodel);
86     if (right==NULL) {return PFAIL;}
87     if (left==NULL) {
88       delete(right);
89       return false;
90     }
91     bool t=left->intvalue()>right->intvalue();
92     delete(right);
93     return t;
94   }
95   case PREDICATE_SET: {
96     Label *label=p->getlabel();
97     Setexpr * setexpr=p->getsetexpr();
98     Element *labelele=(Element *) env->get(label->label());
99     switch(setexpr->gettype()) {
100       case SETEXPR_LABEL:
101         return globalmodel->getdomainrelation()->getset(setexpr->getsetlabel()->getname())->getset()->contains(labelele);
102       case SETEXPR_REL:
103         return globalmodel->getdomainrelation()->getrelation(setexpr->getrelation()->getname())->getrelation()->getset(setexpr->getlabel()->label())->contains(labelele);
104       case SETEXPR_INVREL:
105         return globalmodel->getdomainrelation()->getrelation(setexpr->getrelation()->getname())->getrelation()->invgetset(setexpr->getlabel()->label())->contains(labelele);
106     }
107   }
108   case PREDICATE_EQ1:
109   case PREDICATE_GTE1: {
110     int setsize;
111     Setexpr * setexpr=p->getsetexpr();
112     switch(setexpr->gettype()) {
113     case SETEXPR_LABEL:
114       setsize=globalmodel->getdomainrelation()->getset(setexpr->getsetlabel()->getname())->getset()->size();
115       break;
116     case SETEXPR_REL: {
117       Element *key=(Element *)env->get(setexpr->getlabel()->label());
118       WorkSet *ws=globalmodel->getdomainrelation()->getrelation(setexpr->getrelation()->getname())->getrelation()->getset(key);
119       if (ws!=NULL)
120         setsize=ws->size();
121       else
122         setsize=0;
123       break;
124     }
125     case SETEXPR_INVREL: {
126       Element *key=(Element *)env->get(setexpr->getlabel()->label());
127       WorkSet *ws=globalmodel->getdomainrelation()->getrelation(setexpr->getrelation()->getname())->getrelation()->invgetset(key);
128       if (ws!=NULL)
129         setsize=ws->size();
130       else
131         setsize=0;
132       break;
133     }
134     }
135     return ((p->gettype()==PREDICATE_EQ1)&&(setsize==1))||
136       ((p->gettype()==PREDICATE_GTE1)&&(setsize>=1));
137   }
138   }
139 }
140
141
142 // evaluates the truth value of the given statement
143 int processobject::processstatement(Statement *s, Hashtable *env) {
144   switch (s->gettype()) {
145   case STATEMENT_OR: {
146     int l=processstatement(s->getleft(),env);
147     int r=processstatement(s->getright(),env);
148     if (l==PFAIL&&(r==PFAIL||r==PFALSE)) return PFAIL;
149     if ((l==PFAIL||l==PFALSE)&&r==PFAIL) return PFAIL;
150     return l||r;
151   }
152   case STATEMENT_AND: {
153     int l=processstatement(s->getleft(),env);
154     int r=processstatement(s->getright(),env);
155     if (l==PFAIL&&(r==PFAIL||r==PTRUE)) return PFAIL;
156     if (r==PFAIL&&(l==PFAIL||l==PTRUE)) return PFAIL;
157     return l&&r;
158   }
159   case STATEMENT_NOT: {
160     int l=processstatement(s->getleft(),env);
161     if (l==PFAIL) return PFAIL;
162     return !l;
163   }
164   case STATEMENT_PRED:
165     return processpredicate(s->getpredicate(),env);
166   }
167 }
168
169
170 // returns true if and only if the given constraint is satisfied 
171 bool processobject::issatisfied(Constraint *c) 
172 {
173   State *st=new State(c,globalmodel->gethashtable());
174   bool satisfied = true;
175   if (st->initializestate(globalmodel))
176     while (true)
177       {      
178         if (c->getstatement()!=NULL)
179           if (processstatement(c->getstatement(),st->env)!=PTRUE) 
180             satisfied = false;
181         if (!st->increment(globalmodel))
182             break;
183       }
184
185   delete(st);
186   return satisfied;
187 }
188
189
190
191 /* processed the given constraint and if it's not satisfied, 
192    displays a message and tries to repair the constraint 
193    The function returns true only if the constraint was initially
194    satisfied. */
195 bool processobject::processconstraint(Constraint *c) {
196   State *st=new State(c,globalmodel->gethashtable());
197   bool clean=true;
198   if (st->initializestate(globalmodel)) {
199     while(true) {
200       if (c->getstatement()!=NULL) {
201         modelcheck++;
202         if (processstatement(c->getstatement(),st->env)!=PTRUE) {
203           modeltrigger++;
204 #ifdef TOOL
205           printf("Constraint violation\n");
206           printf("   Violated constraint: "); c->print();
207           printf("   State for which it was violated: "); st->print(globalmodel);
208           printf("  Current value(s):");
209           c->getstatement()->print_sets(st->env, globalmodel);
210           printf("\n\n");
211           return false;
212 #endif
213
214 #ifdef REPAIR
215           printf("Repairing...\n");
216           if (c->getcrash()) {
217             printf("Fatal program error violating special constraint.\n");
218             exit(-1);
219           }
220           repair->repairconstraint(c,this,st->env);
221           clean=false;
222 #endif
223         }
224       }
225
226       if (!st->increment(globalmodel))
227         break; /* done */
228     }
229   }
230   delete(st);
231   return clean;
232 }
233
234
235
236 /* breaks the given constraint by invalidating each of its satisfied sentences */
237 void processobject::breakconstraint(Constraint *c)
238 {  
239 #ifdef DEBUGMESSAGES
240   printf("Constraint to be broken: ");
241   c->print();
242   printf("\n");
243   fflush(NULL);
244 #endif
245
246   // first, get get the constraint in normal form
247   NormalForm *nf = globalmodel->getnormalform(c);
248
249   // for each CoerceSentence in nf, find if it's satisfied. If so, break it.
250   for (int i=0; i<nf->getnumsentences(); i++)
251     {
252 #ifdef DEBUGMESSAGES
253       printf("In processobject::breakconstraint, i=%d \n", i);
254       fflush(NULL);
255 #endif
256
257       CoerceSentence *s = nf->getsentence(i);
258       
259       // find if s is satisfied
260       bool satisfied = true;
261       State *st = new State(c, globalmodel->gethashtable());
262       if (st->initializestate(globalmodel))
263         while(true) 
264           {
265             if (!s->issatisfied(this, st->env))
266               satisfied=false;
267
268             if (!st->increment(globalmodel))
269               break;
270           }  
271       delete(st);
272       
273
274       // if s is satisfied, then break it
275
276       if (satisfied)
277         {
278           // first, select an arbitrary binding, for ex. the first one
279           st = new State(c, globalmodel->gethashtable());
280           
281           if (st->initializestate(globalmodel))
282             {
283 #ifdef DEBUGMESSAGES
284               printf("numpredicates = %d\n", s->getnumpredicates());
285 #endif
286               
287               for (int j=0; j<s->getnumpredicates(); j++)
288                 {
289                   CoercePredicate *cp = s->getpredicate(j);
290                   // break this predicate with probability prob_breakpredicate
291                   if (random()<model::prob_breakpredicate*RAND_MAX)
292                     {
293 #ifdef DEBUGMESSAGES
294                       printf("po::breakconstraint:  We break predicate %d\n",j);
295                       fflush(NULL);
296 #endif
297                       
298                       Action *action = repair->findbreakaction(cp);
299                       action->breakpredicate(st->env, cp);
300                       
301 #ifdef DEBUGMESSAGES
302                       printf("After action->breakpredicate was called\n");
303                       fflush(NULL);
304 #endif
305                     }
306                 }
307             }
308           
309           delete(st);
310         }
311     }
312 }
313
314
315
316 /* satisfies the given satisfied contraint in another way */
317 void processobject::modifyconstraint(Constraint *c)
318 {
319 #ifdef DEBUGMESSAGES
320   printf("Constraint to be modified: ");
321   c->print();
322   printf("\n");
323   fflush(NULL);
324 #endif
325
326   // first, get the constraint in normal form
327   NormalForm *nf = globalmodel->getnormalform(c);
328
329   /* for each CoerceSentence in nf, find if it's satisfied. 
330      If it's satisfied, we break it with probability prob_breaksatisfiedsentence;
331      If it's not satisfied, we repair it with probability prob_repairbrokensentence
332   */
333
334   bool still_valid = false;
335
336   for (int i=0; i<nf->getnumsentences(); i++)
337     {
338 #ifdef DEBUGMESSAGES
339       printf("In processobject::modifyconstraint, i=%d \n", i);
340       fflush(NULL);
341 #endif
342
343       CoerceSentence *s = nf->getsentence(i);
344       
345       // find if s is satisfied
346       bool satisfied = true;
347       State *st = new State(c, globalmodel->gethashtable());
348       if (st->initializestate(globalmodel))
349         while(true) 
350           {
351             if (!s->issatisfied(this, st->env))
352               satisfied=false;
353
354             if (!st->increment(globalmodel))
355               break;
356           }  
357       delete(st);
358       
359       // if s is satisfied, then break it
360       if  (satisfied)
361         if (random()<model::prob_breaksatisfiedsentence*RAND_MAX) // then break it
362           {
363             // first, select an arbitrary binding, for ex. the first one
364             st = new State(c, globalmodel->gethashtable());
365             
366             if (st->initializestate(globalmodel))
367               {
368                 for (int j=0; j<s->getnumpredicates(); j++)
369                   {
370                     CoercePredicate *cp = s->getpredicate(j);
371                     // break this predicate with probability prob_breakpredicate
372                     if (random()<model::prob_breakpredicate*RAND_MAX)
373                       {
374 #ifdef DEBUGMESSAGES
375                         printf("po::modifyconstraint:  We break predicate %d\n",j);
376                         fflush(NULL);
377 #endif
378                         
379                         Action *action = repair->findbreakaction(cp);
380                         action->breakpredicate(st->env, cp);
381                         
382 #ifdef DEBUGMESSAGES
383                         printf("After action->modifypredicate was called\n");
384                         fflush(NULL);
385 #endif
386                       }
387                   }
388               }
389             delete(st);
390           }
391         else still_valid = true;
392       else // if not satisfied, then repair it with prob_repairbrokensentence
393         if (random()<model::prob_repairbrokensentence)
394           {
395             // first, select an arbitrary binding, for ex. the first one
396             st = new State(c, globalmodel->gethashtable());
397             
398             if (st->initializestate(globalmodel))
399               {
400                 for (int j=0; j<s->getnumpredicates(); j++)
401                   {
402                     CoercePredicate *cp = s->getpredicate(j);
403                     Action *action = repair->findrepairaction(cp);
404                     action->repairpredicate(st->env, cp);
405                         
406 #ifdef DEBUGMESSAGES
407                         printf("After action->repairpredicate was called\n");
408                         fflush(NULL);
409 #endif
410                   }
411               }
412             
413             delete(st);     
414             still_valid = true;
415           }
416     }
417
418   if (!still_valid) // if all sentences are broken, repair the first one
419     {
420       CoerceSentence *saux = nf->getsentence(0);
421       // first, select an arbitrary binding, for ex. the first one
422       State *st = new State(c, globalmodel->gethashtable());
423       
424       if (st->initializestate(globalmodel))
425         {
426           for (int j=0; j<saux->getnumpredicates(); j++)
427             {
428               CoercePredicate *cp = saux->getpredicate(j);
429               Action *action = repair->findrepairaction(cp);
430               action->repairpredicate(st->env, cp);
431               
432 #ifdef DEBUGMESSAGES
433               printf("After action->repairpredicate was called\n");
434               fflush(NULL);
435 #endif
436             }
437         }
438       
439       delete(st);           
440     }
441   
442 }
443
444
445 processobject::~processobject() {
446 }
447
448
449 // computes ve = V.R
450 Element * evaluatevalueexpr(Valueexpr *ve, Hashtable *env, model *m) {
451   Element *e=NULL;
452   if (ve->gettype()==0) {
453     e=(Element *) env->get(ve->getlabel()->label());
454   } else
455     e=evaluatevalueexpr(ve->getvalueexpr(),env,m);
456   if (e==NULL)
457     return e;
458   if (ve->getinverted())
459     return (Element *)m->getdomainrelation()->getrelation(ve->getrelation()->getname())->getrelation()->invgetobj(e);
460   else
461     return (Element *)m->getdomainrelation()->getrelation(ve->getrelation()->getname())->getrelation()->getobj(e);
462 }
463
464
465
466 // evaluates E = V | number | string | E-E | E+E | E*E | E/E | E.R |size(SE)
467 Element * evaluateexpr(Elementexpr *ee, Hashtable *env, model *m) {
468   switch(ee->gettype()) {
469   case ELEMENTEXPR_LABEL: {
470     return new Element((Element *)env->get(ee->getlabel()->label()));
471   }
472   case ELEMENTEXPR_SUB: {
473     Elementexpr *left=ee->getleft();
474     Elementexpr *right=ee->getright();
475     Element *leftval=evaluateexpr(left,env,m);
476     if(leftval==NULL) return NULL;
477     Element *rightval=evaluateexpr(right,env,m);
478     if(rightval==NULL) {delete(leftval);return NULL;}
479     Element *diff=new Element(leftval->intvalue()-rightval->intvalue());
480     delete(leftval);delete(rightval);
481     return diff;
482   }
483   case ELEMENTEXPR_ADD: {
484     Elementexpr *left=ee->getleft();
485     Elementexpr *right=ee->getright();
486     Element *leftval=evaluateexpr(left,env,m);
487     if(leftval==NULL) return NULL;
488     Element *rightval=evaluateexpr(right,env,m);
489     if(rightval==NULL) {delete(leftval);return NULL;}
490     Element *sum=new Element(leftval->intvalue()+rightval->intvalue());
491     delete(leftval);delete(rightval);
492     return sum;
493   }
494   case ELEMENTEXPR_RELATION: {
495     Elementexpr *left=ee->getleft();
496     Relation *rel=ee->getrelation();
497     Element *leftval=evaluateexpr(left,env,m);
498     if(leftval==NULL) return NULL;
499     Element *retval=(Element *)m->getdomainrelation()->getrelation(rel->getname())->getrelation()->getobj(leftval);
500     delete(leftval);
501     return new Element(retval);
502   }
503   case ELEMENTEXPR_MULT: {
504     Elementexpr *left=ee->getleft();
505     Elementexpr *right=ee->getright();
506     Element *leftval=evaluateexpr(left,env,m);
507     if(leftval==NULL) return NULL;
508     Element *rightval=evaluateexpr(right,env,m);
509     if(rightval==NULL) {delete(leftval);return NULL;}
510     Element *diff=new Element(leftval->intvalue()*rightval->intvalue());
511     delete(leftval);delete(rightval);
512     return diff;
513   }
514   case ELEMENTEXPR_LIT: {
515     Literal *l=ee->getliteral();
516     switch(l->gettype()) {
517     case LITERAL_NUMBER:
518       return new Element(l->number());
519     case LITERAL_TOKEN:
520       return new Element(copystr(l->token()));
521     default:
522       printf("ERROR with lit type\n");
523       exit(-1);
524     }
525   }
526   /*  case ELEMENTEXPR_PARAM: {
527     Element *ele=evaluateexpr(ee->getleft(),env,m);
528     Element *eec=ele->paramvalue(ee->getliteral()->number());
529     Element *retval=new Element(eec);
530     delete(ele);
531     return eec;
532     }*/ //NO OBJECT PARAMETERS
533   case ELEMENTEXPR_SETSIZE:
534     Setexpr * setexpr=ee->getsetexpr();
535     switch(setexpr->gettype()) {
536     case SETEXPR_LABEL:
537       return new Element(m->getdomainrelation()->getset(setexpr->getsetlabel()->getname())->getset()->size());
538     case SETEXPR_REL: {
539       Element *key=(Element *)env->get(setexpr->getlabel()->label());
540       WorkSet *ws=m->getdomainrelation()->getrelation(setexpr->getrelation()->getname())->getrelation()->getset(key);
541       if (ws==NULL)
542         return new Element(0);
543       else
544         return new Element(ws->size());
545     }
546     case SETEXPR_INVREL: {
547       Element *key=(Element *)env->get(setexpr->getlabel()->label());
548       WorkSet *ws=m->getdomainrelation()->getrelation(setexpr->getrelation()->getname())->getrelation()->invgetset(key);
549       if (ws==NULL)
550         return new Element(0);
551       else
552         return new Element(ws->size());
553     }
554     }
555     break;
556   }
557 }