4 #include "inc_solver.h"
6 /** Code ported from C++ BAT implementation of NICE-SAT */
8 VectorImpl(Edge, Edge, 16)
11 CNF * cnf=ourmalloc(sizeof(CNF));
13 cnf->capacity=DEFAULT_CNF_ARRAY_SIZE;
14 cnf->mask=cnf->capacity-1;
15 cnf->node_array=ourcalloc(1, sizeof(Node *)*cnf->capacity);
17 cnf->maxsize=(uint)(((double)cnf->capacity)*LOAD_FACTOR);
18 cnf->enableMatching=true;
19 allocInlineDefVectorEdge(& cnf->constraints);
23 void deleteCNF(CNF * cnf) {
24 for(uint i=0;i<cnf->capacity;i++) {
25 Node *n=cnf->node_array[i];
29 deleteVectorArrayEdge(& cnf->constraints);
30 ourfree(cnf->node_array);
34 void resizeCNF(CNF *cnf, uint newCapacity) {
35 Node **old_array=cnf->node_array;
36 Node **new_array=ourcalloc(1, sizeof(Node *)*newCapacity);
37 uint oldCapacity=cnf->capacity;
38 uint newMask=newCapacity-1;
39 for(uint i=0;i<oldCapacity;i++) {
41 uint hashCode=n->hashCode;
42 uint newindex=hashCode & newMask;
43 for(;;newindex=(newindex+1) & newMask) {
44 if (new_array[newindex] == NULL) {
45 new_array[newindex]=n;
51 cnf->node_array=new_array;
52 cnf->capacity=newCapacity;
53 cnf->maxsize=(uint)(((double)cnf->capacity)*LOAD_FACTOR);
57 Node * allocNode(NodeType type, uint numEdges, Edge * edges, uint hashcode) {
58 Node *n=(Node *)ourmalloc(sizeof(Node)+sizeof(Edge)*numEdges);
59 memcpy(n->edges, edges, sizeof(Edge)*numEdges);
61 n->flags.wasExpanded=0;
62 n->flags.cnfVisitedDown=0;
63 n->flags.cnfVisitedUp=0;
66 n->intAnnot[0]=0;n->intAnnot[1]=0;
67 n->ptrAnnot[0]=NULL;n->ptrAnnot[1]=NULL;
71 Edge createNode(CNF *cnf, NodeType type, uint numEdges, Edge * edges) {
72 if (cnf->size > cnf->maxsize) {
73 resizeCNF(cnf, cnf->capacity << 1);
75 uint hashvalue=hashNode(type, numEdges, edges);
77 uint index=hashvalue & mask;
79 for(;;index=(index+1)&mask) {
80 n_ptr=&cnf->node_array[index];
82 if ((*n_ptr)->hashCode==hashvalue) {
83 if (compareNodes(*n_ptr, type, numEdges, edges)) {
92 *n_ptr=allocNode(type, numEdges, edges, hashvalue);
97 uint hashNode(NodeType type, uint numEdges, Edge * edges) {
98 uint hashvalue=type ^ numEdges;
99 for(uint i=0;i<numEdges;i++) {
100 hashvalue ^= (uint) edges[i].node_ptr;
101 hashvalue = (hashvalue << 3) | (hashvalue >> 29); //rotate left by 3 bits
103 return (uint) hashvalue;
106 bool compareNodes(Node * node, NodeType type, uint numEdges, Edge *edges) {
107 if (node->flags.type!=type || node->numEdges != numEdges)
109 Edge *nodeedges=node->edges;
110 for(uint i=0;i<numEdges;i++) {
111 if (!equalsEdge(nodeedges[i], edges[i]))
117 Edge constraintOR(CNF * cnf, uint numEdges, Edge *edges) {
118 Edge edgearray[numEdges];
120 for(uint i=0; i<numEdges; i++) {
121 edgearray[i]=constraintNegate(edges[i]);
123 Edge eand=constraintAND(cnf, numEdges, edgearray);
124 return constraintNegate(eand);
127 Edge constraintOR2(CNF * cnf, Edge left, Edge right) {
128 Edge lneg=constraintNegate(left);
129 Edge rneg=constraintNegate(right);
130 Edge eand=constraintAND2(cnf, left, right);
131 return constraintNegate(eand);
134 int comparefunction(const Edge * e1, const Edge * e2) {
135 return ((uintptr_t)e1->node_ptr)-((uintptr_t)e2->node_ptr);
138 Edge constraintAND(CNF * cnf, uint numEdges, Edge * edges) {
139 qsort(edges, numEdges, sizeof(Edge), (int (*)(const void *, const void *)) comparefunction);
141 while(initindex<numEdges && equalsEdge(edges[initindex], E_True))
144 uint remainSize=numEdges-initindex;
148 else if (remainSize == 1)
149 return edges[initindex];
150 else if (equalsEdge(edges[initindex], E_False))
153 /** De-duplicate array */
155 edges[lowindex++]=edges[initindex++];
157 for(;initindex<numEdges;initindex++) {
158 Edge e1=edges[lowindex];
159 Edge e2=edges[initindex];
160 if (sameNodeVarEdge(e1, e2)) {
161 if (!sameSignEdge(e1, e2)) {
165 edges[lowindex++]=edges[initindex];
170 if (cnf->enableMatching && lowindex==2 &&
171 isNegNodeEdge(edges[0]) && isNegNodeEdge(edges[1]) &&
172 getNodeType(edges[0]) == NodeType_AND &&
173 getNodeType(edges[1]) == NodeType_AND &&
174 getNodeSize(edges[0]) == 2 &&
175 getNodeSize(edges[1]) == 2) {
176 Edge * e0edges=getEdgeArray(edges[0]);
177 Edge * e1edges=getEdgeArray(edges[1]);
178 if (sameNodeOppSign(e0edges[0], e1edges[0])) {
179 return constraintNegate(constraintITE(cnf, e0edges[0], e0edges[1], e1edges[1]));
180 } else if (sameNodeOppSign(e0edges[0], e1edges[1])) {
181 return constraintNegate(constraintITE(cnf, e0edges[0], e0edges[1], e1edges[0]));
182 } else if (sameNodeOppSign(e0edges[1], e1edges[0])) {
183 return constraintNegate(constraintITE(cnf, e0edges[1], e0edges[0], e1edges[1]));
184 } else if (sameNodeOppSign(e0edges[1], e1edges[1])) {
185 return constraintNegate(constraintITE(cnf, e0edges[1], e0edges[0], e1edges[0]));
189 return createNode(cnf, NodeType_AND, numEdges, edges);
192 Edge constraintAND2(CNF * cnf, Edge left, Edge right) {
193 Edge edges[2]={left, right};
194 return constraintAND(cnf, 2, edges);
197 Edge constraintIMPLIES(CNF * cnf, Edge left, Edge right) {
200 array[1]=constraintNegate(right);
201 Edge eand=constraintAND(cnf, 2, array);
202 return constraintNegate(eand);
205 Edge constraintIFF(CNF * cnf, Edge left, Edge right) {
206 bool negate=sameSignEdge(left, right);
207 Edge lpos=getNonNeg(left);
208 Edge rpos=getNonNeg(right);
211 if (equalsEdge(lpos, rpos)) {
213 } else if (ltEdge(lpos, rpos)) {
214 Edge edges[]={lpos, rpos};
215 e=(edgeIsConst(lpos)) ? rpos : createNode(cnf, NodeType_IFF, 2, edges);
217 Edge edges[]={rpos, lpos};
218 e=(edgeIsConst(rpos)) ? lpos : createNode(cnf, NodeType_IFF, 2, edges);
221 e=constraintNegate(e);
225 Edge constraintITE(CNF * cnf, Edge cond, Edge thenedge, Edge elseedge) {
226 if (isNegEdge(cond)) {
227 cond=constraintNegate(cond);
233 bool negate = isNegEdge(thenedge);
235 thenedge=constraintNegate(thenedge);
236 elseedge=constraintNegate(elseedge);
240 if (equalsEdge(cond, E_True)) {
242 } else if (equalsEdge(thenedge, E_True) || equalsEdge(cond, thenedge)) {
243 result=constraintOR(cnf, 2, (Edge[]) {cond, elseedge});
244 } else if (equalsEdge(elseedge, E_True) || sameNodeOppSign(cond, elseedge)) {
245 result=constraintIMPLIES(cnf, cond, thenedge);
246 } else if (equalsEdge(thenedge, E_False) || equalsEdge(cond, elseedge)) {
247 result=constraintAND(cnf, 2, (Edge[]) {cond, thenedge});
248 } else if (equalsEdge(thenedge, elseedge)) {
250 } else if (sameNodeOppSign(thenedge, elseedge)) {
251 if (ltEdge(cond, thenedge)) {
252 result=createNode(cnf, NodeType_IFF, 2, (Edge[]) {cond, thenedge});
254 result=createNode(cnf, NodeType_IFF, 2, (Edge[]) {thenedge, cond});
257 Edge edges[]={cond, thenedge, elseedge};
258 result=createNode(cnf, NodeType_ITE, 3, edges);
261 result=constraintNegate(result);
265 void addConstraint(CNF *cnf, Edge constraint) {
266 pushVectorEdge(&cnf->constraints, constraint);
269 Edge constraintNewVar(CNF *cnf) {
270 uint varnum=cnf->varcount++;
271 Edge e={(Node *) ((((uintptr_t)varnum) << VAR_SHIFT) | EDGE_IS_VAR_CONSTANT) };
275 void countPass(CNF *cnf) {
276 uint numConstraints=getSizeVectorEdge(&cnf->constraints);
277 VectorEdge *ve=allocDefVectorEdge();
278 for(uint i=0; i<numConstraints;i++) {
279 countConstraint(cnf, ve, getVectorEdge(&cnf->constraints, i));
281 deleteVectorEdge(ve);
284 void countConstraint(CNF *cnf, VectorEdge *stack, Edge e) {
285 //Skip constants and variables...
286 if (edgeIsVarConst(e))
289 clearVectorEdge(stack);pushVectorEdge(stack, e);
291 bool isMatching=cnf->enableMatching;
293 while(getSizeVectorEdge(stack) != 0) {
294 Edge e=lastVectorEdge(stack); popVectorEdge(stack);
295 bool polarity=isNegEdge(e);
296 Node *n=getNodePtrFromEdge(e);
297 if (getExpanded(n, polarity)) {
298 if (n->flags.type == NodeType_IFF ||
299 n->flags.type == NodeType_ITE) {
300 Edge pExp={n->ptrAnnot[polarity]};
301 getNodePtrFromEdge(pExp)->intAnnot[0]++;
303 n->intAnnot[polarity]++;
306 setExpanded(n, polarity); n->intAnnot[polarity]=1;
308 if (n->flags.type == NodeType_ITE||
309 n->flags.type == NodeType_IFF) {
310 n->intAnnot[polarity]=0;
311 Edge cond=n->edges[0];
312 Edge thenedge=n->edges[1];
313 Edge elseedge=n->flags.type == NodeType_IFF? constraintNegate(thenedge): n->edges[2];
314 thenedge=constraintNegateIf(thenedge, !polarity);
315 elseedge=constraintNegateIf(elseedge, !polarity);
316 thenedge=constraintAND2(cnf, cond, thenedge);
317 cond=constraintNegate(cond);
318 elseedge=constraintAND2(cnf, cond, elseedge);
319 thenedge=constraintNegate(thenedge);
320 elseedge=constraintNegate(elseedge);
321 cnf->enableMatching=false;
322 Edge succ1=constraintAND2(cnf, thenedge, elseedge);
323 n->ptrAnnot[polarity]=succ1.node_ptr;
324 cnf->enableMatching=isMatching;
325 pushVectorEdge(stack, succ1);
326 if (getExpanded(n, !polarity)) {
327 Edge succ2={(Node *)n->ptrAnnot[!polarity]};
328 Node *n1=getNodePtrFromEdge(succ1);
329 Node *n2=getNodePtrFromEdge(succ2);
330 n1->ptrAnnot[0]=succ2.node_ptr;
331 n2->ptrAnnot[0]=succ1.node_ptr;
332 n1->ptrAnnot[1]=succ2.node_ptr;
333 n2->ptrAnnot[1]=succ1.node_ptr;
336 for (uint i=0;i<n->numEdges;i++) {
337 Edge succ=n->edges[i];
338 succ=constraintNegateIf(succ, polarity);
339 if(!edgeIsVarConst(succ)) {
340 pushVectorEdge(stack, succ);
348 void convertPass(CNF *cnf, bool backtrackLit) {
349 uint numConstraints=getSizeVectorEdge(&cnf->constraints);
350 VectorEdge *ve=allocDefVectorEdge();
351 for(uint i=0; i<numConstraints;i++) {
352 convertConstraint(cnf, ve, getVectorEdge(&cnf->constraints, i), backtrackLit);
354 deleteVectorEdge(ve);
357 void convertConstraint(CNF *cnf, VectorEdge *stack, Edge root, bool backtrackLit) {
358 Node *nroot=getNodePtrFromEdge(root);
360 if (isNodeEdge(root) && (nroot->flags.type == NodeType_ITE || nroot->flags.type == NodeType_IFF)) {
361 root = (Edge) { (Node *) nroot->ptrAnnot[isNegEdge(root)]};
364 if (edgeIsConst(root)) {
365 if (isNegEdge(root)) {
367 Edge newvar=constraintNewVar(cnf);
368 Literal var=getEdgeVar(newvar);
369 Literal clause[] = {var, -var, 0};
370 addArrayClauseLiteral(cnf->solver, 3, clause);
376 } else if (edgeIsVarConst(root)) {
377 Literal clause[] = { getEdgeVar(root), 0};
378 addArrayClauseLiteral(cnf->solver, 2, clause);
382 clearVectorEdge(stack);pushVectorEdge(stack, root);
383 while(getSizeVectorEdge(stack)!=0) {
384 Edge e=lastVectorEdge(stack);
385 Node *n=getNodePtrFromEdge(e);
387 if (edgeIsVarConst(e)) {
388 popVectorEdge(stack);
390 } else if (n->flags.type==NodeType_ITE ||
391 n->flags.type==NodeType_IFF) {
392 popVectorEdge(stack);
393 pushVectorEdge(stack, (Edge) {(Node *)n->ptrAnnot[0]});
394 pushVectorEdge(stack, (Edge) {(Node *)n->ptrAnnot[1]});
398 bool needPos = (n->intAnnot[0] > 0);
399 bool needNeg = (n->intAnnot[1] > 0);
400 if ((!needPos || n->flags.cnfVisitedUp & 1) ||
401 (!needNeg || n->flags.cnfVisitedUp & 2)) {
402 popVectorEdge(stack);
403 } else if ((needPos && !n->flags.cnfVisitedDown & 1) ||
404 (needNeg && !n->flags.cnfVisitedDown & 2)) {
406 n->flags.cnfVisitedDown|=1;
408 n->flags.cnfVisitedDown|=2;
409 for(uint i=0; i<n->numEdges; i++) {
410 Edge arg=n->edges[i];
411 arg=constraintNegateIf(arg, isNegEdge(e));
412 pushVectorEdge(stack, arg); //WARNING, THIS LOOKS LIKE A BUG IN THE ORIGINAL CODE
415 popVectorEdge(stack);
419 CNFExpr * cnfExp = (CNFExpr *) nroot->ptrAnnot[isNegEdge(root)];
420 if (isProxy(cnfExp)) {
421 //solver.add(getProxy(cnfExp))
422 } else if (backtrackLit) {
423 //solver.add(introProxy(solver, root, cnfExp, isNegEdge(root)));
425 //solver.add(*cnfExp);
428 if (!((intptr_t) cnfExp & 1)) {
430 nroot->ptrAnnot[isNegEdge(root)] = NULL;
435 Literal introProxy(CNF * cnf, Edge e, CNFExpr* exp, bool isNeg) {
437 Node * n = getNodePtrFromEdge(e);
439 if (n->flags.cnfVisitedUp & (1<<!isNeg)) {
440 CNFExpr* otherExp = (CNFExpr*) n->ptrAnnot[!isNeg];
441 if (isProxy(otherExp))
442 l = -getProxy(otherExp);
444 Edge semNeg={(Node *) n->ptrAnnot[isNeg]};
445 Node * nsemNeg=getNodePtrFromEdge(semNeg);
446 if (nsemNeg != NULL) {
447 if (nsemNeg->flags.cnfVisitedUp & (1 << isNeg)) {
448 CNFExpr* otherExp = (CNFExpr*) nsemNeg->ptrAnnot[isNeg];
449 if (isProxy(otherExp))
450 l = -getProxy(otherExp);
451 } else if (nsemNeg->flags.cnfVisitedUp & (1<< !isNeg)) {
452 CNFExpr* otherExp = (CNFExpr*) nsemNeg->ptrAnnot[!isNeg];
453 if (isProxy(otherExp))
454 l = getProxy(otherExp);
460 Edge newvar = constraintNewVar(cnf);
461 l = getEdgeVar(newvar);
463 // Output the constraints on the auxiliary variable
464 constrainCNF(cnf, l, exp);
465 //delete exp; //FIXME
467 n->ptrAnnot[isNeg] = (void*) ((intptr_t) (l << 1) | 1);
473 void produceCNF(CNF * cnf, Edge e) {
474 CNFExpr* expPos = NULL;
475 CNFExpr* expNeg = NULL;
476 Node *n = getNodePtrFromEdge(e);
478 if (n->intAnnot[0] > 0) {
479 expPos = produceConjunction(cnf, e);
482 if (n->intAnnot[1] > 0) {
483 expNeg = produceDisjunction(cnf, e);
486 /// @todo Propagate constants across semantic negations (this can
487 /// be done similarly to the calls to propagate shown below). The
488 /// trick here is that we need to figure out how to get the
489 /// semantic negation pointers, and ensure that they can have CNF
490 /// produced for them at the right point
492 /// propagate(solver, expPos, snPos, false) || propagate(solver, expNeg, snNeg, false)
494 // propagate from positive to negative, negative to positive
495 propagate(cnf, expPos, expNeg, true) || propagate(cnf, expNeg, expPos, true);
497 // The polarity heuristic entails visiting the discovery polarity first
499 saveCNF(cnf, expPos, e, false);
500 saveCNF(cnf, expNeg, e, true);
502 saveCNF(cnf, expNeg, e, true);
503 saveCNF(cnf, expPos, e, false);
509 bool propagate(CNF *cnf, CNFExpr * dest, CNFExpr * src, bool negate) {
510 if (src != NULL && !isProxy(src) && getLitSizeCNF(src) == 0) {
512 dest = allocCNFExprBool(negate ? alwaysFalseCNF(src) : alwaysTrueCNF(src));
513 } else if (isProxy(dest)) {
514 bool alwaysTrue = (negate ? alwaysFalseCNF(src) : alwaysTrueCNF(src));
516 Literal clause[] = {getProxy(dest), 0};
517 addArrayClauseLiteral(cnf->solver, 2, clause);
519 Literal clause[] = {-getProxy(dest), 0};
520 addArrayClauseLiteral(cnf->solver, 2, clause);
523 dest = allocCNFExprBool(negate ? alwaysFalseCNF(src) : alwaysTrueCNF(src));
525 clearCNF(dest, negate ? alwaysFalseCNF(src) : alwaysTrueCNF(src));
532 void saveCNF(CNF *cnf, CNFExpr* exp, Edge e, bool sign) {
533 Node *n=getNodePtrFromEdge(e);
534 n->flags.cnfVisitedUp & (1 << sign);
535 if (exp == NULL || isProxy(exp)) return;
537 if (exp->litSize == 1) {
538 Literal l = exp->singletons()[0];
540 n->ptrAnnot[sign] = (void*) ((intptr_t) (l << 1) | 1);
541 } else if (exp->litSize != 0 && (n->intAnnot[sign] > 1 || e->isVarForced())) {
542 introProxy(solver, e, exp, sign);
544 n->ptrAnnot[sign] = exp;
548 void constrainCNF(CNF * cnf, Literal l, CNFExpr *exp) {
549 if (alwaysTrueCNF(exp)) {
551 } else if (alwaysFalseCNF(expr)) {
552 Literal clause[] = {-l, 0};
553 addArrayClauseLiteral(cnf->solver, 2, clause);
560 void outputCNF(CNF *cnf, CNFExpr *exp) {
564 CNFExpr* fillArgs(CNF *cnf, Edge e, bool isNeg, Edge * largestEdge, VectorEdge * args) {
567 *largestEdge = (void*) NULL;
568 CnfExp* largest = NULL;
571 Edge arg = (*e)[--i]; arg.negateIf(isNeg);
578 if (arg->op() == NodeOp_Ite || arg->op() == NodeOp_Iff) {
579 arg = arg->ptrAnnot(arg.isNeg());
582 if (arg->intAnnot(arg.isNeg()) == 1) {
583 CnfExp* argExp = (CnfExp*) arg->ptrAnnot(arg.isNeg());
584 if (!isProxy(argExp)) {
585 if (largest == NULL) {
589 } else if (argExp->litSize > largest->litSize) {
590 args.push(largestEdge);
600 if (largest != NULL) {
601 largestEdge->ptrAnnot(largestEdge.isNeg()) = NULL;
608 CNFExpr * produceConjunction(CNF * cnf, Edge e) {
610 CnfExp* accum = fillArgs(e, false, largestEdge);
611 if (accum == NULL) accum = new CnfExp(true);
613 int i = _args.size();
615 Edge arg(_args[--i]);
617 accum->conjoin(atomLit(arg));
619 CnfExp* argExp = (CnfExp*) arg->ptrAnnot(arg.isNeg());
621 bool destroy = (--arg->intAnnot(arg.isNeg()) == 0);
622 if (isProxy(argExp)) { // variable has been introduced
623 accum->conjoin(getProxy(argExp));
625 accum->conjoin(argExp, destroy);
626 if (destroy) arg->ptrAnnot(arg.isNeg()) = NULL;
636 CNFExpr* produceDisjunction(CNF *cnf, Edge e) {
638 CNFExpr* accum = fillArgs(e, true, largestEdge);
640 accum = new CNFExpr(false);
642 // This is necessary to check to make sure that we don't start out
643 // with an accumulator that is "too large".
645 /// @todo Strictly speaking, introProxy doesn't *need* to free
646 /// memory, then this wouldn't have to reallocate CNFExpr
648 /// @todo When this call to introProxy is made, the semantic
649 /// negation pointer will have been destroyed. Thus, it will not
650 /// be possible to use the correct proxy. That should be fixed.
652 // at this point, we will either have NULL, or a destructible expression
653 if (accum->clauseSize() > CLAUSE_MAX)
654 accum = new CNFExpr(introProxy(solver, largestEdge, accum, largestEdge.isNeg()));
656 int i = _args.size();
658 Edge arg(_args[--i]);
660 accum->disjoin(atomLit(arg));
662 CNFExpr* argExp = (CNFExpr*) arg->ptrAnnot(arg.isNeg());
664 bool destroy = (--arg->intAnnot(arg.isNeg()) == 0);
665 if (isProxy(argExp)) { // variable has been introduced
666 accum->disjoin(getProxy(argExp));
667 } else if (argExp->litSize == 0) {
668 accum->disjoin(argExp, destroy);
670 // check to see if we should introduce a proxy
671 int aL = accum->litSize; // lits in accum
672 int eL = argExp->litSize; // lits in argument
673 int aC = getClauseSizeCNF(accum); // clauses in accum
674 int eC = getClauseSizeCNF(argExp); // clauses in argument
676 if (eC > CLAUSE_MAX || (eL * aC + aL * eC > eL + aC + aL + aC)) {
677 accum->disjoin(introProxy(solver, arg, argExp, arg.isNeg()));
679 accum->disjoin(argExp, destroy);
680 if (destroy) arg->ptrAnnot(arg.isNeg()) = NULL;