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 org.sat4j.core.Vec;
31  import org.sat4j.core.VecInt;
32  import org.sat4j.specs.ContradictionException;
33  import org.sat4j.specs.IConstr;
34  import org.sat4j.specs.ISolver;
35  import org.sat4j.specs.IVec;
36  import org.sat4j.specs.IVecInt;
37  
38  /**
39   * Utility class to easily feed a SAT solver using logical gates.
40   * 
41   * @author leberre
42   * 
43   */
44  public class GateTranslator extends SolverDecorator<ISolver> {
45  
46  	/**
47       * 
48       */
49  	private static final long serialVersionUID = 1L;
50  
51  	public GateTranslator(ISolver solver) {
52  		super(solver);
53  	}
54  
55  	/**
56  	 * translate y <=> FALSE into a clause.
57  	 * 
58  	 * @param y
59  	 *            a variable to falsify
60  	 * @throws ContradictionException
61  	 *             iff a trivial inconsistency is found.
62  	 * @since 2.1
63  	 */
64  	public IConstr gateFalse(int y) throws ContradictionException {
65  		IVecInt clause = new VecInt(2);
66  		clause.push(-y);
67  		return processClause(clause);
68  	}
69  
70  	/**
71  	 * translate y <=> TRUE into a clause.
72  	 * 
73  	 * @param y
74  	 *            a variable to verify
75  	 * @throws ContradictionException
76  	 * @since 2.1
77  	 */
78  	public IConstr gateTrue(int y) throws ContradictionException {
79  		IVecInt clause = new VecInt(2);
80  		clause.push(y);
81  		return processClause(clause);
82  	}
83  
84  	/**
85  	 * translate y <=> if x1 then x2 else x3 into clauses.
86  	 * 
87  	 * @param y
88  	 * @param x1
89  	 *            the selector variable
90  	 * @param x2
91  	 * @param x3
92  	 * @throws ContradictionException
93  	 * @since 2.1
94  	 */
95  	public IConstr[] ite(int y, int x1, int x2, int x3)
96  			throws ContradictionException {
97  		IConstr[] constrs = new IConstr[6];
98  		IVecInt clause = new VecInt(5);
99  		// y <=> (x1 -> x2) and (not x1 -> x3)
100 		// y -> (x1 -> x2) and (not x1 -> x3)
101 		clause.push(-y).push(-x1).push(x2);
102 		constrs[0] = processClause(clause);
103 		clause.clear();
104 		clause.push(-y).push(x1).push(x3);
105 		constrs[1] = processClause(clause);
106 		// y <- (x1 -> x2) and (not x1 -> x3)
107 		// not(x1 -> x2) or not(not x1 -> x3) or y
108 		// x1 and not x2 or not x1 and not x3 or y
109 		// (x1 and not x2) or ((not x1 or y) and (not x3 or y))
110 		// (x1 or not x1 or y) and (not x2 or not x1 or y) and (x1 or not x3 or
111 		// y) and (not x2 or not x3 or y)
112 		// not x1 or not x2 or y and x1 or not x3 or y and not x2 or not x3 or y
113 		clause.clear();
114 		clause.push(-x1).push(-x2).push(y);
115 		constrs[2] = processClause(clause);
116 		clause.clear();
117 		clause.push(x1).push(-x3).push(y);
118 		constrs[3] = processClause(clause);
119 		clause.clear();
120 		clause.push(-x2).push(-x3).push(y);
121 		constrs[4] = processClause(clause);
122 		// taken from Niklas Een et al SAT 2007 paper
123 		// Adding the following redundant clause will improve unit propagation
124 		// y -> x2 or x3
125 		clause.clear();
126 		clause.push(-y).push(x2).push(x3);
127 		constrs[5] = processClause(clause);
128 		return constrs;
129 	}
130 
131 	/**
132 	 * Translate y <=> x1 /\ x2 /\ ... /\ xn into clauses.
133 	 * 
134 	 * @param y
135 	 * @param literals
136 	 *            the x1 ... xn literals.
137 	 * @throws ContradictionException
138 	 * @since 2.1
139 	 */
140 	public IConstr[] and(int y, IVecInt literals) throws ContradictionException {
141 		// y <=> AND x1 ... xn
142 		IConstr[] constrs = new IConstr[literals.size() + 1];
143 		// y <= x1 .. xn
144 		IVecInt clause = new VecInt(literals.size() + 2);
145 		clause.push(y);
146 		for (int i = 0; i < literals.size(); i++) {
147 			clause.push(-literals.get(i));
148 		}
149 		constrs[0] = processClause(clause);
150 		clause.clear();
151 		for (int i = 0; i < literals.size(); i++) {
152 			// y => xi
153 			clause.clear();
154 			clause.push(-y);
155 			clause.push(literals.get(i));
156 			constrs[i + 1] = processClause(clause);
157 		}
158 		return constrs;
159 	}
160 
161 	/**
162 	 * Translate y <=> x1 /\ x2
163 	 * 
164 	 * @param y
165 	 * @param x1
166 	 * @param x2
167 	 * @throws ContradictionException
168 	 * @since 2.1
169 	 */
170 	public IConstr[] and(int y, int x1, int x2) throws ContradictionException {
171 		IVecInt clause = new VecInt(4);
172 		IConstr[] constrs = new IConstr[3];
173 		clause.push(-y);
174 		clause.push(x1);
175 		constrs[0] = addClause(clause);
176 		clause.clear();
177 		clause.push(-y);
178 		clause.push(x2);
179 		constrs[1] = addClause(clause);
180 		clause.clear();
181 		clause.push(y);
182 		clause.push(-x1);
183 		clause.push(-x2);
184 		constrs[2] = addClause(clause);
185 		return constrs;
186 	}
187 
188 	/**
189 	 * translate y <=> x1 \/ x2 \/ ... \/ xn into clauses.
190 	 * 
191 	 * @param y
192 	 * @param literals
193 	 * @throws ContradictionException
194 	 * @since 2.1
195 	 */
196 	public IConstr[] or(int y, IVecInt literals) throws ContradictionException {
197 		// y <=> OR x1 x2 ...xn
198 		// y => x1 x2 ... xn
199 		IConstr[] constrs = new IConstr[literals.size() + 1];
200 		IVecInt clause = new VecInt(literals.size() + 2);
201 		literals.copyTo(clause);
202 		clause.push(-y);
203 		constrs[0] = processClause(clause);
204 		clause.clear();
205 		for (int i = 0; i < literals.size(); i++) {
206 			// xi => y
207 			clause.clear();
208 			clause.push(y);
209 			clause.push(-literals.get(i));
210 			constrs[i + 1] = processClause(clause);
211 		}
212 		return constrs;
213 	}
214 
215 	private IConstr processClause(IVecInt clause) throws ContradictionException {
216 		return addClause(clause);
217 	}
218 
219 	/**
220 	 * Translate y <=> not x into clauses.
221 	 * 
222 	 * @param y
223 	 * @param x
224 	 * @throws ContradictionException
225 	 * @since 2.1
226 	 */
227 	public IConstr[] not(int y, int x) throws ContradictionException {
228 		IConstr[] constrs = new IConstr[2];
229 		IVecInt clause = new VecInt(3);
230 		// y <=> not x
231 		// y => not x = not y or not x
232 		clause.push(-y).push(-x);
233 		constrs[0] = processClause(clause);
234 		// y <= not x = y or x
235 		clause.clear();
236 		clause.push(y).push(x);
237 		constrs[1] = processClause(clause);
238 		return constrs;
239 	}
240 
241 	/**
242 	 * translate y <=> x1 xor x2 xor ... xor xn into clauses.
243 	 * 
244 	 * @param y
245 	 * @param literals
246 	 * @throws ContradictionException
247 	 * @since 2.1
248 	 */
249 	public IConstr[] xor(int y, IVecInt literals) throws ContradictionException {
250 		literals.push(-y);
251 		int[] f = new int[literals.size()];
252 		literals.copyTo(f);
253 		IVec<IConstr> vconstrs = new Vec<IConstr>();
254 		xor2Clause(f, 0, false, vconstrs);
255 		IConstr[] constrs = new IConstr[vconstrs.size()];
256 		vconstrs.copyTo(constrs);
257 		return constrs;
258 	}
259 
260 	/**
261 	 * translate y <=> (x1 <=> x2 <=> ... <=> xn) into clauses.
262 	 * 
263 	 * @param y
264 	 * @param literals
265 	 * @throws ContradictionException
266 	 * @since 2.1
267 	 */
268 	public IConstr[] iff(int y, IVecInt literals) throws ContradictionException {
269 		literals.push(y);
270 		int[] f = new int[literals.size()];
271 		literals.copyTo(f);
272 		IVec<IConstr> vconstrs = new Vec<IConstr>();
273 		iff2Clause(f, 0, false, vconstrs);
274 		IConstr[] constrs = new IConstr[vconstrs.size()];
275 		vconstrs.copyTo(constrs);
276 		return constrs;
277 	}
278 
279 	private void xor2Clause(int[] f, int prefix, boolean negation,
280 			IVec<IConstr> constrs) throws ContradictionException {
281 		if (prefix == f.length - 1) {
282 			IVecInt clause = new VecInt(f.length + 1);
283 			for (int i = 0; i < f.length - 1; ++i) {
284 				clause.push(f[i]);
285 			}
286 			clause.push(f[f.length - 1] * (negation ? -1 : 1));
287 			constrs.push(processClause(clause));
288 			return;
289 		}
290 
291 		if (negation) {
292 			f[prefix] = -f[prefix];
293 			xor2Clause(f, prefix + 1, false, constrs);
294 			f[prefix] = -f[prefix];
295 
296 			xor2Clause(f, prefix + 1, true, constrs);
297 		} else {
298 			xor2Clause(f, prefix + 1, false, constrs);
299 
300 			f[prefix] = -f[prefix];
301 			xor2Clause(f, prefix + 1, true, constrs);
302 			f[prefix] = -f[prefix];
303 		}
304 	}
305 
306 	private void iff2Clause(int[] f, int prefix, boolean negation,
307 			IVec<IConstr> constrs) throws ContradictionException {
308 		if (prefix == f.length - 1) {
309 			IVecInt clause = new VecInt(f.length + 1);
310 			for (int i = 0; i < f.length - 1; ++i) {
311 				clause.push(f[i]);
312 			}
313 			clause.push(f[f.length - 1] * (negation ? -1 : 1));
314 			processClause(clause);
315 			return;
316 		}
317 
318 		if (negation) {
319 			iff2Clause(f, prefix + 1, false, constrs);
320 			f[prefix] = -f[prefix];
321 			iff2Clause(f, prefix + 1, true, constrs);
322 			f[prefix] = -f[prefix];
323 		} else {
324 			f[prefix] = -f[prefix];
325 			iff2Clause(f, prefix + 1, false, constrs);
326 			f[prefix] = -f[prefix];
327 			iff2Clause(f, prefix + 1, true, constrs);
328 		}
329 	}
330 
331 }