Improve precision of interference analysis. Allow sizeof(v.r1.r2) expressions.
[repair.git] / Repair / RepairInterpreter / ActionAssign.cc
1 // handles prediate of the following forms: VE<E, VE<=E, VE=E, VE>=E, VE>E
2
3 #include <stdlib.h>
4 #include <assert.h>
5 #include "ActionAssign.h"
6 #include "dmodel.h"
7 #include "normalizer.h"
8 #include "omodel.h"
9 #include "Relation.h"
10 #include "set.h"
11 #include "Hashtable.h"
12 #include "model.h"
13 #include "processobject.h"
14 #include "element.h"
15 #include "common.h"
16
17
18 ActionAssign::ActionAssign(DomainRelation *drel, model *m) {
19   domrelation=drel;
20   globalmodel=m;
21 }
22
23 char * ActionAssign::gettype(Constraint *c,Elementexpr *ee) {
24   switch(ee->gettype()) {
25   case ELEMENTEXPR_LABEL:
26     return getset(c,ee->getlabel()->label());
27   case ELEMENTEXPR_SUB:
28   case ELEMENTEXPR_ADD:
29   case ELEMENTEXPR_MULT:
30     return "int";
31   case ELEMENTEXPR_LIT: {
32     Literal *lit=ee->getliteral();
33     switch(lit->gettype()) {
34     case LITERAL_NUMBER:
35       return "int";
36     case LITERAL_TOKEN:
37       return "token";
38     case LITERAL_BOOL:
39       printf("ERROR in gettype\n");
40       exit(-1);
41     }
42   }
43   case ELEMENTEXPR_SETSIZE:
44     return "int";
45   case ELEMENTEXPR_RELATION: {
46     Relation *r=ee->getrelation();
47     DomainRelation *drel=globalmodel->getdomainrelation();
48     return drel->getrelation(r->getname())->getrange();
49   }
50   }
51 }
52
53
54 // repairs the given predicate
55 void ActionAssign::repairpredicate(Hashtable *env, CoercePredicate *cp) {
56   Predicate *p=cp->getpredicate();
57   Element *ele=evaluateexpr(p->geteleexpr(),env,globalmodel); //ele=E
58   Element *index=(Element *) env->get(p->getvalueexpr()->getlabel()->label()); // index=V
59   char *rel=p->getvalueexpr()->getrelation()->getname(); // rel=R
60   WorkRelation *relation=domrelation->getrelation(rel)->getrelation();
61   Element *old=(Element *)relation->getobj(index); // old=V.R
62   if (old!=NULL)
63     relation->remove(index,old);
64   DRelation *drel=domrelation->getrelation(rel);
65   
66   if(!equivalentstrings(drel->getdomain(),"int")) {
67     DomainSet *domain=domrelation->getset(drel->getdomain());
68     if (!domain->getset()->contains(index))
69       domrelation->addtoset(index,domain,globalmodel);
70     }
71
72
73   switch (p->gettype()) {
74   case PREDICATE_LT: {
75     Element *ele2=new Element(ele->intvalue()-1);
76     delete(ele);
77     relation->put(index,ele2);
78     break;
79   }
80   case PREDICATE_LTE: {
81     relation->put(index,ele);
82     break;
83   }
84   case PREDICATE_EQUALS: {
85     relation->put(index,ele);
86     if(!equivalentstrings(drel->getrange(),"int")&&
87        !equivalentstrings(drel->getrange(),"token")) {
88       DomainSet *range=domrelation->getset(drel->getrange());
89       if (!range->getset()->contains(ele))
90         domrelation->addtoset(ele,range,globalmodel);
91     }
92     break;
93   }
94   case PREDICATE_GTE: {
95     relation->put(index,ele);
96     break;
97   }
98   case PREDICATE_GT: {
99     Element *ele2=new Element(ele->intvalue()+1);
100     delete(ele);
101     relation->put(index,ele2);
102     break;
103   }
104   }
105 }
106
107
108
109 void ActionAssign::breakpredicate(Hashtable *env, CoercePredicate *cp)
110 {
111 #ifdef DEBUGMESSAGES
112   printf("ActionAssign::breakpredicate CALLED\n");
113   cp->getpredicate()->print(); printf("\n");
114 #endif
115
116   Predicate *p = cp->getpredicate();
117   Element *ele = evaluateexpr(p->geteleexpr(),env,globalmodel); //ele=E
118   Element *index = (Element *) env->get(p->getvalueexpr()->getlabel()->label()); // index=V
119
120
121 #ifdef DEBUGMESSAGES
122   printf("index=%s\n", p->getvalueexpr()->getlabel()->label());
123   if (index == NULL)    
124     printf("index - bad\n");
125   else printf("index - ok\n");
126 #endif
127   
128   char *rel = p->getvalueexpr()->getrelation()->getname(); // rel=R
129   WorkRelation *relation = domrelation->getrelation(rel)->getrelation();
130
131 #ifdef DEBUGMESSAGES
132   if (relation == NULL)    
133     printf("relation - bad\n");
134   else printf("relation - ok\n");
135   fflush(NULL);
136 #endif
137
138   Element *old_ve = (Element *)relation->getobj(index); // old_ve=V.R
139
140   if (old_ve!=NULL)
141     relation->remove(index,old_ve);
142   DRelation *drel = domrelation->getrelation(rel);
143   
144   if(!equivalentstrings(drel->getdomain(),"int")) 
145     {
146       DomainSet *domain = domrelation->getset(drel->getdomain());
147       if (!domain->getset()->contains(index))
148         domrelation->addtoset(index,domain,globalmodel);
149     }
150
151 #ifdef DEBUGMESSAGES
152   printf("p->gettype() = %d\n", p->gettype());
153   fflush(NULL);
154 #endif
155
156
157   switch (p->gettype()) {
158   // VE<E
159   case PREDICATE_LT: 
160     {
161       // set VE=E which breaks VE<E
162       Element *newele=new Element(ele->intvalue());
163       delete(ele);
164       relation->put(index,newele);
165       break;
166     }
167
168   // VE<=E
169   case PREDICATE_LTE: 
170     {
171       // set VE=E+1, which breaks VE<=E
172       Element *newele=new Element(ele->intvalue()+1);
173       delete(ele);
174       relation->put(index,newele);
175       break;
176     }
177
178   // VE=E
179   case PREDICATE_EQUALS: 
180     {      
181       DRelation *drel=domrelation->getrelation(rel);      
182
183       // if the V.R is an integer, set VE=E+1, which breaks VE=E
184       if (equivalentstrings(drel->getrange(),"int")) 
185         {
186           Element *newele=new Element(ele->intvalue()+1);
187           delete(ele);
188           relation->put(index,newele);
189         }
190       else 
191         {
192           Element *newele = NULL;
193           printf("PREDICATE_EQUALS for tokens\n");
194           //printf("range name = %s\n", drel->getrange()); fflush(NULL);
195           //printf("Current value: ");  old_ve->print();  printf("\n");
196
197           /* find a value in the actual range that is different from the
198              current value of V.R */
199           char* old_token = old_ve->gettoken();
200           WorkSet *ws = drel->gettokenrange();
201           bool found = false;
202           char *token = (char*) ws->firstelement();
203           while (token)
204             {
205               printf("Token: %s\n", token);
206               if (!equivalentstrings(token, old_token))
207                 {
208                   found = true;
209                   newele = new Element(token);
210                   break;
211                 }             
212               token = (char*) ws->getnextelement(token);
213             }
214
215           if (!found)
216             {
217               printf("The following predicate cannot be broken:");
218               cp->getpredicate()->print(); printf("\n");
219             }
220           else relation->put(index, newele);
221
222           fflush(NULL);
223           printf("\n\n");                       
224         }
225       break;
226     }
227
228   // VE>=E
229   case PREDICATE_GTE: 
230     {
231       // set VE=E-1, which breaks VE>=E
232       Element *newele=new Element(ele->intvalue()-1);
233       delete(ele);
234       relation->put(index,newele);
235       break;
236     }
237
238   // VE>E
239   case PREDICATE_GT: 
240     {
241       // set VE=E, which breaks VE>E
242       Element *newele=new Element(ele->intvalue());
243       delete(ele);
244       relation->put(index,newele);
245       break;
246     }
247   }
248 }
249
250
251
252 bool ActionAssign::conflict(Constraint *c1, CoercePredicate *p1,Constraint *c2, CoercePredicate *p2) {
253   assert(canrepairpredicate(p1));
254   if(comparepredicates(c1,p1,c2,p2))
255     return false; /*same predicates don't conflict*/
256   /* we have v.r?a */
257   /* add <v,?> to r */
258
259   /* Compute bounding set if there is one */
260   
261   
262   DomainRelation *drel=globalmodel->getdomainrelation();
263   char *insertset=drel->getrelation(p1->getpredicate()->getvalueexpr()->getrelation()->getname())->getrange();
264   
265   char *boundset=gettype(c1,p1->getpredicate()->geteleexpr());
266   
267   /* Check conflicts arrising from addition to set */
268   {
269     WorkSet *ws=domrelation->conflictaddsets(insertset,NULL,globalmodel);
270     DomainSet *ds=(DomainSet *) ws->firstelement();
271     while(ds!=NULL) {
272       if (conflictwithaddtoset(ds->getname(),c2,p2)) {
273         delete(ws);
274         return true;
275       }
276       ds=(DomainSet *) ws->getnextelement(ds);
277     }
278     delete(ws);
279   }
280   /* Check conflicts arrising from deletions from set */
281   {
282     WorkSet *ws=domrelation->conflictdelsets(insertset, NULL);    
283     DomainSet *ds=(DomainSet *) ws->firstelement();
284     while (ds!=NULL) {
285       if (conflictwithremovefromset(NULL,ds->getname(),c2,p2)) {
286         delete(ws);
287         return true;
288       }
289       ds=(DomainSet *) ws->getnextelement(ds);
290     }
291     delete(ws);
292   }
293   return testforconflict(getset(c1,p1->getpredicate()->getvalueexpr()->getlabel()->label()), NULL,
294                          p1->getpredicate()->getvalueexpr()->getrelation()->getname(),c2,p2)||
295     testforconflictremove(getset(c1,p1->getpredicate()->getvalueexpr()->getlabel()->label()), NULL,
296                           p1->getpredicate()->getvalueexpr()->getrelation()->getname(),c2,p2);
297 }
298
299 bool ActionAssign::canrepairpredicate(CoercePredicate *cp) {
300   if (cp->getcoercebool()==false)
301     return false;
302   Predicate *p=cp->getpredicate();
303   if (p==NULL)
304     return false;
305   if (p->gettype()==PREDICATE_LT||
306       p->gettype()==PREDICATE_LTE||
307       p->gettype()==PREDICATE_EQUALS||
308       p->gettype()==PREDICATE_GTE||
309       p->gettype()==PREDICATE_GT) {
310     Valueexpr *ve=p->getvalueexpr();
311     DRelation *dr=domrelation->getrelation(ve->getrelation()->getname());
312     if (dr->isstatic()) /* can't change static relations */
313       return false;
314     else
315       return true;
316   }  
317   /* Coercing set membership */
318   return false;
319 }