View Javadoc

1   /*******************************************************************************
2    * SAT4J: a SATisfiability library for Java Copyright (C) 2004, 2012 Artois University and CNRS
3    *
4    * All rights reserved. This program and the accompanying materials
5    * are made available under the terms of the Eclipse Public License v1.0
6    * which accompanies this distribution, and is available at
7    *  http://www.eclipse.org/legal/epl-v10.html
8    *
9    * Alternatively, the contents of this file may be used under the terms of
10   * either the GNU Lesser General Public License Version 2.1 or later (the
11   * "LGPL"), in which case the provisions of the LGPL are applicable instead
12   * of those above. If you wish to allow use of your version of this file only
13   * under the terms of the LGPL, and not to allow others to use your version of
14   * this file under the terms of the EPL, indicate your decision by deleting
15   * the provisions above and replace them with the notice and other provisions
16   * required by the LGPL. If you do not delete the provisions above, a recipient
17   * may use your version of this file under the terms of the EPL or the LGPL.
18   *
19   * Based on the original MiniSat specification from:
20   *
21   * An extensible SAT solver. Niklas Een and Niklas Sorensson. Proceedings of the
22   * Sixth International Conference on Theory and Applications of Satisfiability
23   * Testing, LNCS 2919, pp 502-518, 2003.
24   *
25   * See www.minisat.se for the original solver in C++.
26   *
27   * Contributors:
28   *   CRIL - initial API and implementation
29   *******************************************************************************/
30  package org.sat4j.tools;
31  
32  import java.math.BigInteger;
33  
34  import org.sat4j.core.Vec;
35  import org.sat4j.core.VecInt;
36  import org.sat4j.specs.ContradictionException;
37  import org.sat4j.specs.IConstr;
38  import org.sat4j.specs.ISolver;
39  import org.sat4j.specs.IVec;
40  import org.sat4j.specs.IVecInt;
41  
42  /**
43   * Utility class to easily feed a SAT solver using logical gates.
44   * 
45   * @author leberre
46   * 
47   */
48  public class GateTranslator extends SolverDecorator<ISolver> {
49  
50      /**
51       * 
52       */
53      private static final long serialVersionUID = 1L;
54  
55      public GateTranslator(ISolver solver) {
56          super(solver);
57      }
58  
59      /**
60       * translate y <=> FALSE into a clause.
61       * 
62       * @param y
63       *            a variable to falsify
64       * @throws ContradictionException
65       *             iff a trivial inconsistency is found.
66       * @since 2.1
67       */
68      public IConstr gateFalse(int y) throws ContradictionException {
69          IVecInt clause = new VecInt(2);
70          clause.push(-y);
71          return processClause(clause);
72      }
73  
74      /**
75       * translate y <=> TRUE into a clause.
76       * 
77       * @param y
78       *            a variable to verify
79       * @throws ContradictionException
80       * @since 2.1
81       */
82      public IConstr gateTrue(int y) throws ContradictionException {
83          IVecInt clause = new VecInt(2);
84          clause.push(y);
85          return processClause(clause);
86      }
87  
88      /**
89       * translate y <=> if x1 then x2 else x3 into clauses.
90       * 
91       * @param y
92       * @param x1
93       *            the selector variable
94       * @param x2
95       * @param x3
96       * @throws ContradictionException
97       * @since 2.1
98       */
99      public IConstr[] ite(int y, int x1, int x2, int x3)
100             throws ContradictionException {
101         IConstr[] constrs = new IConstr[6];
102         IVecInt clause = new VecInt(5);
103         // y <=> (x1 -> x2) and (not x1 -> x3)
104         // y -> (x1 -> x2) and (not x1 -> x3)
105         clause.push(-y).push(-x1).push(x2);
106         constrs[0] = processClause(clause);
107         clause.clear();
108         clause.push(-y).push(x1).push(x3);
109         constrs[1] = processClause(clause);
110         // y <- (x1 -> x2) and (not x1 -> x3)
111         // not(x1 -> x2) or not(not x1 -> x3) or y
112         // x1 and not x2 or not x1 and not x3 or y
113         // (x1 and not x2) or ((not x1 or y) and (not x3 or y))
114         // (x1 or not x1 or y) and (not x2 or not x1 or y) and (x1 or not x3 or
115         // y) and (not x2 or not x3 or y)
116         // not x1 or not x2 or y and x1 or not x3 or y and not x2 or not x3 or y
117         clause.clear();
118         clause.push(-x1).push(-x2).push(y);
119         constrs[2] = processClause(clause);
120         clause.clear();
121         clause.push(x1).push(-x3).push(y);
122         constrs[3] = processClause(clause);
123         clause.clear();
124         clause.push(-x2).push(-x3).push(y);
125         constrs[4] = processClause(clause);
126         // taken from Niklas Een et al SAT 2007 paper
127         // Adding the following redundant clause will improve unit propagation
128         // y -> x2 or x3
129         clause.clear();
130         clause.push(-y).push(x2).push(x3);
131         constrs[5] = processClause(clause);
132         return constrs;
133     }
134 
135     /**
136      * Translate y <=> x1 /\ x2 /\ ... /\ xn into clauses.
137      * 
138      * @param y
139      * @param literals
140      *            the x1 ... xn literals.
141      * @throws ContradictionException
142      * @since 2.1
143      */
144     public IConstr[] and(int y, IVecInt literals) throws ContradictionException {
145         // y <=> AND x1 ... xn
146         IConstr[] constrs = new IConstr[literals.size() + 1];
147         // y <= x1 .. xn
148         IVecInt clause = new VecInt(literals.size() + 2);
149         clause.push(y);
150         for (int i = 0; i < literals.size(); i++) {
151             clause.push(-literals.get(i));
152         }
153         constrs[0] = processClause(clause);
154         clause.clear();
155         for (int i = 0; i < literals.size(); i++) {
156             // y => xi
157             clause.clear();
158             clause.push(-y);
159             clause.push(literals.get(i));
160             constrs[i + 1] = processClause(clause);
161         }
162         return constrs;
163     }
164 
165     /**
166      * Translate y <=> x1 /\ x2
167      * 
168      * @param y
169      * @param x1
170      * @param x2
171      * @throws ContradictionException
172      * @since 2.1
173      */
174     public IConstr[] and(int y, int x1, int x2) throws ContradictionException {
175         IVecInt clause = new VecInt(4);
176         IConstr[] constrs = new IConstr[3];
177         clause.push(-y);
178         clause.push(x1);
179         constrs[0] = addClause(clause);
180         clause.clear();
181         clause.push(-y);
182         clause.push(x2);
183         constrs[1] = addClause(clause);
184         clause.clear();
185         clause.push(y);
186         clause.push(-x1);
187         clause.push(-x2);
188         constrs[2] = addClause(clause);
189         return constrs;
190     }
191 
192     /**
193      * translate y <=> x1 \/ x2 \/ ... \/ xn into clauses.
194      * 
195      * @param y
196      * @param literals
197      * @throws ContradictionException
198      * @since 2.1
199      */
200     public IConstr[] or(int y, IVecInt literals) throws ContradictionException {
201         // y <=> OR x1 x2 ...xn
202         // y => x1 x2 ... xn
203         IConstr[] constrs = new IConstr[literals.size() + 1];
204         IVecInt clause = new VecInt(literals.size() + 2);
205         literals.copyTo(clause);
206         clause.push(-y);
207         constrs[0] = processClause(clause);
208         clause.clear();
209         for (int i = 0; i < literals.size(); i++) {
210             // xi => y
211             clause.clear();
212             clause.push(y);
213             clause.push(-literals.get(i));
214             constrs[i + 1] = processClause(clause);
215         }
216         return constrs;
217     }
218 
219     /**
220      * translate y <= x1 \/ x2 \/ ... \/ xn into clauses.
221      * 
222      * @param y
223      * @param literals
224      * @throws ContradictionException
225      * @since 2.1
226      */
227     public IConstr[] halfOr(int y, IVecInt literals)
228             throws ContradictionException {
229         IConstr[] constrs = new IConstr[literals.size()];
230         IVecInt clause = new VecInt(literals.size() + 2);
231         for (int i = 0; i < literals.size(); i++) {
232             // xi => y
233             clause.clear();
234             clause.push(y);
235             clause.push(-literals.get(i));
236             constrs[i] = processClause(clause);
237         }
238         return constrs;
239     }
240 
241     private IConstr processClause(IVecInt clause) throws ContradictionException {
242         return addClause(clause);
243     }
244 
245     /**
246      * Translate y <=> not x into clauses.
247      * 
248      * @param y
249      * @param x
250      * @throws ContradictionException
251      * @since 2.1
252      */
253     public IConstr[] not(int y, int x) throws ContradictionException {
254         IConstr[] constrs = new IConstr[2];
255         IVecInt clause = new VecInt(3);
256         // y <=> not x
257         // y => not x = not y or not x
258         clause.push(-y).push(-x);
259         constrs[0] = processClause(clause);
260         // y <= not x = y or x
261         clause.clear();
262         clause.push(y).push(x);
263         constrs[1] = processClause(clause);
264         return constrs;
265     }
266 
267     /**
268      * translate y <=> x1 xor x2 xor ... xor xn into clauses.
269      * 
270      * @param y
271      * @param literals
272      * @throws ContradictionException
273      * @since 2.1
274      */
275     public IConstr[] xor(int y, IVecInt literals) throws ContradictionException {
276         literals.push(-y);
277         int[] f = new int[literals.size()];
278         literals.copyTo(f);
279         IVec<IConstr> vconstrs = new Vec<IConstr>();
280         xor2Clause(f, 0, false, vconstrs);
281         IConstr[] constrs = new IConstr[vconstrs.size()];
282         vconstrs.copyTo(constrs);
283         return constrs;
284     }
285 
286     /**
287      * translate y <=> (x1 <=> x2 <=> ... <=> xn) into clauses.
288      * 
289      * @param y
290      * @param literals
291      * @throws ContradictionException
292      * @since 2.1
293      */
294     public IConstr[] iff(int y, IVecInt literals) throws ContradictionException {
295         literals.push(y);
296         int[] f = new int[literals.size()];
297         literals.copyTo(f);
298         IVec<IConstr> vconstrs = new Vec<IConstr>();
299         iff2Clause(f, 0, false, vconstrs);
300         IConstr[] constrs = new IConstr[vconstrs.size()];
301         vconstrs.copyTo(constrs);
302         return constrs;
303     }
304 
305     /**
306      * @since 2.2
307      */
308     public void xor(int x, int a, int b) throws ContradictionException {
309         IVecInt clause = new VecInt(3);
310         clause.push(-a).push(b).push(x);
311         processClause(clause);
312         clause.clear();
313         clause.push(a).push(-b).push(x);
314         processClause(clause);
315         clause.clear();
316         clause.push(-a).push(-b).push(-x);
317         processClause(clause);
318         clause.clear();
319         clause.push(a).push(b).push(-x);
320         processClause(clause);
321         clause.clear();
322     }
323 
324     private void xor2Clause(int[] f, int prefix, boolean negation,
325             IVec<IConstr> constrs) throws ContradictionException {
326         if (prefix == f.length - 1) {
327             IVecInt clause = new VecInt(f.length + 1);
328             for (int i = 0; i < f.length - 1; ++i) {
329                 clause.push(f[i]);
330             }
331             clause.push(f[f.length - 1] * (negation ? -1 : 1));
332             constrs.push(processClause(clause));
333             return;
334         }
335 
336         if (negation) {
337             f[prefix] = -f[prefix];
338             xor2Clause(f, prefix + 1, false, constrs);
339             f[prefix] = -f[prefix];
340 
341             xor2Clause(f, prefix + 1, true, constrs);
342         } else {
343             xor2Clause(f, prefix + 1, false, constrs);
344 
345             f[prefix] = -f[prefix];
346             xor2Clause(f, prefix + 1, true, constrs);
347             f[prefix] = -f[prefix];
348         }
349     }
350 
351     private void iff2Clause(int[] f, int prefix, boolean negation,
352             IVec<IConstr> constrs) throws ContradictionException {
353         if (prefix == f.length - 1) {
354             IVecInt clause = new VecInt(f.length + 1);
355             for (int i = 0; i < f.length - 1; ++i) {
356                 clause.push(f[i]);
357             }
358             clause.push(f[f.length - 1] * (negation ? -1 : 1));
359             processClause(clause);
360             return;
361         }
362 
363         if (negation) {
364             iff2Clause(f, prefix + 1, false, constrs);
365             f[prefix] = -f[prefix];
366             iff2Clause(f, prefix + 1, true, constrs);
367             f[prefix] = -f[prefix];
368         } else {
369             f[prefix] = -f[prefix];
370             iff2Clause(f, prefix + 1, false, constrs);
371             f[prefix] = -f[prefix];
372             iff2Clause(f, prefix + 1, true, constrs);
373         }
374     }
375 
376     // From Een and Sorensson JSAT 2006 paper
377 
378     /**
379      * @since 2.2
380      */
381     public void fullAdderSum(int x, int a, int b, int c)
382             throws ContradictionException {
383         IVecInt clause = new VecInt(4);
384         // -a /\ -b /\ -c -> -x
385         clause.push(a).push(b).push(c).push(-x);
386         processClause(clause);
387         clause.clear();
388         // -a /\ b /\ c -> -x
389         clause.push(a).push(-b).push(-c).push(-x);
390         processClause(clause);
391         clause.clear();
392         clause.push(-a).push(b).push(-c).push(-x);
393         processClause(clause);
394         clause.clear();
395         clause.push(-a).push(-b).push(c).push(-x);
396         processClause(clause);
397         clause.clear();
398         clause.push(-a).push(-b).push(-c).push(x);
399         processClause(clause);
400         clause.clear();
401         clause.push(-a).push(b).push(c).push(x);
402         processClause(clause);
403         clause.clear();
404         clause.push(a).push(-b).push(c).push(x);
405         processClause(clause);
406         clause.clear();
407         clause.push(a).push(b).push(-c).push(x);
408         processClause(clause);
409         clause.clear();
410     }
411 
412     /**
413      * @since 2.2
414      */
415     public void fullAdderCarry(int x, int a, int b, int c)
416             throws ContradictionException {
417         IVecInt clause = new VecInt(3);
418         clause.push(-b).push(-c).push(x);
419         processClause(clause);
420         clause.clear();
421         clause.push(-a).push(-c).push(x);
422         processClause(clause);
423         clause.clear();
424         clause.push(-a).push(-b).push(x);
425         processClause(clause);
426         clause.clear();
427         clause.push(b).push(c).push(-x);
428         processClause(clause);
429         clause.clear();
430         clause.push(a).push(c).push(-x);
431         processClause(clause);
432         clause.clear();
433         clause.push(a).push(b).push(-x);
434         processClause(clause);
435         clause.clear();
436     }
437 
438     /**
439      * @since 2.2
440      */
441     public void additionalFullAdderConstraints(int xcarry, int xsum, int a,
442             int b, int c) throws ContradictionException {
443         IVecInt clause = new VecInt(3);
444         clause.push(-xcarry).push(-xsum).push(a);
445         processClause(clause);
446         clause.push(-xcarry).push(-xsum).push(b);
447         processClause(clause);
448         clause.push(-xcarry).push(-xsum).push(c);
449         processClause(clause);
450         clause.push(xcarry).push(xsum).push(-a);
451         processClause(clause);
452         clause.push(xcarry).push(xsum).push(-b);
453         processClause(clause);
454         clause.push(xcarry).push(xsum).push(-c);
455         processClause(clause);
456     }
457 
458     /**
459      * @since 2.2
460      */
461     public void halfAdderSum(int x, int a, int b) throws ContradictionException {
462         xor(x, a, b);
463     }
464 
465     /**
466      * @since 2.2
467      */
468     public void halfAdderCarry(int x, int a, int b)
469             throws ContradictionException {
470         and(x, a, b);
471     }
472 
473     /**
474      * Translate an optimization function into constraints and provides the
475      * binary literals in results. Works only when the value of the objective
476      * function is positive.
477      * 
478      * @since 2.2
479      */
480     public void optimisationFunction(IVecInt literals, IVec<BigInteger> coefs,
481             IVecInt result) throws ContradictionException {
482         IVec<IVecInt> buckets = new Vec<IVecInt>();
483         IVecInt bucket;
484         // filling the buckets
485         for (int i = 0; i < literals.size(); i++) {
486             int p = literals.get(i);
487             BigInteger a = coefs.get(i);
488             for (int j = 0; j < a.bitLength(); j++) {
489                 bucket = createIfNull(buckets, j);
490                 if (a.testBit(j)) {
491                     bucket.push(p);
492                 }
493             }
494         }
495         // creating the adder
496         int x, y, z;
497         int sum, carry;
498         for (int i = 0; i < buckets.size(); i++) {
499             bucket = buckets.get(i);
500             while (bucket.size() >= 3) {
501                 x = bucket.get(0);
502                 y = bucket.get(1);
503                 z = bucket.get(2);
504                 bucket.remove(x);
505                 bucket.remove(y);
506                 bucket.remove(z);
507                 sum = nextFreeVarId(true);
508                 carry = nextFreeVarId(true);
509                 fullAdderSum(sum, x, y, z);
510                 fullAdderCarry(carry, x, y, z);
511                 additionalFullAdderConstraints(carry, sum, x, y, z);
512                 bucket.push(sum);
513                 createIfNull(buckets, i + 1).push(carry);
514             }
515             while (bucket.size() == 2) {
516                 x = bucket.get(0);
517                 y = bucket.get(1);
518                 bucket.remove(x);
519                 bucket.remove(y);
520                 sum = nextFreeVarId(true);
521                 carry = nextFreeVarId(true);
522                 halfAdderSum(sum, x, y);
523                 halfAdderCarry(carry, x, y);
524                 bucket.push(sum);
525                 createIfNull(buckets, i + 1).push(carry);
526             }
527             assert bucket.size() == 1;
528             result.push(bucket.last());
529             bucket.pop();
530             assert bucket.isEmpty();
531         }
532     }
533 
534     /**
535      * Create a new bucket if it does not exists. Works only because the buckets
536      * are explored in increasing order.
537      * 
538      * @param buckets
539      * @param i
540      * @return
541      */
542     private IVecInt createIfNull(IVec<IVecInt> buckets, int i) {
543         IVecInt bucket = buckets.get(i);
544         if (bucket == null) {
545             bucket = new VecInt();
546             buckets.push(bucket);
547             assert buckets.get(i) == bucket;
548         }
549         return bucket;
550 
551     }
552 }