View Javadoc

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