1 #include "constraint.h"
4 #include "inc_solver.h"
8 V2 Copyright (c) 2014 Ben Chambers, Eugene Goldberg, Pete Manolios,
9 Vasilis Papavasileiou, Sudarshan Srinivasan, and Daron Vroon.
11 Permission is hereby granted, free of charge, to any person obtaining
12 a copy of this software and associated documentation files (the
13 "Software"), to deal in the Software without restriction, including
14 without limitation the rights to use, copy, modify, merge, publish,
15 distribute, sublicense, and/or sell copies of the Software, and to
16 permit persons to whom the Software is furnished to do so, subject to
17 the following conditions:
19 The above copyright notice and this permission notice shall be
20 included in all copies or substantial portions of the Software. If
21 you download or use the software, send email to Pete Manolios
22 (pete@ccs.neu.edu) with your name, contact information, and a short
23 note describing what you want to use BAT for. For any reuse or
24 distribution, you must make clear to others the license terms of this
27 Contact Pete Manolios if you want any of these conditions waived.
29 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
30 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
31 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
32 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
33 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
34 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
35 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
39 C port of CNF SAT Conversion Copyright Brian Demsky 2017.
43 VectorImpl(Edge, Edge, 16)
44 Edge E_True = {(Node *)(uintptr_t) EDGE_IS_VAR_CONSTANT};
45 Edge E_False = {(Node *)(uintptr_t) (EDGE_IS_VAR_CONSTANT | NEGATE_EDGE)};
46 Edge E_BOGUS = {(Node *)0xffff5673};
47 Edge E_NULL = {(Node *)NULL};
51 CNF *cnf = (CNF *) ourmalloc(sizeof(CNF));
53 cnf->solver = allocIncrementalSolver();
56 cnf->asize = DEFAULT_CNF_ARRAY_SIZE;
57 cnf->array = (int *) ourmalloc(sizeof(int) * DEFAULT_CNF_ARRAY_SIZE);
62 void deleteCNF(CNF *cnf) {
63 deleteIncrementalSolver(cnf->solver);
68 void resetCNF(CNF *cnf) {
69 resetSolver(cnf->solver);
76 Node *allocNode(NodeType type, uint numEdges, Edge *edges) {
77 Node *n = (Node *)ourmalloc(sizeof(Node) + sizeof(Edge) * numEdges);
79 n->numEdges = numEdges;
80 memcpy(n->edges, edges, sizeof(Edge) * numEdges);
84 Node *allocBaseNode(NodeType type, uint numEdges) {
85 Node *n = (Node *)ourmalloc(sizeof(Node) + sizeof(Edge) * numEdges);
87 n->numEdges = numEdges;
91 Node *allocResizeNode(uint capacity) {
92 Node *n = (Node *)ourmalloc(sizeof(Node) + sizeof(Edge) * capacity);
94 n->capacity = capacity;
98 Edge cloneEdge(Edge e) {
99 if (edgeIsVarConst(e))
101 Node * node = getNodePtrFromEdge(e);
102 bool isneg = isNegEdge(e);
103 uint numEdges = node->numEdges;
104 Node * clone = allocBaseNode(node->type, numEdges);
105 for(uint i=0; i < numEdges; i++) {
106 clone->edges[i] = cloneEdge(node->edges[i]);
108 return isneg ? constraintNegate((Edge) {clone}) : (Edge) {clone};
111 void freeEdgeRec(Edge e) {
112 if (edgeIsVarConst(e))
114 Node * node = getNodePtrFromEdge(e);
115 uint numEdges = node->numEdges;
116 for(uint i=0; i < numEdges; i++) {
117 freeEdgeRec(node->edges[i]);
121 void freeEdgeCNF(Edge e) {
122 Node * node = getNodePtrFromEdge(e);
123 uint numEdges = node->numEdges;
124 for(uint i=0; i < numEdges; i++) {
125 Edge ec = node->edges[i];
126 if (!edgeIsVarConst(ec)) {
127 ourfree(ec.node_ptr);
133 void addEdgeToResizeNode(Node ** node, Edge e) {
134 Node *currnode = *node;
135 if (currnode->capacity == currnode->numEdges) {
136 Node *newnode = allocResizeNode( currnode->capacity << 1);
137 newnode->numEdges = currnode->numEdges;
138 memcpy(newnode->edges, currnode->edges, newnode->numEdges * sizeof(Edge));
143 currnode->edges[currnode->numEdges++] = e;
146 void mergeFreeNodeToResizeNode(Node **node, Node * innode) {
147 Node * currnode = *node;
148 uint currEdges = currnode->numEdges;
149 uint inEdges = innode->numEdges;
151 uint newsize = currEdges + inEdges;
152 if (newsize >= currnode->capacity) {
153 if (newsize < innode->capacity) {
157 *node = currnode = tmp;
159 Node *newnode = allocResizeNode( newsize << 1);
160 newnode->numEdges = currnode->numEdges;
161 memcpy(newnode->edges, currnode->edges, newnode->numEdges * sizeof(Edge));
167 if (inEdges > currEdges && newsize < innode->capacity) {
171 *node = currnode = tmp;
174 memcpy(&currnode->edges[currnode->numEdges], innode->edges, innode->numEdges * sizeof(Edge));
175 currnode->numEdges += innode->numEdges;
179 void mergeNodeToResizeNode(Node **node, Node * innode) {
180 Node * currnode = *node;
181 uint currEdges = currnode->numEdges;
182 uint inEdges = innode->numEdges;
183 uint newsize = currEdges + inEdges;
184 if (newsize >= currnode->capacity) {
185 Node *newnode = allocResizeNode( newsize << 1);
186 newnode->numEdges = currnode->numEdges;
187 memcpy(newnode->edges, currnode->edges, newnode->numEdges * sizeof(Edge));
192 memcpy(&currnode->edges[currnode->numEdges], innode->edges, inEdges * sizeof(Edge));
193 currnode->numEdges += inEdges;
196 Edge createNode(NodeType type, uint numEdges, Edge *edges) {
197 Edge e = {allocNode(type, numEdges, edges)};
201 Edge constraintOR(CNF *cnf, uint numEdges, Edge *edges) {
202 Edge edgearray[numEdges];
204 for (uint i = 0; i < numEdges; i++) {
205 edgearray[i] = constraintNegate(edges[i]);
207 Edge eand = constraintAND(cnf, numEdges, edgearray);
208 return constraintNegate(eand);
211 Edge constraintOR2(CNF *cnf, Edge left, Edge right) {
212 Edge lneg = constraintNegate(left);
213 Edge rneg = constraintNegate(right);
214 Edge eand = constraintAND2(cnf, lneg, rneg);
215 return constraintNegate(eand);
218 int comparefunction(const Edge *e1, const Edge *e2) {
219 if (e1->node_ptr == e2->node_ptr)
221 if (((uintptr_t)e1->node_ptr) < ((uintptr_t) e2->node_ptr))
227 Edge constraintAND(CNF *cnf, uint numEdges, Edge *edges) {
228 ASSERT(numEdges != 0);
230 bsdqsort(edges, numEdges, sizeof(Edge), (int (*)(const void *, const void *))comparefunction);
232 while (initindex < numEdges && equalsEdge(edges[initindex], E_True))
235 uint remainSize = numEdges - initindex;
239 else if (remainSize == 1)
240 return edges[initindex];
241 else if (equalsEdge(edges[initindex], E_False))
244 /** De-duplicate array */
246 edges[lowindex] = edges[initindex++];
248 for (; initindex < numEdges; initindex++) {
249 Edge e1 = edges[lowindex];
250 Edge e2 = edges[initindex];
251 if (sameNodeVarEdge(e1, e2)) {
252 if (!sameSignEdge(e1, e2)) {
256 edges[++lowindex] = edges[initindex];
258 lowindex++; //Make lowindex look like size
264 isNegNodeEdge(edges[0]) && isNegNodeEdge(edges[1]) &&
265 getNodeType(edges[0]) == NodeType_AND &&
266 getNodeType(edges[1]) == NodeType_AND &&
267 getNodeSize(edges[0]) == 2 &&
268 getNodeSize(edges[1]) == 2) {
269 Edge *e0edges = getEdgeArray(edges[0]);
270 Edge *e1edges = getEdgeArray(edges[1]);
271 if (sameNodeOppSign(e0edges[0], e1edges[0])) {
272 return constraintNegate(constraintITE(cnf, e0edges[0], e0edges[1], e1edges[1]));
273 } else if (sameNodeOppSign(e0edges[0], e1edges[1])) {
274 return constraintNegate(constraintITE(cnf, e0edges[0], e0edges[1], e1edges[0]));
275 } else if (sameNodeOppSign(e0edges[1], e1edges[0])) {
276 return constraintNegate(constraintITE(cnf, e0edges[1], e0edges[0], e1edges[1]));
277 } else if (sameNodeOppSign(e0edges[1], e1edges[1])) {
278 return constraintNegate(constraintITE(cnf, e0edges[1], e0edges[0], e1edges[0]));
282 return createNode(NodeType_AND, lowindex, edges);
285 Edge constraintAND2(CNF *cnf, Edge left, Edge right) {
286 Edge edges[2] = {left, right};
287 return constraintAND(cnf, 2, edges);
290 Edge constraintIMPLIES(CNF *cnf, Edge left, Edge right) {
293 array[1] = constraintNegate(right);
294 Edge eand = constraintAND(cnf, 2, array);
295 return constraintNegate(eand);
298 Edge constraintIFF(CNF *cnf, Edge left, Edge right) {
299 bool negate = !sameSignEdge(left, right);
300 Edge lpos = getNonNeg(left);
301 Edge rpos = getNonNeg(right);
304 if (equalsEdge(lpos, rpos)) {
306 } else if (ltEdge(lpos, rpos)) {
307 Edge edges[] = {lpos, rpos};
308 e = (edgeIsConst(lpos)) ? rpos : createNode(NodeType_IFF, 2, edges);
310 Edge edges[] = {rpos, lpos};
311 e = (edgeIsConst(rpos)) ? lpos : createNode(NodeType_IFF, 2, edges);
314 e = constraintNegate(e);
318 Edge constraintITE(CNF *cnf, Edge cond, Edge thenedge, Edge elseedge) {
319 if (isNegEdge(cond)) {
320 cond = constraintNegate(cond);
326 bool negate = isNegEdge(thenedge);
328 thenedge = constraintNegate(thenedge);
329 elseedge = constraintNegate(elseedge);
333 if (equalsEdge(cond, E_True)) {
335 } else if (equalsEdge(thenedge, E_True) || equalsEdge(cond, thenedge)) {
336 Edge array[] = {cond, elseedge};
337 result = constraintOR(cnf, 2, array);
338 } else if (equalsEdge(elseedge, E_True) || sameNodeOppSign(cond, elseedge)) {
339 result = constraintIMPLIES(cnf, cond, thenedge);
340 } else if (equalsEdge(thenedge, E_False) || equalsEdge(cond, elseedge)) {
341 Edge array[] = {cond, thenedge};
342 result = constraintAND(cnf, 2, array);
343 } else if (equalsEdge(thenedge, elseedge)) {
345 } else if (sameNodeOppSign(thenedge, elseedge)) {
346 if (ltEdge(cond, thenedge)) {
347 Edge array[] = {cond, thenedge};
348 result = createNode(NodeType_IFF, 2, array);
350 Edge array[] = {thenedge, cond};
351 result = createNode(NodeType_IFF, 2, array);
354 Edge edges[] = {cond, thenedge, elseedge};
355 result = createNode(NodeType_ITE, 3, edges);
358 result = constraintNegate(result);
362 Edge simplifyCNF(CNF *cnf, Edge input) {
363 if (edgeIsVarConst(input)) {
364 Node *newvec = allocResizeNode(1);
365 addEdgeToResizeNode(&newvec, input);
366 return (Edge) {newvec};
368 bool negated = isNegEdge(input);
369 Node * node = getNodePtrFromEdge(input);
370 NodeType type = node->type;
372 if (type == NodeType_AND) {
374 Node *newvec = allocResizeNode(node->numEdges);
375 uint numEdges = node->numEdges;
376 for(uint i = 0; i < numEdges; i++) {
377 Edge e = simplifyCNF(cnf, node->edges[i]);
378 mergeFreeNodeToResizeNode(&newvec, e.node_ptr);
380 return (Edge) {newvec};
382 Edge cond = node->edges[0];
383 Edge thenedge = node->edges[1];
384 Edge elseedge = (type == NodeType_IFF) ? constraintNegate(thenedge) : node->edges[2];
385 Edge thenedges[] = {cond, constraintNegate(thenedge)};
386 Edge thencons = constraintNegate(createNode(NodeType_AND, 2, thenedges));
387 Edge elseedges[] = {constraintNegate(cond), constraintNegate(elseedge)};
388 Edge elsecons = constraintNegate(createNode(NodeType_AND, 2, elseedges));
389 Edge thencnf = simplifyCNF(cnf, thencons);
390 Edge elsecnf = simplifyCNF(cnf, elsecons);
391 //free temporary nodes
392 ourfree(getNodePtrFromEdge(thencons));
393 ourfree(getNodePtrFromEdge(elsecons));
394 Node * result = thencnf.node_ptr;
395 mergeFreeNodeToResizeNode(&result, elsecnf.node_ptr);
396 return (Edge) {result};
399 if (type == NodeType_AND) {
401 uint numEdges = node->numEdges;
403 for(uint i = 0; i < numEdges; i++) {
404 Edge e = node->edges[i];
405 bool enegate = isNegEdge(e);
406 if (!edgeIsVarConst(e)) {
407 Node * enode = getNodePtrFromEdge(e);
408 NodeType etype = enode->type;
410 if (etype == NodeType_AND) {
412 uint eNumEdges = enode->numEdges;
413 Node * newnode = allocResizeNode(0);
414 Node * clause = allocBaseNode(NodeType_AND, numEdges);
415 memcpy(clause->edges, node->edges, sizeof(Edge) * i);
416 if ((i + 1) < numEdges) {
417 memcpy(&clause->edges[i+1], &node->edges[i+1], sizeof(Edge) * (numEdges - i - 1));
420 for(uint j = 0; j < eNumEdges; j++) {
421 clause->edges[i] = constraintNegate(enode->edges[j]);
422 Edge simplify = simplifyCNF(cnf, constraintNegate((Edge){clause}));
423 mergeFreeNodeToResizeNode(&newnode, simplify.node_ptr);
426 return (Edge) {newnode};
429 Edge cond = enode->edges[0];
430 Edge thenedge = enode->edges[1];
431 Edge elseedge = (enode->type == NodeType_IFF) ? constraintNegate(thenedge) : enode->edges[2];
432 Edge thenedges[] = {cond, constraintNegate(thenedge)};
433 Edge thencons = constraintNegate(createNode(NodeType_AND, 2, thenedges));
434 Edge elseedges[] = {constraintNegate(cond), constraintNegate(elseedge)};
435 Edge elsecons = constraintNegate(createNode(NodeType_AND, 2, elseedges));
438 Node * newnode = allocResizeNode(0);
439 Node * clause = allocBaseNode(NodeType_AND, numEdges);
440 memcpy(clause->edges, node->edges, sizeof(Edge) * i);
441 if ((i + 1) < numEdges) {
442 memcpy(&clause->edges[i+1], &node->edges[i+1], sizeof(Edge) * (numEdges - i - 1));
445 clause->edges[i] = constraintNegate(thencons);
446 Edge simplify = simplifyCNF(cnf, constraintNegate((Edge){clause}));
447 mergeFreeNodeToResizeNode(&newnode, simplify.node_ptr);
449 clause->edges[i] = constraintNegate(elsecons);
450 simplify = simplifyCNF(cnf, constraintNegate((Edge){clause}));
451 mergeFreeNodeToResizeNode(&newnode, simplify.node_ptr);
453 //free temporary nodes
454 ourfree(getNodePtrFromEdge(thencons));
455 ourfree(getNodePtrFromEdge(elsecons));
457 return (Edge) {newnode};
460 if (etype == NodeType_AND) {
462 uint eNumEdges = enode->numEdges;
463 Node * clause = allocBaseNode(NodeType_AND, eNumEdges + numEdges - 1);
464 memcpy(clause->edges, node->edges, sizeof(Edge) * i);
465 if ((i + 1) < numEdges) {
466 memcpy(&clause->edges[i], &node->edges[i+1], sizeof(Edge) * (numEdges - i - 1));
468 memcpy(&clause->edges[numEdges-1], enode->edges, sizeof(Edge) * eNumEdges);
469 Edge eclause = {clause};
470 Edge result = simplifyCNF(cnf, constraintNegate(eclause));
474 //OR of !(IFF or ITE)
475 Edge cond = node->edges[0];
476 Edge thenedge = node->edges[1];
477 Edge elseedge = (type == NodeType_IFF) ? constraintNegate(thenedge) : node->edges[2];
478 Edge thenedges[] = {cond, constraintNegate(thenedge)};
479 Edge thencons = createNode(NodeType_AND, 2, thenedges);
480 Edge elseedges[] = {constraintNegate(cond), constraintNegate(elseedge)};
481 Edge elsecons = createNode(NodeType_AND, 2, elseedges);
484 Node * clause = allocBaseNode(NodeType_AND, numEdges + 1);
485 memcpy(clause->edges, node->edges, sizeof(Edge) * i);
486 if ((i + 1) < numEdges) {
487 memcpy(&clause->edges[i], &node->edges[i+1], sizeof(Edge) * (numEdges - i - 1));
489 clause->edges[numEdges-1] = constraintNegate(thencons);
490 clause->edges[numEdges] = constraintNegate(elsecons);
491 Edge result = simplifyCNF(cnf, constraintNegate((Edge) {clause}));
492 //free temporary nodes
493 ourfree(getNodePtrFromEdge(thencons));
494 ourfree(getNodePtrFromEdge(elsecons));
502 Node *newvec = allocResizeNode(numEdges);
503 for(uint i=0; i < numEdges; i++) {
504 addEdgeToResizeNode(&newvec, constraintNegate(node->edges[i]));
506 Node * result = allocResizeNode(1);
507 addEdgeToResizeNode(&result, (Edge){newvec});
508 return (Edge) {result};
510 Edge cond = node->edges[0];
511 Edge thenedge = node->edges[1];
512 Edge elseedge = (type == NodeType_IFF) ? constraintNegate(thenedge) : node->edges[2];
515 Edge thenedges[] = {cond, constraintNegate(thenedge)};
516 Edge thencons = createNode(NodeType_AND, 2, thenedges);
517 Edge elseedges[] = {constraintNegate(cond), constraintNegate(elseedge)};
518 Edge elsecons = createNode(NodeType_AND, 2, elseedges);
520 Edge combinededges[] = {constraintNegate(thencons), constraintNegate(elsecons)};
521 Edge combined = constraintNegate(createNode(NodeType_AND, 2, combinededges));
522 Edge result = simplifyCNF(cnf, combined);
523 //free temporary nodes
524 ourfree(getNodePtrFromEdge(thencons));
525 ourfree(getNodePtrFromEdge(elsecons));
526 ourfree(getNodePtrFromEdge(combined));
532 void outputCNF(CNF *cnf, Edge cnfform) {
533 Node * andNode = cnfform.node_ptr;
534 uint numEdges = andNode->numEdges;
535 for(uint i=0; i < numEdges; i++) {
536 Edge e = andNode->edges[i];
537 if (edgeIsVarConst(e)) {
538 int array[1] = {getEdgeVar(e)};
539 ASSERT(array[0] != 0);
540 addArrayClauseLiteral(cnf->solver, 1, array);
542 Node * clause = e.node_ptr;
543 uint cnumEdges = clause->numEdges;
544 if (cnumEdges > cnf->asize) {
545 cnf->asize = cnumEdges << 1;
547 cnf->array = (int *) ourmalloc(sizeof(int) * cnf->asize);
549 int * array = cnf->array;
550 for(uint j=0; j < cnumEdges; j++) {
551 array[j] = getEdgeVar(clause->edges[j]);
552 ASSERT(array[j] != 0);
554 addArrayClauseLiteral(cnf->solver, cnumEdges, array);
559 void addConstraintCNF(CNF *cnf, Edge constraint) {
560 if (equalsEdge(constraint, E_True))
562 else if (equalsEdge(constraint, E_False)) {
567 Edge cnfform = simplifyCNF(cnf, constraint);
568 freeEdgeRec(constraint);
569 outputCNF(cnf, cnfform);
570 freeEdgeCNF(cnfform);
572 model_print("****SATC_ADDING NEW Constraint*****\n");
573 printCNF(constraint);
574 model_print("\n******************************\n");
578 Edge constraintNewVar(CNF *cnf) {
579 uint varnum = cnf->varcount++;
580 Edge e = {(Node *) ((((uintptr_t)varnum) << VAR_SHIFT) | EDGE_IS_VAR_CONSTANT) };
584 int solveCNF(CNF *cnf) {
585 long long startTime = getTimeNano();
586 finishedClauses(cnf->solver);
587 long long startSolve = getTimeNano();
588 int result = cnf->unsat ? IS_UNSAT : solve(cnf->solver);
589 long long finishTime = getTimeNano();
590 cnf->encodeTime = startSolve - startTime;
591 model_print("CNF Encode time: %f\n", cnf->encodeTime / 1000000000.0);
592 cnf->solveTime = finishTime - startSolve;
593 model_print("Solve time: %f\n", cnf->solveTime / 1000000000.0);
597 bool getValueCNF(CNF *cnf, Edge var) {
598 Literal l = getEdgeVar(var);
599 bool isneg = (l < 0);
601 return isneg ^ getValueSolver(cnf->solver, l);
604 void printCNF(Edge e) {
605 if (edgeIsVarConst(e)) {
606 Literal l = getEdgeVar(e);
607 model_print ("%d", l);
610 bool isNeg = isNegEdge(e);
611 if (edgeIsConst(e)) {
618 Node *n = getNodePtrFromEdge(e);
620 //Pretty print things that are equivalent to OR's
621 if (getNodeType(e) == NodeType_AND) {
623 for (uint i = 0; i < n->numEdges; i++) {
624 Edge e = n->edges[i];
627 printCNF(constraintNegate(e));
635 switch (getNodeType(e)) {
647 for (uint i = 0; i < n->numEdges; i++) {
648 Edge e = n->edges[i];
656 Edge generateBinaryConstraint(CNF *cnf, uint numvars, Edge *vars, uint value) {
657 Edge carray[numvars];
658 for (uint j = 0; j < numvars; j++) {
659 carray[j] = ((value & 1) == 1) ? vars[j] : constraintNegate(vars[j]);
663 return constraintAND(cnf, numvars, carray);
666 /** Generates a constraint to ensure that all encodings are less than value */
667 Edge generateLTValueConstraint(CNF *cnf, uint numvars, Edge *vars, uint value) {
668 Edge orarray[numvars];
669 Edge andarray[numvars];
675 for (uint j = 0; j < numvars; j++) {
677 orarray[ori++] = constraintNegate(vars[j]);
680 //no ones to flip, so bail now...
682 return constraintAND(cnf, andi, andarray);
684 andarray[andi++] = constraintOR(cnf, ori, orarray);
686 value = value + (1 << (__builtin_ctz(value)));
691 Edge generateEquivNVConstraint(CNF *cnf, uint numvars, Edge *var1, Edge *var2) {
695 for (uint i = 0; i < numvars; i++) {
696 array[i] = constraintIFF(cnf, var1[i], var2[i]);
698 return constraintAND(cnf, numvars, array);
701 Edge generateLTConstraint(CNF *cnf, uint numvars, Edge *var1, Edge *var2) {
704 Edge result = constraintAND2(cnf, constraintNegate( var1[0]), var2[0]);
705 for (uint i = 1; i < numvars; i++) {
706 Edge lt = constraintAND2(cnf, constraintNegate( var1[i]), var2[i]);
707 Edge eq = constraintAND2(cnf, constraintIFF(cnf, var1[i], var2[i]), result);
708 result = constraintOR2(cnf, lt, eq);
713 Edge generateLTEConstraint(CNF *cnf, uint numvars, Edge *var1, Edge *var2) {
716 Edge result = constraintIMPLIES(cnf, var1[0], var2[0]);
717 for (uint i = 1; i < numvars; i++) {
718 Edge lt = constraintAND2(cnf, constraintNegate( var1[i]), var2[i]);
719 Edge eq = constraintAND2(cnf, constraintIFF(cnf, var1[i], var2[i]), result);
720 result = constraintOR2(cnf, lt, eq);