fixing more bugs ...
[satune.git] / src / Backend / satencoder.c
1 #include "satencoder.h"
2 #include "structs.h"
3 #include "csolver.h"
4 #include "boolean.h"
5 #include "constraint.h"
6 #include "common.h"
7 #include "element.h"
8 #include "function.h"
9 #include "tableentry.h"
10 #include "table.h"
11 #include "order.h"
12 #include "predicate.h"
13 #include "orderpair.h"
14 #include "set.h"
15
16 SATEncoder * allocSATEncoder() {
17         SATEncoder *This=ourmalloc(sizeof (SATEncoder));
18         This->varcount=1;
19         This->satSolver = allocIncrementalSolver();
20         return This;
21 }
22
23 void deleteSATEncoder(SATEncoder *This) {
24         deleteIncrementalSolver(This->satSolver);
25         ourfree(This);
26 }
27
28 Constraint * getElementValueConstraint(SATEncoder* encoder,Element* This, uint64_t value) {
29         generateElementEncodingVariables(encoder, getElementEncoding(This));
30         switch(getElementEncoding(This)->type){
31                 case ONEHOT:
32                         //FIXME
33                         ASSERT(0);
34                         break;
35                 case UNARY:
36                         ASSERT(0);
37                         break;
38                 case BINARYINDEX:
39                         return getElementValueBinaryIndexConstraint(This, value);
40                         break;
41                 case ONEHOTBINARY:
42                         ASSERT(0);
43                         break;
44                 case BINARYVAL:
45                         ASSERT(0);
46                         break;
47                 default:
48                         ASSERT(0);
49                         break;
50         }
51         return NULL;
52 }
53 Constraint * getElementValueBinaryIndexConstraint(Element* This, uint64_t value) {
54         ASTNodeType type = GETELEMENTTYPE(This);
55         ASSERT(type == ELEMSET || type == ELEMFUNCRETURN);
56         ElementEncoding* elemEnc = getElementEncoding(This);
57         for(uint i=0; i<elemEnc->encArraySize; i++){
58                 if( isinUseElement(elemEnc, i) && elemEnc->encodingArray[i]==value){
59                         return generateBinaryConstraint(elemEnc->numVars,
60                                 elemEnc->variables, i);
61                 }
62         }
63         return NULL;
64 }
65
66 void addConstraintToSATSolver(Constraint *c, IncrementalSolver* satSolver) {
67         VectorConstraint* simplified = simplifyConstraint(c);
68         uint size = getSizeVectorConstraint(simplified);
69         for(uint i=0; i<size; i++) {
70                 Constraint *simp=getVectorConstraint(simplified, i);
71                 if (simp->type==TRUE)
72                         continue;
73                 ASSERT(simp->type!=FALSE);
74                 dumpConstraint(simp, satSolver);
75         }
76         deleteVectorConstraint(simplified);
77 }
78
79 void encodeAllSATEncoder(CSolver *csolver, SATEncoder * This) {
80         VectorBoolean *constraints=csolver->constraints;
81         uint size=getSizeVectorBoolean(constraints);
82         for(uint i=0;i<size;i++) {
83                 Boolean *constraint=getVectorBoolean(constraints, i);
84                 Constraint* c= encodeConstraintSATEncoder(This, constraint);
85                 printConstraint(c);
86                 model_print("\n\n");
87                 addConstraintToSATSolver(c, This->satSolver);
88                 //FIXME: When do we want to delete constraints? Should we keep an array of them
89                 // and delete them later, or it would be better to just delete them right away?
90         }
91 }
92
93 Constraint * encodeConstraintSATEncoder(SATEncoder *This, Boolean *constraint) {
94         switch(GETBOOLEANTYPE(constraint)) {
95         case ORDERCONST:
96                 return encodeOrderSATEncoder(This, (BooleanOrder *) constraint);
97         case BOOLEANVAR:
98                 return encodeVarSATEncoder(This, (BooleanVar *) constraint);
99         case LOGICOP:
100                 return encodeLogicSATEncoder(This, (BooleanLogic *) constraint);
101         case PREDICATEOP:
102                 return encodePredicateSATEncoder(This, (BooleanPredicate *) constraint);
103         default:
104                 model_print("Unhandled case in encodeConstraintSATEncoder %u", GETBOOLEANTYPE(constraint));
105                 exit(-1);
106         }
107 }
108
109 void getArrayNewVarsSATEncoder(SATEncoder* encoder, uint num, Constraint **carray) {
110         for(uint i=0;i<num;i++)
111                 carray[i]=getNewVarSATEncoder(encoder);
112 }
113
114 Constraint * getNewVarSATEncoder(SATEncoder *This) {
115         Constraint * var=allocVarConstraint(VAR, This->varcount);
116         Constraint * varneg=allocVarConstraint(NOTVAR, This->varcount++);
117         setNegConstraint(var, varneg);
118         setNegConstraint(varneg, var);
119         return var;
120 }
121
122 Constraint * encodeVarSATEncoder(SATEncoder *This, BooleanVar * constraint) {
123         if (constraint->var == NULL) {
124                 constraint->var=getNewVarSATEncoder(This);
125         }
126         return constraint->var;
127 }
128
129 Constraint * encodeLogicSATEncoder(SATEncoder *This, BooleanLogic * constraint) {
130         Constraint * array[getSizeArrayBoolean(&constraint->inputs)];
131         for(uint i=0;i<getSizeArrayBoolean(&constraint->inputs);i++)
132                 array[i]=encodeConstraintSATEncoder(This, getArrayBoolean(&constraint->inputs, i));
133
134         switch(constraint->op) {
135         case L_AND:
136                 return allocArrayConstraint(AND, getSizeArrayBoolean(&constraint->inputs), array);
137         case L_OR:
138                 return allocArrayConstraint(OR, getSizeArrayBoolean(&constraint->inputs), array);
139         case L_NOT:
140                 ASSERT( getSizeArrayBoolean(&constraint->inputs)==1);
141                 return negateConstraint(array[0]);
142         case L_XOR: {
143                 ASSERT( getSizeArrayBoolean(&constraint->inputs)==2);
144                 Constraint * nleft=negateConstraint(cloneConstraint(array[0]));
145                 Constraint * nright=negateConstraint(cloneConstraint(array[1]));
146                 return allocConstraint(OR,
147                                                                                                          allocConstraint(AND, array[0], nright),
148                                                                                                          allocConstraint(AND, nleft, array[1]));
149         }
150         case L_IMPLIES:
151                 ASSERT( getSizeArrayBoolean( &constraint->inputs)==2);
152                 return allocConstraint(IMPLIES, array[0], array[1]);
153         default:
154                 model_print("Unhandled case in encodeLogicSATEncoder %u", constraint->op);
155                 exit(-1);
156         }
157 }
158
159
160 Constraint * encodeOrderSATEncoder(SATEncoder *This, BooleanOrder * constraint) {
161         switch( constraint->order->type){
162                 case PARTIAL:
163                         return encodePartialOrderSATEncoder(This, constraint);
164                 case TOTAL:
165                         return encodeTotalOrderSATEncoder(This, constraint);
166                 default:
167                         ASSERT(0);
168         }
169         return NULL;
170 }
171
172 Constraint * getPairConstraint(SATEncoder *This, HashTableBoolConst * table, OrderPair * pair) {
173         bool negate = false;
174         OrderPair flipped;
175         if (pair->first > pair->second) {
176                 negate=true;
177                 flipped.first=pair->second;
178                 flipped.second=pair->first;
179                 pair = &flipped;        //FIXME: accessing a local variable from outside of the function?
180         }
181         Constraint * constraint;
182         if (!containsBoolConst(table, pair)) {
183                 constraint = getNewVarSATEncoder(This);
184                 OrderPair * paircopy = allocOrderPair(pair->first, pair->second);
185                 putBoolConst(table, paircopy, constraint);
186         } else
187                 constraint = getBoolConst(table, pair);
188         if (negate)
189                 return negateConstraint(constraint);
190         else
191                 return constraint;
192         
193 }
194
195 Constraint * encodeTotalOrderSATEncoder(SATEncoder *This, BooleanOrder * boolOrder){
196         ASSERT(boolOrder->order->type == TOTAL);
197         if(boolOrder->order->boolsToConstraints == NULL){
198                 initializeOrderHashTable(boolOrder->order);
199                 return createAllTotalOrderConstraintsSATEncoder(This, boolOrder->order);
200         }
201         HashTableBoolConst* boolToConsts = boolOrder->order->boolsToConstraints;
202         OrderPair pair={boolOrder->first, boolOrder->second};
203         Constraint* constraint = getPairConstraint(This, boolToConsts, & pair);
204         ASSERT(constraint != NULL);
205         return constraint;
206 }
207
208 Constraint* createAllTotalOrderConstraintsSATEncoder(SATEncoder* This, Order* order){
209         ASSERT(order->type == TOTAL);
210         VectorInt* mems = order->set->members;
211         HashTableBoolConst* table = order->boolsToConstraints;
212         uint size = getSizeVectorInt(mems);
213         Constraint* constraints [size*size];
214         uint csize =0;
215         for(uint i=0; i<size; i++){
216                 uint64_t valueI = getVectorInt(mems, i);
217                 for(uint j=i+1; j<size;j++){
218                         uint64_t valueJ = getVectorInt(mems, j);
219                         OrderPair pairIJ = {valueI, valueJ};
220                         Constraint* constIJ=getPairConstraint(This, table, & pairIJ);
221                         for(uint k=j+1; k<size; k++){
222                                 uint64_t valueK = getVectorInt(mems, k);
223                                 OrderPair pairJK = {valueJ, valueK};
224                                 OrderPair pairIK = {valueI, valueK};
225                                 Constraint* constIK = getPairConstraint(This, table, & pairIK);
226                                 Constraint* constJK = getPairConstraint(This, table, & pairJK);
227                                 constraints[csize++] = generateTransOrderConstraintSATEncoder(This, constIJ, constJK, constIK); 
228                                 ASSERT(csize < size*size);
229                         }
230                 }
231         }
232         return allocArrayConstraint(AND, csize, constraints);
233 }
234
235 Constraint* getOrderConstraint(HashTableBoolConst *table, OrderPair *pair){
236         ASSERT(pair->first!= pair->second);
237         Constraint* constraint= getBoolConst(table, pair);
238         ASSERT(constraint!= NULL);
239         if(pair->first > pair->second)
240                 return constraint;
241         else
242                 return negateConstraint(constraint);
243 }
244
245 Constraint * generateTransOrderConstraintSATEncoder(SATEncoder *This, Constraint *constIJ,Constraint *constJK,Constraint *constIK){
246         //FIXME: first we should add the the constraint to the satsolver!
247         ASSERT(constIJ!= NULL && constJK != NULL && constIK != NULL);
248         Constraint *carray[] = {constIJ, constJK, negateConstraint(constIK)};
249         Constraint * loop1= allocArrayConstraint(OR, 3, carray);
250         Constraint * carray2[] = {negateConstraint(constIJ), negateConstraint(constJK), constIK};
251         Constraint * loop2= allocArrayConstraint(OR, 3,carray2 );
252         return allocConstraint(AND, loop1, loop2);
253 }
254
255 Constraint * encodePartialOrderSATEncoder(SATEncoder *This, BooleanOrder * constraint){
256         // FIXME: we can have this implementation for partial order. Basically,
257         // we compute the transitivity between two order constraints specified by the client! (also can be used
258         // when client specify sparse constraints for the total order!)
259         ASSERT(constraint->order->type == PARTIAL);
260 /*
261         HashTableBoolConst* boolToConsts = boolOrder->order->boolsToConstraints;
262         if( containsBoolConst(boolToConsts, boolOrder) ){
263                 return getBoolConst(boolToConsts, boolOrder);
264         } else {
265                 Constraint* constraint = getNewVarSATEncoder(This); 
266                 putBoolConst(boolToConsts,boolOrder, constraint);
267                 VectorBoolean* orderConstrs = &boolOrder->order->constraints;
268                 uint size= getSizeVectorBoolean(orderConstrs);
269                 for(uint i=0; i<size; i++){
270                         ASSERT(GETBOOLEANTYPE( getVectorBoolean(orderConstrs, i)) == ORDERCONST );
271                         BooleanOrder* tmp = (BooleanOrder*)getVectorBoolean(orderConstrs, i);
272                         BooleanOrder* newBool;
273                         Constraint* first, *second;
274                         if(tmp->second==boolOrder->first){
275                                 newBool = (BooleanOrder*)allocBooleanOrder(tmp->order,tmp->first,boolOrder->second);
276                                 first = encodeTotalOrderSATEncoder(This, tmp);
277                                 second = constraint;
278                                 
279                         }else if (boolOrder->second == tmp->first){
280                                 newBool = (BooleanOrder*)allocBooleanOrder(tmp->order,boolOrder->first,tmp->second);
281                                 first = constraint;
282                                 second = encodeTotalOrderSATEncoder(This, tmp);
283                         }else
284                                 continue;
285                         Constraint* transConstr= encodeTotalOrderSATEncoder(This, newBool);
286                         generateTransOrderConstraintSATEncoder(This, first, second, transConstr );
287                 }
288                 return constraint;
289         }
290 */      
291         return NULL;
292 }
293
294 Constraint * encodePredicateSATEncoder(SATEncoder * This, BooleanPredicate * constraint) {
295         switch(GETPREDICATETYPE(constraint->predicate) ){
296                 case TABLEPRED:
297                         return encodeTablePredicateSATEncoder(This, constraint);
298                 case OPERATORPRED:
299                         return encodeOperatorPredicateSATEncoder(This, constraint);
300                 default:
301                         ASSERT(0);
302         }
303         return NULL;
304 }
305
306 Constraint * encodeTablePredicateSATEncoder(SATEncoder * This, BooleanPredicate * constraint){
307         switch(constraint->encoding.type){
308                 case ENUMERATEIMPLICATIONS:
309                 case ENUMERATEIMPLICATIONSNEGATE:
310                         return encodeEnumTablePredicateSATEncoder(This, constraint);
311                 case CIRCUIT:
312                         ASSERT(0);
313                         break;
314                 default:
315                         ASSERT(0);
316         }
317         return NULL;
318 }
319
320 Constraint * encodeEnumTablePredicateSATEncoder(SATEncoder * This, BooleanPredicate * constraint){
321         VectorTableEntry* entries = &(((PredicateTable*)constraint->predicate)->table->entries);
322         FunctionEncodingType encType = constraint->encoding.type;
323         uint size = getSizeVectorTableEntry(entries);
324         Constraint* constraints[size];
325         for(uint i=0; i<size; i++){
326                 TableEntry* entry = getVectorTableEntry(entries, i);
327                 if(encType==ENUMERATEIMPLICATIONS && entry->output!= true)
328                         continue;
329                 else if(encType==ENUMERATEIMPLICATIONSNEGATE && entry->output !=false)
330                         continue;
331                 ArrayElement* inputs = &constraint->inputs;
332                 uint inputNum =getSizeArrayElement(inputs);
333                 Constraint* carray[inputNum];
334                 for(uint j=0; j<inputNum; j++){
335                         Element* el = getArrayElement(inputs, j);
336                         Constraint* tmpc = getElementValueConstraint(This,el, entry->inputs[j]);
337                         ASSERT(tmpc!= NULL);
338                         if( GETELEMENTTYPE(el) == ELEMFUNCRETURN){
339                                 Constraint* func =encodeFunctionElementSATEncoder(This, (ElementFunction*) el);
340                                 ASSERT(func!=NULL);
341                                 carray[j] = allocConstraint(AND, func, tmpc);
342                         } else {
343                                 carray[j] = tmpc;
344                         }
345                         ASSERT(carray[j]!= NULL);
346                 }
347                 constraints[i]=allocArrayConstraint(AND, inputNum, carray);
348         }
349         Constraint* result= allocArrayConstraint(OR, size, constraints);
350         //FIXME: if it didn't match with any entry
351         return encType==ENUMERATEIMPLICATIONS? result: negateConstraint(result);
352 }
353
354 Constraint * encodeOperatorPredicateSATEncoder(SATEncoder * This, BooleanPredicate * constraint){
355         switch(constraint->encoding.type){
356                 case ENUMERATEIMPLICATIONS:
357                         return encodeEnumOperatorPredicateSATEncoder(This, constraint);
358                 case CIRCUIT:
359                         ASSERT(0);
360                         break;
361                 default:
362                         ASSERT(0);
363         }
364         return NULL;
365 }
366
367 Constraint * encodeEnumOperatorPredicateSATEncoder(SATEncoder * This, BooleanPredicate * constraint){
368         ASSERT(GETPREDICATETYPE(constraint->predicate)==OPERATORPRED);
369         PredicateOperator* predicate = (PredicateOperator*)constraint->predicate;
370         ASSERT(predicate->op == EQUALS); //For now, we just only support equals
371         //getting maximum size of in common elements between two sets!
372         uint size=getSizeVectorInt( getArraySet( &predicate->domains, 0)->members);
373         uint64_t commonElements [size];
374         getEqualitySetIntersection(predicate, &size, commonElements);
375         Constraint*  carray[size];
376         Element* elem1 = getArrayElement( &constraint->inputs, 0);
377         Constraint *elemc1 = NULL, *elemc2 = NULL;
378         if( GETELEMENTTYPE(elem1) == ELEMFUNCRETURN)
379                 elemc1 = encodeFunctionElementSATEncoder(This, (ElementFunction*) elem1);
380         Element* elem2 = getArrayElement( &constraint->inputs, 1);
381         if( GETELEMENTTYPE(elem2) == ELEMFUNCRETURN)
382                 elemc2 = encodeFunctionElementSATEncoder(This, (ElementFunction*) elem2);
383         for(uint i=0; i<size; i++){
384                 Constraint* arg1 = getElementValueConstraint(This, elem1, commonElements[i]);
385                 ASSERT(arg1!=NULL);
386                 Constraint* arg2 = getElementValueConstraint(This, elem2, commonElements[i]);
387                 ASSERT(arg2 != NULL);
388                 carray[i] =  allocConstraint(AND, arg1, arg2);
389         }
390         //FIXME: the case when there is no intersection ....
391         Constraint* result = allocArrayConstraint(OR, size, carray);
392         ASSERT(result!= NULL);
393         if(elemc1!= NULL)
394                 result = allocConstraint(AND, result, elemc1);
395         if(elemc2 != NULL)
396                 result = allocConstraint (AND, result, elemc2);
397         return result;
398 }
399
400 Constraint* encodeFunctionElementSATEncoder(SATEncoder* encoder, ElementFunction *This){
401         switch(GETFUNCTIONTYPE(This->function)){
402                 case TABLEFUNC:
403                         return encodeTableElementFunctionSATEncoder(encoder, This);
404                 case OPERATORFUNC:
405                         return encodeOperatorElementFunctionSATEncoder(encoder, This);
406                 default:
407                         ASSERT(0);
408         }
409         return NULL;
410 }
411
412 Constraint* encodeTableElementFunctionSATEncoder(SATEncoder* encoder, ElementFunction* This){
413         switch(getElementFunctionEncoding(This)->type){
414                 case ENUMERATEIMPLICATIONS:
415                         return encodeEnumTableElemFunctionSATEncoder(encoder, This);
416                         break;
417                 case CIRCUIT:
418                         ASSERT(0);
419                         break;
420                 default:
421                         ASSERT(0);
422         }
423         return NULL;
424 }
425
426 Constraint* encodeOperatorElementFunctionSATEncoder(SATEncoder* encoder, ElementFunction* This){
427         ASSERT(GETFUNCTIONTYPE(This->function) == OPERATORFUNC);
428         ASSERT(getSizeArrayElement(&This->inputs)==2 );
429         ElementEncoding* elem1 = getElementEncoding( getArrayElement(&This->inputs,0) );
430         ElementEncoding* elem2 = getElementEncoding( getArrayElement(&This->inputs,1) );
431         Constraint* carray[elem1->encArraySize*elem2->encArraySize];
432         uint size=0;
433         Constraint* overFlowConstraint = ((BooleanVar*) This->overflowstatus)->var;
434         for(uint i=0; i<elem1->encArraySize; i++){
435                 if(isinUseElement(elem1, i)){
436                         for( uint j=0; j<elem2->encArraySize; j++){
437                                 if(isinUseElement(elem2, j)){
438                                         bool isInRange = false;
439                                         uint64_t result= applyFunctionOperator((FunctionOperator*)This->function,elem1->encodingArray[i],
440                                                 elem2->encodingArray[j], &isInRange);
441                                         //FIXME: instead of getElementValueConstraint, it might be useful to have another function
442                                         // that doesn't iterate over encodingArray and treats more efficient ...
443                                         Constraint* valConstrIn1 = getElementValueConstraint(encoder, elem1->element, elem1->encodingArray[i]);
444                                         ASSERT(valConstrIn1 != NULL);
445                                         Constraint* valConstrIn2 = getElementValueConstraint(encoder, elem2->element, elem2->encodingArray[j]);
446                                         ASSERT(valConstrIn2 != NULL);
447                                         Constraint* valConstrOut = getElementValueConstraint(encoder, (Element*) This, result);
448                                         if(valConstrOut == NULL)
449                                                 continue; //FIXME:Should talk to brian about it!
450                                         Constraint* OpConstraint = allocConstraint(IMPLIES, 
451                                                 allocConstraint(AND, valConstrIn1, valConstrIn2) , valConstrOut);
452                                         switch( ((FunctionOperator*)This->function)->overflowbehavior ){
453                                                 case IGNORE:
454                                                         if(isInRange){
455                                                                 carray[size++] = OpConstraint;
456                                                         }
457                                                         break;
458                                                 case WRAPAROUND:
459                                                         carray[size++] = OpConstraint;
460                                                         break;
461                                                 case FLAGFORCESOVERFLOW:
462                                                         if(isInRange){
463                                                                 Constraint* const1 = allocConstraint(IMPLIES,
464                                                                         allocConstraint(AND, valConstrIn1, valConstrIn2), 
465                                                                         negateConstraint(overFlowConstraint));
466                                                                 carray[size++] = allocConstraint(AND, const1, OpConstraint);
467                                                         }
468                                                         break;
469                                                 case OVERFLOWSETSFLAG:
470                                                         if(isInRange){
471                                                                 carray[size++] = OpConstraint;
472                                                         } else{
473                                                                 carray[size++] = allocConstraint(IMPLIES,
474                                                                         allocConstraint(AND, valConstrIn1, valConstrIn2),
475                                                                         overFlowConstraint);
476                                                         }
477                                                         break;
478                                                 case FLAGIFFOVERFLOW:
479                                                         if(isInRange){
480                                                                 Constraint* const1 = allocConstraint(IMPLIES,
481                                                                         allocConstraint(AND, valConstrIn1, valConstrIn2), 
482                                                                         negateConstraint(overFlowConstraint));
483                                                                 carray[size++] = allocConstraint(AND, const1, OpConstraint);
484                                                         }else{
485                                                                 carray[size++] = allocConstraint(IMPLIES,
486                                                                         allocConstraint(AND, valConstrIn1, valConstrIn2),
487                                                                         overFlowConstraint);
488                                                         }
489                                                         break;
490                                                 case NOOVERFLOW:
491                                                         if(!isInRange){
492                                                                 ASSERT(0);
493                                                         }
494                                                         carray[size++] = OpConstraint;
495                                                         break;
496                                                 default:
497                                                         ASSERT(0);
498                                         }
499                                         
500                                 }
501                         }
502                 }
503         }
504         return allocArrayConstraint(AND, size, carray);
505 }
506
507 Constraint* encodeEnumTableElemFunctionSATEncoder(SATEncoder* encoder, ElementFunction* This){
508         ASSERT(GETFUNCTIONTYPE(This->function)==TABLEFUNC);
509         ArrayElement* elements= &This->inputs;
510         Table* table = ((FunctionTable*) (This->function))->table;
511         uint size = getSizeVectorTableEntry(&table->entries);
512         Constraint* constraints[size]; //FIXME: should add a space for the case that didn't match any entries
513         for(uint i=0; i<size; i++){
514                 TableEntry* entry = getVectorTableEntry(&table->entries, i);
515                 uint inputNum =getSizeArrayElement(elements);
516                 Constraint* carray[inputNum];
517                 for(uint j=0; j<inputNum; j++){
518                         Element* el= getArrayElement(elements, j);
519                         carray[j] = getElementValueConstraint(encoder, el, entry->inputs[j]);
520                         ASSERT(carray[j]!= NULL);
521                 }
522                 Constraint* output = getElementValueConstraint(encoder, (Element*)This, entry->output);
523                 ASSERT(output!= NULL);
524                 Constraint* row= allocConstraint(IMPLIES, allocArrayConstraint(AND, inputNum, carray), output);
525                 constraints[i]=row;
526         }
527         Constraint* result = allocArrayConstraint(OR, size, constraints);
528         return result;
529 }