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  
20  package org.sat4j.pb.tools;
21  
22  import java.math.BigInteger;
23  import java.util.Collection;
24  import java.util.HashMap;
25  import java.util.Iterator;
26  import java.util.Map;
27  import java.util.Set;
28  import java.util.TreeSet;
29  
30  import org.sat4j.core.Vec;
31  import org.sat4j.core.VecInt;
32  import org.sat4j.pb.IPBSolver;
33  import org.sat4j.pb.ObjectiveFunction;
34  import org.sat4j.specs.ContradictionException;
35  import org.sat4j.specs.IConstr;
36  import org.sat4j.specs.IVec;
37  import org.sat4j.specs.IVecInt;
38  import org.sat4j.specs.TimeoutException;
39  import org.sat4j.tools.GateTranslator;
40  
41  /**
42   * Helper class intended to make life easier to people to feed a sat solver
43   * programmatically.
44   * 
45   * @author daniel
46   * 
47   * @param <T>
48   *            The class of the objects to map into boolean variables.
49   * @param <C>
50   *            The class of the object to map to each constraint.
51   */
52  public class DependencyHelper<T, C> {
53  
54  	public final INegator NO_NEGATION = new INegator() {
55  
56  		public boolean isNegated(Object thing) {
57  			return false;
58  		}
59  
60  		public Object unNegate(Object thing) {
61  			return thing;
62  		}
63  	};
64  
65  	public static final INegator BASIC_NEGATION = new INegator() {
66  
67  		public boolean isNegated(Object thing) {
68  			return (thing instanceof Negation);
69  		}
70  
71  		public Object unNegate(Object thing) {
72  			return ((Negation) thing).getThing();
73  		}
74  	};
75  
76  	private static final class Negation {
77  		private final Object thing;
78  
79  		Negation(Object thing) {
80  			this.thing = thing;
81  		}
82  
83  		Object getThing() {
84  			return thing;
85  		}
86  	}
87  
88  	/**
89  	 * 
90  	 */
91  	private static final long serialVersionUID = 1L;
92  
93  	private final Map<T, Integer> mapToDimacs = new HashMap<T, Integer>();
94  	private final Map<Integer, T> mapToDomain = new HashMap<Integer, T>();
95  	final Map<IConstr, C> descs = new HashMap<IConstr, C>();
96  
97  	private final XplainPB xplain;
98  	private final GateTranslator gator;
99  	final IPBSolver solver;
100 	private INegator negator = BASIC_NEGATION;
101 
102 	private ObjectiveFunction objFunction;
103 	private IVecInt objLiterals;
104 	private IVec<BigInteger> objCoefs;
105 
106 	public boolean explanationEnabled = true;
107 	public boolean canonicalOptFunction = true;
108 
109 	/**
110 	 * 
111 	 * @param solver
112 	 *            the solver to be used to solve the problem.
113 	 */
114 	public DependencyHelper(IPBSolver solver) {
115 		this(solver, true);
116 	}
117 
118 	/**
119 	 * 
120 	 * @param solver
121 	 *            the solver to be used to solve the problem.
122 	 * @param explanationEnabled
123 	 *            if true, will add one new variable per constraint to allow the
124 	 *            solver to compute an explanation in case of failure. Default
125 	 *            is true. Usually, this is set to false when one wants to check
126 	 *            the encoding produced by the helper.
127 	 */
128 	public DependencyHelper(IPBSolver solver, boolean explanationEnabled) {
129 		this(solver, explanationEnabled, true);
130 	}
131 
132 	/**
133 	 * 
134 	 * @param solver
135 	 *            the solver to be used to solve the problem.
136 	 * @param explanationEnabled
137 	 *            if true, will add one new variable per constraint to allow the
138 	 *            solver to compute an explanation in case of failure. Default
139 	 *            is true. Usually, this is set to false when one wants to check
140 	 *            the encoding produced by the helper.
141 	 * @param canonicalOptFunctionEnabled
142 	 *            when set to true, the objective function sum up all the
143 	 *            coefficients for a given literal. The default is true. It is
144 	 *            useful to set it to false when checking the encoding produced
145 	 *            by the helper.
146 	 * @since 2.2
147 	 */
148 	public DependencyHelper(IPBSolver solver, boolean explanationEnabled,
149 			boolean canonicalOptFunctionEnabled) {
150 		if (explanationEnabled) {
151 			this.xplain = new XplainPB(solver);
152 			this.solver = this.xplain;
153 		} else {
154 			this.xplain = null;
155 			this.solver = solver;
156 		}
157 		this.gator = new GateTranslator(this.solver);
158 		canonicalOptFunction = canonicalOptFunctionEnabled;
159 	}
160 
161 	public void setNegator(INegator negator) {
162 		this.negator = negator;
163 	}
164 
165 	/**
166 	 * Translate a domain object into a dimacs variable.
167 	 * 
168 	 * @param thing
169 	 *            a domain object
170 	 * @return the dimacs variable (an integer) representing that domain object.
171 	 */
172 	int getIntValue(T thing) {
173 		return getIntValue(thing, true);
174 	}
175 
176 	/**
177 	 * Translate a domain object into a dimacs variable.
178 	 * 
179 	 * @param thing
180 	 *            a domain object
181 	 * @param create
182 	 *            to allow or not the solver to create a new id if the object in
183 	 *            unknown. If set to false, the method will throw an
184 	 *            IllegalArgumentException if the object is unknown.
185 	 * @return the dimacs variable (an integer) representing that domain object.
186 	 */
187 	int getIntValue(T thing, boolean create) {
188 		T myThing;
189 		boolean negated = negator.isNegated(thing);
190 		if (negated) {
191 			myThing = (T) negator.unNegate(thing);
192 		} else {
193 			myThing = thing;
194 		}
195 		Integer intValue = mapToDimacs.get(myThing);
196 		if (intValue == null) {
197 			if (create) {
198 				intValue = solver.nextFreeVarId(true);
199 				mapToDomain.put(intValue, myThing);
200 				mapToDimacs.put(myThing, intValue);
201 			} else {
202 				throw new IllegalArgumentException("" + myThing
203 						+ " is unknown in the solver!");
204 			}
205 		}
206 		if (negated) {
207 			return -intValue;
208 		}
209 		return intValue;
210 	}
211 
212 	/**
213 	 * Retrieve the solution found.
214 	 * 
215 	 * THAT METHOD IS EXPECTED TO BE CALLED IF hasASolution() RETURNS TRUE.
216 	 * 
217 	 * @return the domain object that must be satisfied to satisfy the
218 	 *         constraints entered in the solver.
219 	 * @see {@link #hasASolution()}
220 	 */
221 	public IVec<T> getSolution() {
222 		int[] model = solver.model();
223 		IVec<T> toInstall = new Vec<T>();
224 		if (model != null) {
225 			for (int i : model) {
226 				if (i > 0) {
227 					toInstall.push(mapToDomain.get(i));
228 				}
229 			}
230 		}
231 		return toInstall;
232 	}
233 
234 	public BigInteger getSolutionCost() {
235 		return objFunction.calculateDegree(solver.model());
236 	}
237 
238 	/**
239 	 * Retrieve the boolean value associated with a domain object in the
240 	 * solution found by the solver. THAT METHOD IS EXPECTED TO BE CALLED IF
241 	 * hasASolution() RETURNS TRUE.
242 	 * 
243 	 * @param t
244 	 *            a domain object
245 	 * @return true iff the domain object has been set to true in the current
246 	 *         solution.
247 	 * @throws IllegalArgumentException
248 	 *             If the argument of the method is unknown to the solver.
249 	 */
250 	public boolean getBooleanValueFor(T t) {
251 		return solver.model(getIntValue(t, false));
252 	}
253 
254 	/**
255 	 * 
256 	 * @return true if the set of constraints entered inside the solver can be
257 	 *         satisfied.
258 	 * @throws TimeoutException
259 	 */
260 	public boolean hasASolution() throws TimeoutException {
261 		return solver.isSatisfiable();
262 	}
263 
264 	/**
265 	 * 
266 	 * @return true if the set of constraints entered inside the solver can be
267 	 *         satisfied.
268 	 * @throws TimeoutException
269 	 */
270 	public boolean hasASolution(IVec<T> assumps) throws TimeoutException {
271 		IVecInt assumptions = new VecInt();
272 		for (Iterator<T> it = assumps.iterator(); it.hasNext();) {
273 			assumptions.push(getIntValue(it.next()));
274 		}
275 		return solver.isSatisfiable(assumptions);
276 	}
277 
278 	/**
279 	 * 
280 	 * @return true if the set of constraints entered inside the solver can be
281 	 *         satisfied.
282 	 * @throws TimeoutException
283 	 */
284 	public boolean hasASolution(Collection<T> assumps) throws TimeoutException {
285 		IVecInt assumptions = new VecInt();
286 		for (T t : assumps) {
287 			assumptions.push(getIntValue(t));
288 		}
289 		return solver.isSatisfiable(assumptions);
290 	}
291 
292 	/**
293 	 * Explain the reason of the inconsistency of the set of constraints.
294 	 * 
295 	 * THAT METHOD IS EXPECTED TO BE CALLED IF hasASolution() RETURNS FALSE.
296 	 * 
297 	 * @return a set of objects used to "name" each constraint entered in the
298 	 *         solver.
299 	 * @throws TimeoutException
300 	 * @see {@link #hasASolution()}
301 	 */
302 	public Set<C> why() throws TimeoutException {
303 		if (!explanationEnabled) {
304 			throw new UnsupportedOperationException("Explanation not enabled!");
305 		}
306 		Collection<IConstr> explanation = xplain.explain();
307 		Set<C> ezexplain = new TreeSet<C>();
308 		for (IConstr constr : explanation) {
309 			C desc = descs.get(constr);
310 			if (desc != null) {
311 				ezexplain.add(desc);
312 			}
313 		}
314 		return ezexplain;
315 	}
316 
317 	/**
318 	 * Explain a domain object has been set to true in a solution.
319 	 * 
320 	 * @return a set of objects used to "name" each constraint entered in the
321 	 *         solver.
322 	 * @throws TimeoutException
323 	 * @see {@link #hasASolution()}
324 	 */
325 	public Set<C> why(T thing) throws TimeoutException {
326 		IVecInt assumps = new VecInt();
327 		assumps.push(-getIntValue(thing));
328 		return why(assumps);
329 	}
330 
331 	/**
332 	 * Explain a domain object has been set to false in a solution.
333 	 * 
334 	 * @return a set of objects used to "name" each constraint entered in the
335 	 *         solver.
336 	 * @throws TimeoutException
337 	 * @see {@link #hasASolution()}
338 	 */
339 	public Set<C> whyNot(T thing) throws TimeoutException {
340 		IVecInt assumps = new VecInt();
341 		assumps.push(getIntValue(thing));
342 		return why(assumps);
343 	}
344 
345 	private Set<C> why(IVecInt assumps) throws TimeoutException {
346 		if (xplain.isSatisfiable(assumps)) {
347 			return new TreeSet<C>();
348 		}
349 		return why();
350 	}
351 
352 	/**
353 	 * Add a constraint to set the value of a domain object to true.
354 	 * 
355 	 * @param thing
356 	 *            the domain object
357 	 * @param name
358 	 *            the name of the constraint, to be used in an explanation if
359 	 *            needed.
360 	 * @throws ContradictionException
361 	 *             if the set of constraints appears to be trivially
362 	 *             inconsistent.
363 	 */
364 	public void setTrue(T thing, C name) throws ContradictionException {
365 		IConstr constr = gator.gateTrue(getIntValue(thing));
366 		if (constr != null) {
367 			descs.put(constr, name);
368 		}
369 	}
370 
371 	/**
372 	 * Add a constraint to set the value of a domain object to false.
373 	 * 
374 	 * @param thing
375 	 *            the domain object
376 	 * @param name
377 	 *            the name of the constraint, to be used in an explanation if
378 	 *            needed.
379 	 * @throws ContradictionException
380 	 *             if the set of constraints appears to be trivially
381 	 *             inconsistent.
382 	 */
383 	public void setFalse(T thing, C name) throws ContradictionException {
384 		IConstr constr = gator.gateFalse(getIntValue(thing));
385 		// constraints duplication detection may end up with null constraint
386 		if (constr != null) {
387 			descs.put(constr, name);
388 		}
389 
390 	}
391 
392 	/**
393 	 * Create a logical implication of the form lhs -> rhs
394 	 * 
395 	 * @param lhs
396 	 *            some domain objects. They form a conjunction in the left hand
397 	 *            side of the implication.
398 	 * @return the right hand side of the implication.
399 	 */
400 	public ImplicationRHS<T, C> implication(T... lhs) {
401 		IVecInt clause = new VecInt();
402 		for (T t : lhs) {
403 			clause.push(-getIntValue(t));
404 		}
405 		return new ImplicationRHS<T, C>(this, clause);
406 	}
407 
408 	public DisjunctionRHS<T, C> disjunction(T... lhs) {
409 		IVecInt literals = new VecInt();
410 		for (T t : lhs) {
411 			literals.push(-getIntValue(t));
412 		}
413 		return new DisjunctionRHS<T, C>(this, literals);
414 	}
415 
416 	/**
417 	 * Create a constraint stating that at most i domain object should be set to
418 	 * true.
419 	 * 
420 	 * @param i
421 	 *            the maximum number of domain object to set to true.
422 	 * @param things
423 	 *            the domain objects.
424 	 * @return an object used to name the constraint. The constraint MUST BE
425 	 *         NAMED.
426 	 * @throws ContradictionException
427 	 */
428 	public void atLeast(C name, int i, T... things)
429 			throws ContradictionException {
430 		IVecInt literals = new VecInt();
431 		for (T t : things) {
432 			literals.push(getIntValue(t));
433 		}
434 		descs.put(solver.addAtLeast(literals, i), name);
435 	}
436 
437 	/**
438 	 * Create a constraint stating that at most i domain object should be set to
439 	 * true.
440 	 * 
441 	 * @param i
442 	 *            the maximum number of domain object to set to true.
443 	 * @param things
444 	 *            the domain objects.
445 	 * @return an object used to name the constraint. The constraint MUST BE
446 	 *         NAMED.
447 	 * @throws ContradictionException
448 	 */
449 	public ImplicationNamer<T, C> atMost(int i, T... things)
450 			throws ContradictionException {
451 		IVec<IConstr> toName = new Vec<IConstr>();
452 		IVecInt literals = new VecInt();
453 		for (T t : things) {
454 			literals.push(getIntValue(t));
455 		}
456 		toName.push(solver.addAtMost(literals, i));
457 		return new ImplicationNamer<T, C>(this, toName);
458 	}
459 
460 	/**
461 	 * Create a constraint stating that at most i domain object should be set to
462 	 * true.
463 	 * 
464 	 * @param i
465 	 *            the maximum number of domain object to set to true.
466 	 * @param things
467 	 *            the domain objects.
468 	 * @return an object used to name the constraint. The constraint MUST BE
469 	 *         NAMED.
470 	 * @throws ContradictionException
471 	 */
472 	public void atMost(C name, int i, T... things)
473 			throws ContradictionException {
474 		IVecInt literals = new VecInt();
475 		for (T t : things) {
476 			literals.push(getIntValue(t));
477 		}
478 		descs.put(solver.addAtMost(literals, i), name);
479 	}
480 
481 	/**
482 	 * Create a clause (thing1 or thing 2 ... or thingn)
483 	 * 
484 	 * @param name
485 	 * @param things
486 	 * 
487 	 * @throws ContradictionException
488 	 */
489 	public void clause(C name, T... things) throws ContradictionException {
490 		IVecInt literals = new VecInt(things.length);
491 		for (T t : things) {
492 			literals.push(getIntValue(t));
493 		}
494 		IConstr constr = gator.addClause(literals);
495 		// constr can be null if duplicated clauses are detected.
496 		if (constr != null) {
497 			descs.put(constr, name);
498 		}
499 
500 	}
501 
502 	/**
503 	 * Create a constraint using equivalency chains thing <=> (thing1 <=> thing2
504 	 * <=> ... <=> thingn)
505 	 * 
506 	 * @param thing
507 	 *            a domain object
508 	 * @param things
509 	 *            other domain objects.
510 	 * @throws ContradictionException
511 	 */
512 	public void iff(C name, T thing, T... otherThings)
513 			throws ContradictionException {
514 		IVecInt literals = new VecInt(otherThings.length);
515 		for (T t : otherThings) {
516 			literals.push(getIntValue(t));
517 		}
518 		IConstr[] constrs = gator.iff(getIntValue(thing), literals);
519 		for (IConstr constr : constrs) {
520 			if (constr == null) {
521 				throw new IllegalStateException(
522 						"Constraints are not supposed to be null when using the helper");
523 			}
524 			descs.put(constr, name);
525 		}
526 	}
527 
528 	/**
529 	 * Create a constraint of the form thing <=> (thing1 and thing 2 ... and
530 	 * thingn)
531 	 * 
532 	 * @param name
533 	 * @param thing
534 	 * @param otherThings
535 	 * @throws ContradictionException
536 	 */
537 	public void and(C name, T thing, T... otherThings)
538 			throws ContradictionException {
539 		IVecInt literals = new VecInt(otherThings.length);
540 		for (T t : otherThings) {
541 			literals.push(getIntValue(t));
542 		}
543 		IConstr[] constrs = gator.and(getIntValue(thing), literals);
544 		for (IConstr constr : constrs) {
545 			if (constr == null) {
546 				throw new IllegalStateException(
547 						"Constraints are not supposed to be null when using the helper");
548 			}
549 			descs.put(constr, name);
550 		}
551 	}
552 
553 	/**
554 	 * Create a constraint of the form thing <=> (thing1 or thing 2 ... or
555 	 * thingn)
556 	 * 
557 	 * @param name
558 	 * @param thing
559 	 * @param otherThings
560 	 * @throws ContradictionException
561 	 */
562 	public void or(C name, T thing, T... otherThings)
563 			throws ContradictionException {
564 		IVecInt literals = new VecInt(otherThings.length);
565 		for (T t : otherThings) {
566 			literals.push(getIntValue(t));
567 		}
568 		IConstr[] constrs = gator.or(getIntValue(thing), literals);
569 		for (IConstr constr : constrs) {
570 			if (constr == null) {
571 				throw new IllegalStateException(
572 						"Constraints are not supposed to be null when using the helper");
573 			}
574 			descs.put(constr, name);
575 		}
576 	}
577 
578 	/**
579 	 * Create a constraint of the form thing <=> (if conditionThing then
580 	 * thenThing else elseThing)
581 	 * 
582 	 * @param name
583 	 * @param thing
584 	 * @param otherThings
585 	 * @throws ContradictionException
586 	 */
587 	public void ifThenElse(C name, T thing, T conditionThing, T thenThing,
588 			T elseThing) throws ContradictionException {
589 		IConstr[] constrs = gator.ite(getIntValue(thing),
590 				getIntValue(conditionThing), getIntValue(thenThing),
591 				getIntValue(elseThing));
592 		for (IConstr constr : constrs) {
593 			if (constr == null) {
594 				throw new IllegalStateException(
595 						"Constraints are not supposed to be null when using the helper");
596 			}
597 			descs.put(constr, name);
598 		}
599 	}
600 
601 	/**
602 	 * Add an objective function to ask for a solution that minimize the
603 	 * objective function.
604 	 * 
605 	 * @param wobj
606 	 *            a set of weighted objects (pairs of domain object and
607 	 *            BigInteger).
608 	 */
609 	public void setObjectiveFunction(WeightedObject<T>... wobj) {
610 		createObjectivetiveFunctionIfNeeded(wobj.length);
611 		for (WeightedObject<T> wo : wobj) {
612 			addProperly(wo.thing, wo.getWeight());
613 		}
614 
615 	}
616 
617 	private void addProperly(T thing, BigInteger weight) {
618 		int lit = getIntValue(thing);
619 		int index;
620 		if (canonicalOptFunction && (index = objLiterals.indexOf(lit)) != -1) {
621 			objCoefs.set(index, objCoefs.get(index).add(weight));
622 		} else {
623 			objLiterals.push(lit);
624 			objCoefs.push(weight);
625 		}
626 	}
627 
628 	private void createObjectivetiveFunctionIfNeeded(int n) {
629 		if (objFunction == null) {
630 			objLiterals = new VecInt(n);
631 			objCoefs = new Vec<BigInteger>(n);
632 			objFunction = new ObjectiveFunction(objLiterals, objCoefs);
633 			solver.setObjectiveFunction(objFunction);
634 		}
635 	}
636 
637 	/**
638 	 * Add a weighted literal to the objective function.
639 	 * 
640 	 * @param thing
641 	 * @param weight
642 	 */
643 	public void addToObjectiveFunction(T thing, int weight) {
644 		addToObjectiveFunction(thing, BigInteger.valueOf(weight));
645 	}
646 
647 	/**
648 	 * Add a weighted literal to the objective function.
649 	 * 
650 	 * @param thing
651 	 * @param weight
652 	 */
653 	public void addToObjectiveFunction(T thing, BigInteger weight) {
654 		createObjectivetiveFunctionIfNeeded(20);
655 		addProperly(thing, weight);
656 	}
657 
658 	/**
659 	 * Create a PB constraint of the form <code>
660 	 * w1.l1 + w2.l2 + ... wn.ln >= degree
661 	 * </code> where wi are position integers and li are domain objects.
662 	 * 
663 	 * @param degree
664 	 * @param wobj
665 	 * @throws ContradictionException
666 	 */
667 	public void atLeast(C name, BigInteger degree, WeightedObject<T>... wobj)
668 			throws ContradictionException {
669 		IVecInt literals = new VecInt(wobj.length);
670 		IVec<BigInteger> coeffs = new Vec<BigInteger>(wobj.length);
671 		for (WeightedObject<T> wo : wobj) {
672 			literals.push(getIntValue(wo.thing));
673 			coeffs.push(wo.getWeight());
674 		}
675 		descs.put(solver.addPseudoBoolean(literals, coeffs, true, degree), name);
676 	}
677 
678 	/**
679 	 * Create a PB constraint of the form <code>
680 	 * w1.l1 + w2.l2 + ... wn.ln <= degree
681 	 * </code> where wi are position integers and li are domain objects.
682 	 * 
683 	 * @param degree
684 	 * @param wobj
685 	 * @throws ContradictionException
686 	 */
687 	public void atMost(C name, BigInteger degree, WeightedObject<T>... wobj)
688 			throws ContradictionException {
689 		IVecInt literals = new VecInt(wobj.length);
690 		IVec<BigInteger> coeffs = new Vec<BigInteger>(wobj.length);
691 		for (WeightedObject<T> wo : wobj) {
692 			literals.push(getIntValue(wo.thing));
693 			coeffs.push(wo.getWeight());
694 		}
695 		descs.put(solver.addPseudoBoolean(literals, coeffs, false, degree),
696 				name);
697 	}
698 
699 	public void atMost(C name, int degree, WeightedObject<T>... wobj)
700 			throws ContradictionException {
701 		atMost(name, BigInteger.valueOf(degree), wobj);
702 	}
703 
704 	/**
705 	 * Stop the SAT solver that is looking for a solution. The solver will throw
706 	 * a TimeoutException.
707 	 */
708 	public void stopSolver() {
709 		solver.expireTimeout();
710 	}
711 
712 	/**
713 	 * Stop the explanation computation. A TimeoutException will be thrown by
714 	 * the explanation algorithm.
715 	 */
716 	public void stopExplanation() {
717 		if (!explanationEnabled) {
718 			throw new UnsupportedOperationException("Explanation not enabled!");
719 		}
720 		xplain.cancelExplanation();
721 	}
722 
723 	public void discard(IVec<T> things) throws ContradictionException {
724 		IVecInt literals = new VecInt(things.size());
725 		for (Iterator<T> it = things.iterator(); it.hasNext();) {
726 			literals.push(-getIntValue(it.next()));
727 		}
728 		solver.addBlockingClause(literals);
729 	}
730 
731 	public void discardSolutionsWithObjectiveValueGreaterThan(long value)
732 			throws ContradictionException {
733 		ObjectiveFunction obj = solver.getObjectiveFunction();
734 		IVecInt literals = new VecInt(obj.getVars().size());
735 		obj.getVars().copyTo(literals);
736 		IVec<BigInteger> coeffs = new Vec<BigInteger>(obj.getCoeffs().size());
737 		obj.getCoeffs().copyTo(coeffs);
738 		solver.addPseudoBoolean(literals, coeffs, false, BigInteger
739 				.valueOf(value));
740 	}
741 
742 	public String getObjectiveFunction() {
743 		ObjectiveFunction obj = solver.getObjectiveFunction();
744 		StringBuffer stb = new StringBuffer();
745 		for (int i = 0; i < obj.getVars().size(); i++) {
746 			stb.append(obj.getCoeffs().get(i)
747 					+ (obj.getVars().get(i) > 0 ? " " : "~")
748 					+ mapToDomain.get(Math.abs(obj.getVars().get(i))) + " ");
749 		}
750 		return stb.toString();
751 	}
752 
753 	public int getNumberOfVariables() {
754 		return mapToDimacs.size();
755 	}
756 
757 	public int getNumberOfConstraints() {
758 		return descs.size();
759 	}
760 
761 	public Map<Integer, T> getMappingToDomain() {
762 		return mapToDomain;
763 	}
764 
765 	public Object not(T thing) {
766 		return new Negation(thing);
767 	}
768 
769 	/**
770 	 * @since 2.2
771 	 * @return the IPBSolver enclosed in the helper.
772 	 */
773 	public IPBSolver getSolver() {
774 		return solver;
775 	}
776 }