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