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.helper;
29  
30  import java.util.Collection;
31  import java.util.HashMap;
32  import java.util.Map;
33  
34  import org.sat4j.core.Vec;
35  import org.sat4j.core.VecInt;
36  import org.sat4j.specs.ContradictionException;
37  import org.sat4j.specs.ISolver;
38  import org.sat4j.specs.IVec;
39  import org.sat4j.specs.IVecInt;
40  import org.sat4j.specs.TimeoutException;
41  
42  /**
43   * Helper class intended to make life easier to people to feed a sat solver
44   * programmatically.
45   * 
46   * @author daniel
47   * 
48   * @param <T>
49   *            The class of the objects to map into boolean variables.
50   */
51  public class MappingHelper<T> {
52  
53  	/**
54  	 * 
55  	 */
56  	private static final long serialVersionUID = 1L;
57  
58  	private final Map<T, Integer> mapToDimacs = new HashMap<T, Integer>();
59  	private final IVec<T> mapToDomain;
60  	final ISolver solver;
61  
62  	public MappingHelper(ISolver solver) {
63  		this.solver = solver;
64  		mapToDomain = new Vec<T>();
65  		mapToDomain.push(null);
66  	}
67  
68  	int getIntValue(T thing) {
69  		Integer intValue = mapToDimacs.get(thing);
70  		if (intValue == null) {
71  			intValue = mapToDomain.size();
72  			mapToDomain.push(thing);
73  			mapToDimacs.put(thing, intValue);
74  		}
75  		return intValue;
76  	}
77  
78  	public IVec<T> getSolution() {
79  		int[] model = solver.model();
80  		IVec<T> toInstall = new Vec<T>();
81  		for (int i : model) {
82  			if (i > 0) {
83  				toInstall.push(mapToDomain.get(i));
84  			}
85  		}
86  		return toInstall;
87  	}
88  
89  	public boolean getBooleanValueFor(T t) {
90  		return solver.model(getIntValue(t));
91  	}
92  
93  	public boolean hasASolution() throws TimeoutException {
94  		return solver.isSatisfiable();
95  	}
96  
97  	/**
98  	 * Easy way to feed the solver with implications.
99  	 * 
100 	 * @param x
101 	 *            a thing.
102 	 * @param y
103 	 *            a thing implied by x.
104 	 * @throws ContradictionException
105 	 */
106 	public void addImplies(T x, T y) throws ContradictionException {
107 		IVecInt clause = new VecInt();
108 		clause.push(-getIntValue(x));
109 		clause.push(getIntValue(y));
110 		solver.addClause(clause);
111 	}
112 
113 	/**
114 	 * Easy way to feed the solver with implications.
115 	 * 
116 	 * @param x
117 	 *            an array of things such that x[i] -> y for all i.
118 	 * @param y
119 	 *            a thing implied by all the x[i].
120 	 * @throws ContradictionException
121 	 */
122 	public void addImplies(T[] x, T y) throws ContradictionException {
123 		IVecInt clause = new VecInt();
124 		for (T t : x) {
125 			clause.push(-getIntValue(t));
126 			clause.push(getIntValue(y));
127 			solver.addClause(clause);
128 			clause.clear();
129 		}
130 	}
131 
132 	/**
133 	 * Easy way to feed the solver with implications.
134 	 * 
135 	 * @param x
136 	 *            a collection of things such that x[i] -> y for all i.
137 	 * @param y
138 	 *            a thing implied by all the x[i].
139 	 * @throws ContradictionException
140 	 */
141 	public void addImplies(Collection<T> x, T y) throws ContradictionException {
142 		IVecInt clause = new VecInt();
143 		for (T t : x) {
144 			clause.push(-getIntValue(t));
145 			clause.push(getIntValue(y));
146 			solver.addClause(clause);
147 			clause.clear();
148 		}
149 	}
150 
151 	/**
152 	 * Easy way to feed the solver with implications.
153 	 * 
154 	 * @param x
155 	 *            a thing such that x -> y[i] for all i
156 	 * @param y
157 	 *            an array of things implied by x.
158 	 * @throws ContradictionException
159 	 *             if a trivial inconsistency is detected.
160 	 */
161 	public void addImplies(T x, T[] y) throws ContradictionException {
162 		IVecInt clause = new VecInt();
163 		for (T t : y) {
164 			clause.push(-getIntValue(x));
165 			clause.push(getIntValue(t));
166 			solver.addClause(clause);
167 			clause.clear();
168 		}
169 	}
170 
171 	/**
172 	 * Easy way to feed the solver with implications.
173 	 * 
174 	 * @param x
175 	 *            a thing such that x -> y[i] for all i
176 	 * @param y
177 	 *            a collection of things implied by x.
178 	 * @throws ContradictionException
179 	 *             if a trivial inconsistency is detected.
180 	 */
181 	public void addImplies(T x, Collection<T> y) throws ContradictionException {
182 		IVecInt clause = new VecInt();
183 		for (T t : y) {
184 			clause.push(-getIntValue(x));
185 			clause.push(getIntValue(t));
186 			solver.addClause(clause);
187 			clause.clear();
188 		}
189 	}
190 
191 	/**
192 	 * Easy way to feed the solver with a clause.
193 	 * 
194 	 * @param x
195 	 *            a thing such that x -> y[1] ... y[n]
196 	 * @param y
197 	 *            an array of things whose disjunction is implied by x.
198 	 * @throws ContradictionException
199 	 *             if a trivial inconsistency is detected.
200 	 */
201 	public void addImplication(T x, T[] y) throws ContradictionException {
202 		IVecInt clause = new VecInt();
203 		clause.push(-getIntValue(x));
204 		for (T t : y) {
205 			clause.push(getIntValue(t));
206 		}
207 		solver.addClause(clause);
208 	}
209 
210 	/**
211 	 * Easy way to feed the solver with implications.
212 	 * 
213 	 * @param x
214 	 *            a thing such that x -> y[1] ... y[n]
215 	 * @param y
216 	 *            a collection of things whose disjunction is implied by x.
217 	 * @throws ContradictionException
218 	 *             if a trivial inconsistency is detected.
219 	 */
220 	public void addImplication(T x, Collection<T> y)
221 			throws ContradictionException {
222 		IVecInt clause = new VecInt();
223 		clause.push(-getIntValue(x));
224 		for (T t : y) {
225 			clause.push(getIntValue(t));
226 		}
227 		solver.addClause(clause);
228 	}
229 
230 	/**
231 	 * Easy way to enter in the solver that at least degree x[i] must be
232 	 * satisfied.
233 	 * 
234 	 * @param x
235 	 *            an array of things.
236 	 * @param degree
237 	 *            the minimal number of elements in x that must be satisfied.
238 	 * @throws ContradictionException
239 	 *             if a trivial inconsistency is detected.
240 	 */
241 	public void addAtLeast(T[] x, int degree) throws ContradictionException {
242 		IVecInt literals = new VecInt(x.length);
243 		for (T t : x) {
244 			literals.push(getIntValue(t));
245 		}
246 		solver.addAtLeast(literals, degree);
247 	}
248 
249 	/**
250 	 * Easy way to enter in the solver that at least degree x[i] must be
251 	 * satisfied.
252 	 * 
253 	 * @param x
254 	 *            an array of things.
255 	 * @param degree
256 	 *            the minimal number of elements in x that must be satisfied.
257 	 * @throws ContradictionException
258 	 *             if a trivial inconsistency is detected.
259 	 */
260 	public void addAtLeast(Collection<T> x, int degree)
261 			throws ContradictionException {
262 		IVecInt literals = new VecInt(x.size());
263 		for (T t : x) {
264 			literals.push(getIntValue(t));
265 		}
266 		solver.addAtLeast(literals, degree);
267 	}
268 
269 	/**
270 	 * Easy way to enter in the solver that at most degree x[i] must be
271 	 * satisfied.
272 	 * 
273 	 * @param x
274 	 *            an array of things.
275 	 * @param degree
276 	 *            the maximal number of elements in x that must be satisfied.
277 	 * @throws ContradictionException
278 	 *             if a trivial inconsistency is detected.
279 	 */
280 	public void addAtMost(T[] x, int degree) throws ContradictionException {
281 		IVecInt literals = new VecInt(x.length);
282 		for (T t : x) {
283 			literals.push(getIntValue(t));
284 		}
285 		solver.addAtMost(literals, degree);
286 	}
287 
288 	/**
289 	 * Easy way to enter in the solver that at most degree x[i] must be
290 	 * satisfied.
291 	 * 
292 	 * @param x
293 	 *            an array of things.
294 	 * @param degree
295 	 *            the maximal number of elements in x that must be satisfied.
296 	 * @throws ContradictionException
297 	 *             if a trivial inconsistency is detected.
298 	 */
299 	public void addAtMost(Collection<T> x, int degree)
300 			throws ContradictionException {
301 		IVecInt literals = new VecInt(x.size());
302 		for (T t : x) {
303 			literals.push(getIntValue(t));
304 		}
305 		solver.addAtMost(literals, degree);
306 	}
307 
308 	public void addExactlyOneOf(T... ts) throws ContradictionException {
309 		IVecInt literals = new VecInt(ts.length);
310 		for (T t : ts) {
311 			literals.push(getIntValue(t));
312 		}
313 		solver.addAtMost(literals, 1);
314 		solver.addClause(literals);
315 	}
316 	
317 	/**
318 	 * Add a constraint x -> (y <-> z).
319 	 * 
320 	 * @param x
321 	 * @param y
322 	 * @param z
323 	 * @throws ContradictionException 
324 	 */
325 	public void addImpliesEquivalence(T x, T y, T z) throws ContradictionException {
326 		IVecInt literals = new VecInt();
327 		literals.push(-getIntValue(x)).push(-getIntValue(y)).push(getIntValue(z));		
328 		solver.addClause(literals);
329 		literals.clear();
330 		literals.push(-getIntValue(x)).push(-getIntValue(z)).push(getIntValue(y));		
331 		solver.addClause(literals);
332 	}
333 
334 	/**
335 	 * Easy way to mean that a set of things are incompatible, i.e. they cannot
336 	 * altogether be satisfied.
337 	 * 
338 	 */
339 	public void addConflict(Collection<T> things) throws ContradictionException {
340 		IVecInt literals = new VecInt(things.size());
341 		for (T t : things) {
342 			literals.push(-getIntValue(t));
343 		}
344 		solver.addClause(literals);
345 	}
346 
347 	/**
348 	 * Easy way to mean that a set of things are incompatible, i.e. they cannot
349 	 * altogether be satisfied.
350 	 * 
351 	 */
352 	public void addConflict(T... things) throws ContradictionException {
353 		IVecInt literals = new VecInt(things.length);
354 		for (T t : things) {
355 			literals.push(-getIntValue(t));
356 		}
357 		solver.addClause(literals);
358 	}
359 
360 	public void setTrue(T... things) throws ContradictionException {
361 		IVecInt clause = new VecInt();
362 		for (T thing : things) {
363 			clause.push(getIntValue(thing));
364 			solver.addClause(clause);
365 			clause.clear();
366 		}
367 	}
368 
369 	public void setFalse(T... things) throws ContradictionException {
370 		IVecInt clause = new VecInt();
371 		for (T thing : things) {
372 			clause.push(-getIntValue(thing));
373 			solver.addClause(clause);
374 			clause.clear();
375 		}
376 	}
377 }