1   
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
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.IteratorInt;
51  import org.sat4j.specs.TimeoutException;
52  import org.sat4j.tools.Backbone;
53  import org.sat4j.tools.GateTranslator;
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  public class DependencyHelper<T, C> {
67  
68  	public static final INegator NO_NEGATION = new INegator() {
69  
70  		public boolean isNegated(Object thing) {
71  			return false;
72  		}
73  
74  		public Object unNegate(Object thing) {
75  			return thing;
76  		}
77  	};
78  
79  	public static final INegator BASIC_NEGATION = new INegator() {
80  
81  		public boolean isNegated(Object thing) {
82  			return thing instanceof Negation;
83  		}
84  
85  		public Object unNegate(Object thing) {
86  			return ((Negation) thing).getThing();
87  		}
88  	};
89  
90  	private static final class Negation {
91  		private final Object thing;
92  
93  		Negation(Object thing) {
94  			this.thing = thing;
95  		}
96  
97  		Object getThing() {
98  			return this.thing;
99  		}
100 
101 		@Override
102 		public String toString() {
103 			return "-" + thing;
104 		}
105 	}
106 
107 	
108 
109 
110 	private static final long serialVersionUID = 1L;
111 
112 	private final Map<T, Integer> mapToDimacs = new HashMap<T, Integer>();
113 	private final Map<Integer, T> mapToDomain = new HashMap<Integer, T>();
114 	final Map<IConstr, C> descs = new HashMap<IConstr, C>();
115 
116 	private final XplainPB xplain;
117 	private final GateTranslator gator;
118 	final IPBSolver solver;
119 	private INegator negator = BASIC_NEGATION;
120 
121 	private ObjectiveFunction objFunction;
122 	private IVecInt objLiterals;
123 	private IVec<BigInteger> objCoefs;
124 
125 	private final boolean explanationEnabled;
126 	private final boolean canonicalOptFunction;
127 
128 	
129 
130 
131 
132 
133 	public DependencyHelper(IPBSolver solver) {
134 		this(solver, true);
135 	}
136 
137 	
138 
139 
140 
141 
142 
143 
144 
145 
146 
147 	public DependencyHelper(IPBSolver solver, boolean explanationEnabled) {
148 		this(solver, explanationEnabled, true);
149 	}
150 
151 	
152 
153 
154 
155 
156 
157 
158 
159 
160 
161 
162 
163 
164 
165 
166 
167 	public DependencyHelper(IPBSolver solver, boolean explanationEnabled,
168 			boolean canonicalOptFunctionEnabled) {
169 		if (explanationEnabled) {
170 			this.xplain = new XplainPB(solver);
171 			this.solver = this.xplain;
172 		} else {
173 			this.xplain = null;
174 			this.solver = solver;
175 		}
176 		this.gator = new GateTranslator(this.solver);
177 		this.explanationEnabled = explanationEnabled;
178 		this.canonicalOptFunction = canonicalOptFunctionEnabled;
179 	}
180 
181 	public void setNegator(INegator negator) {
182 		this.negator = negator;
183 	}
184 
185 	
186 
187 
188 
189 
190 
191 
192 	protected int getIntValue(T thing) {
193 		return getIntValue(thing, true);
194 	}
195 
196 	
197 
198 
199 
200 
201 
202 
203 
204 
205 
206 
207 	protected int getIntValue(T thing, boolean create) {
208 		T myThing;
209 		boolean negated = this.negator.isNegated(thing);
210 		if (negated) {
211 			myThing = (T) this.negator.unNegate(thing);
212 		} else {
213 			myThing = thing;
214 		}
215 		Integer intValue = this.mapToDimacs.get(myThing);
216 		if (intValue == null) {
217 			if (create) {
218 				intValue = this.solver.nextFreeVarId(true);
219 				this.mapToDomain.put(intValue, myThing);
220 				this.mapToDimacs.put(myThing, intValue);
221 			} else {
222 				throw new IllegalArgumentException("" + myThing
223 						+ " is unknown in the solver!");
224 			}
225 		}
226 		if (negated) {
227 			return -intValue;
228 		}
229 		return intValue;
230 	}
231 
232 	
233 
234 
235 
236 
237 
238 
239 
240 
241 
242 
243 
244 
245 
246 	public IVec<T> getSolution() {
247 		int[] model = this.solver.model();
248 		IVec<T> toInstall = new Vec<T>();
249 		if (model != null) {
250 			for (int i : model) {
251 				if (i > 0) {
252 					toInstall.push(this.mapToDomain.get(i));
253 				}
254 			}
255 		}
256 		return toInstall;
257 	}
258 
259 	
260 
261 
262 
263 
264 
265 
266 
267 
268 
269 
270 
271 
272 
273 	public Collection<T> getASolution() {
274 		int[] model = this.solver.model();
275 		Collection<T> toInstall = new ArrayList<T>();
276 		if (model != null) {
277 			for (int i : model) {
278 				if (i > 0) {
279 					toInstall.add(this.mapToDomain.get(i));
280 				}
281 			}
282 		}
283 		return toInstall;
284 	}
285 
286 	public BigInteger getSolutionCost() {
287 		return this.objFunction.calculateDegree(this.solver);
288 	}
289 
290 	
291 
292 
293 
294 
295 
296 
297 
298 
299 
300 
301 
302 	public boolean getBooleanValueFor(T t) {
303 		int dimacsValue = getIntValue(t, false);
304 		if (dimacsValue > 0) {
305 			return this.solver.model(dimacsValue);
306 		} else {
307 			return !this.solver.model(-dimacsValue);
308 		}
309 	}
310 
311 	
312 
313 
314 
315 
316 
317 	public boolean hasASolution() throws TimeoutException {
318 		return this.solver.isSatisfiable();
319 	}
320 
321 	
322 
323 
324 
325 
326 
327 	public boolean hasASolution(IVec<T> assumps) throws TimeoutException {
328 		IVecInt assumptions = new VecInt();
329 		for (Iterator<T> it = assumps.iterator(); it.hasNext();) {
330 			assumptions.push(getIntValue(it.next()));
331 		}
332 		return this.solver.isSatisfiable(assumptions);
333 	}
334 
335 	
336 
337 
338 
339 
340 
341 	public boolean hasASolution(Collection<T> assumps) throws TimeoutException {
342 		IVecInt assumptions = new VecInt();
343 		for (T t : assumps) {
344 			assumptions.push(getIntValue(t));
345 		}
346 		return this.solver.isSatisfiable(assumptions);
347 	}
348 
349 	
350 
351 
352 
353 
354 
355 
356 
357 
358 
359 	public Set<C> why() throws TimeoutException {
360 		if (!this.explanationEnabled) {
361 			throw new UnsupportedOperationException("Explanation not enabled!");
362 		}
363 		Collection<IConstr> explanation = this.xplain.explain();
364 		Set<C> ezexplain = new TreeSet<C>();
365 		for (IConstr constr : explanation) {
366 			C desc = this.descs.get(constr);
367 			if (desc != null) {
368 				ezexplain.add(desc);
369 			}
370 		}
371 		return ezexplain;
372 	}
373 
374 	
375 
376 
377 
378 
379 
380 
381 
382 	public Set<C> why(T thing) throws TimeoutException {
383 		IVecInt assumps = new VecInt();
384 		assumps.push(-getIntValue(thing));
385 		return why(assumps);
386 	}
387 
388 	
389 
390 
391 
392 
393 
394 
395 
396 	public Set<C> whyNot(T thing) throws TimeoutException {
397 		IVecInt assumps = new VecInt();
398 		assumps.push(getIntValue(thing));
399 		return why(assumps);
400 	}
401 
402 	private Set<C> why(IVecInt assumps) throws TimeoutException {
403 		if (this.xplain.isSatisfiable(assumps)) {
404 			return new TreeSet<C>();
405 		}
406 		return why();
407 	}
408 
409 	
410 
411 
412 
413 
414 
415 
416 
417 
418 
419 
420 
421 	public void setTrue(T thing, C name) throws ContradictionException {
422 		IConstr constr = this.gator.gateTrue(getIntValue(thing));
423 		if (constr != null) {
424 			this.descs.put(constr, name);
425 		}
426 	}
427 
428 	
429 
430 
431 
432 
433 
434 
435 
436 
437 
438 
439 
440 	public void setFalse(T thing, C name) throws ContradictionException {
441 		IConstr constr = this.gator.gateFalse(getIntValue(thing));
442 		
443 		if (constr != null) {
444 			this.descs.put(constr, name);
445 		}
446 
447 	}
448 
449 	
450 
451 
452 
453 
454 
455 
456 
457 	public ImplicationRHS<T, C> implication(T... lhs) {
458 		IVecInt clause = new VecInt();
459 		for (T t : lhs) {
460 			clause.push(-getIntValue(t));
461 		}
462 		return new ImplicationRHS<T, C>(this, clause);
463 	}
464 
465 	public DisjunctionRHS<T, C> disjunction(T... lhs) {
466 		IVecInt literals = new VecInt();
467 		for (T t : lhs) {
468 			literals.push(-getIntValue(t));
469 		}
470 		return new DisjunctionRHS<T, C>(this, literals);
471 	}
472 
473 	
474 
475 
476 
477 
478 
479 
480 
481 
482 
483 
484 
485 	public void atLeast(C name, int i, T... things)
486 			throws ContradictionException {
487 		IVecInt literals = new VecInt();
488 		for (T t : things) {
489 			literals.push(getIntValue(t));
490 		}
491 		this.descs.put(this.solver.addAtLeast(literals, i), name);
492 	}
493 
494 	
495 
496 
497 
498 
499 
500 
501 
502 
503 
504 
505 
506 	public ImplicationNamer<T, C> atMost(int i, T... things)
507 			throws ContradictionException {
508 		IVec<IConstr> toName = new Vec<IConstr>();
509 		IVecInt literals = new VecInt();
510 		for (T t : things) {
511 			literals.push(getIntValue(t));
512 		}
513 		toName.push(this.solver.addAtMost(literals, i));
514 		return new ImplicationNamer<T, C>(this, toName);
515 	}
516 
517 	
518 
519 
520 
521 
522 
523 
524 
525 
526 
527 
528 
529 	public void atMost(C name, int i, T... things)
530 			throws ContradictionException {
531 		IVecInt literals = new VecInt();
532 		for (T t : things) {
533 			literals.push(getIntValue(t));
534 		}
535 		this.descs.put(this.solver.addAtMost(literals, i), name);
536 	}
537 
538 	
539 
540 
541 
542 
543 
544 
545 
546 	public void clause(C name, T... things) throws ContradictionException {
547 		IVecInt literals = new VecInt(things.length);
548 		for (T t : things) {
549 			literals.push(getIntValue(t));
550 		}
551 		IConstr constr = this.gator.addClause(literals);
552 		
553 		if (constr != null) {
554 			this.descs.put(constr, name);
555 		}
556 
557 	}
558 
559 	
560 
561 
562 
563 
564 
565 
566 
567 
568 
569 	public void iff(C name, T thing, T... otherThings)
570 			throws ContradictionException {
571 		IVecInt literals = new VecInt(otherThings.length);
572 		for (T t : otherThings) {
573 			literals.push(getIntValue(t));
574 		}
575 		IConstr[] constrs = this.gator.iff(getIntValue(thing), literals);
576 		for (IConstr constr : constrs) {
577 			if (constr != null) {
578 				this.descs.put(constr, name);
579 			}
580 		}
581 	}
582 
583 	
584 
585 
586 
587 
588 
589 
590 
591 
592 	public void and(C name, T thing, T... otherThings)
593 			throws ContradictionException {
594 		IVecInt literals = new VecInt(otherThings.length);
595 		for (T t : otherThings) {
596 			literals.push(getIntValue(t));
597 		}
598 		IConstr[] constrs = this.gator.and(getIntValue(thing), literals);
599 		for (IConstr constr : constrs) {
600 			if (constr != null) {
601 				this.descs.put(constr, name);
602 			}
603 		}
604 	}
605 
606 	
607 
608 
609 
610 
611 
612 
613 
614 
615 	public void or(C name, T thing, T... otherThings)
616 			throws ContradictionException {
617 		IVecInt literals = new VecInt(otherThings.length);
618 		for (T t : otherThings) {
619 			literals.push(getIntValue(t));
620 		}
621 		IConstr[] constrs = this.gator.or(getIntValue(thing), literals);
622 		for (IConstr constr : constrs) {
623 			if (constr != null) {
624 				this.descs.put(constr, name);
625 			}
626 		}
627 	}
628 
629 	
630 
631 
632 
633 
634 
635 
636 
637 
638 	public void halfOr(C name, T thing, T... otherThings)
639 			throws ContradictionException {
640 		IVecInt literals = new VecInt(otherThings.length);
641 		for (T t : otherThings) {
642 			literals.push(getIntValue(t));
643 		}
644 		IConstr[] constrs = this.gator.halfOr(getIntValue(thing), literals);
645 		for (IConstr constr : constrs) {
646 			if (constr != null) {
647 				this.descs.put(constr, name);
648 			}
649 		}
650 	}
651 
652 	
653 
654 
655 
656 
657 
658 
659 
660 
661 	public void ifThenElse(C name, T thing, T conditionThing, T thenThing,
662 			T elseThing) throws ContradictionException {
663 		IConstr[] constrs = this.gator.ite(getIntValue(thing),
664 				getIntValue(conditionThing), getIntValue(thenThing),
665 				getIntValue(elseThing));
666 		for (IConstr constr : constrs) {
667 			if (constr != null) {
668 				this.descs.put(constr, name);
669 			}
670 		}
671 	}
672 
673 	
674 
675 
676 
677 
678 
679 
680 
681 	public void setObjectiveFunction(WeightedObject<T>... wobj) {
682 		createObjectivetiveFunctionIfNeeded(wobj.length);
683 		for (WeightedObject<T> wo : wobj) {
684 			addProperly(wo.thing, wo.getWeight());
685 		}
686 
687 	}
688 
689 	private void addProperly(T thing, BigInteger weight) {
690 		int lit = getIntValue(thing);
691 		int index;
692 		if (this.canonicalOptFunction
693 				&& (index = this.objLiterals.indexOf(lit)) != -1) {
694 			this.objCoefs.set(index, this.objCoefs.get(index).add(weight));
695 			if (this.objCoefs.get(index).equals(BigInteger.ZERO)) {
696 				this.objLiterals.delete(index);
697 				this.objCoefs.delete(index);
698 			}
699 		} else {
700 			this.objLiterals.push(lit);
701 			this.objCoefs.push(weight);
702 		}
703 	}
704 
705 	private void createObjectivetiveFunctionIfNeeded(int n) {
706 		if (this.objFunction == null) {
707 			this.objLiterals = new VecInt(n);
708 			this.objCoefs = new Vec<BigInteger>(n);
709 			this.objFunction = new ObjectiveFunction(this.objLiterals,
710 					this.objCoefs);
711 			this.solver.setObjectiveFunction(this.objFunction);
712 		}
713 	}
714 
715 	
716 
717 
718 
719 
720 
721 	public void addToObjectiveFunction(T thing, int weight) {
722 		addToObjectiveFunction(thing, BigInteger.valueOf(weight));
723 	}
724 
725 	
726 
727 
728 
729 
730 
731 	public void addToObjectiveFunction(T thing, BigInteger weight) {
732 		createObjectivetiveFunctionIfNeeded(20);
733 		addProperly(thing, weight);
734 	}
735 
736 	
737 
738 
739 
740 
741 
742 
743 
744 
745 	public void atLeast(C name, BigInteger degree, WeightedObject<T>... wobj)
746 			throws ContradictionException {
747 		IVecInt literals = new VecInt(wobj.length);
748 		IVec<BigInteger> coeffs = new Vec<BigInteger>(wobj.length);
749 		for (WeightedObject<T> wo : wobj) {
750 			literals.push(getIntValue(wo.thing));
751 			coeffs.push(wo.getWeight());
752 		}
753 		this.descs.put(
754 				this.solver.addPseudoBoolean(literals, coeffs, true, degree),
755 				name);
756 	}
757 
758 	
759 
760 
761 
762 
763 
764 
765 
766 
767 	public void atMost(C name, BigInteger degree, WeightedObject<T>... wobj)
768 			throws ContradictionException {
769 		IVecInt literals = new VecInt(wobj.length);
770 		IVec<BigInteger> coeffs = new Vec<BigInteger>(wobj.length);
771 		for (WeightedObject<T> wo : wobj) {
772 			literals.push(getIntValue(wo.thing));
773 			coeffs.push(wo.getWeight());
774 		}
775 		this.descs.put(
776 				this.solver.addPseudoBoolean(literals, coeffs, false, degree),
777 				name);
778 	}
779 
780 	public void atMost(C name, int degree, WeightedObject<T>... wobj)
781 			throws ContradictionException {
782 		atMost(name, BigInteger.valueOf(degree), wobj);
783 	}
784 
785 	
786 
787 
788 
789 	public void stopSolver() {
790 		this.solver.expireTimeout();
791 	}
792 
793 	
794 
795 
796 
797 	public void stopExplanation() {
798 		if (!this.explanationEnabled) {
799 			throw new UnsupportedOperationException("Explanation not enabled!");
800 		}
801 		this.xplain.cancelExplanation();
802 	}
803 
804 	public void discard(IVec<T> things) throws ContradictionException {
805 		IVecInt literals = new VecInt(things.size());
806 		for (Iterator<T> it = things.iterator(); it.hasNext();) {
807 			literals.push(-getIntValue(it.next()));
808 		}
809 		this.solver.addBlockingClause(literals);
810 	}
811 
812 	public void discardSolutionsWithObjectiveValueGreaterThan(long value)
813 			throws ContradictionException {
814 		ObjectiveFunction obj = this.solver.getObjectiveFunction();
815 		IVecInt literals = new VecInt(obj.getVars().size());
816 		obj.getVars().copyTo(literals);
817 		IVec<BigInteger> coeffs = new Vec<BigInteger>(obj.getCoeffs().size());
818 		obj.getCoeffs().copyTo(coeffs);
819 		this.solver.addPseudoBoolean(literals, coeffs, false,
820 				BigInteger.valueOf(value));
821 	}
822 
823 	public String getObjectiveFunction() {
824 		ObjectiveFunction obj = this.solver.getObjectiveFunction();
825 		StringBuffer stb = new StringBuffer();
826 		for (int i = 0; i < obj.getVars().size(); i++) {
827 			stb.append(obj.getCoeffs().get(i)
828 					+ (obj.getVars().get(i) > 0 ? " " : "~")
829 					+ this.mapToDomain.get(Math.abs(obj.getVars().get(i)))
830 					+ " ");
831 		}
832 		return stb.toString();
833 	}
834 
835 	public int getNumberOfVariables() {
836 		return this.mapToDimacs.size();
837 	}
838 
839 	public int getNumberOfConstraints() {
840 		return this.descs.size();
841 	}
842 
843 	public Map<Integer, T> getMappingToDomain() {
844 		return this.mapToDomain;
845 	}
846 
847 	public Object not(T thing) {
848 		return new Negation(thing);
849 	}
850 
851 	
852 
853 
854 
855 	public IPBSolver getSolver() {
856 		if (this.explanationEnabled) {
857 			return this.xplain.decorated();
858 		}
859 		return this.solver;
860 	}
861 
862 	
863 
864 
865 
866 
867 	public void reset() {
868 		this.mapToDimacs.clear();
869 		this.mapToDomain.clear();
870 		this.descs.clear();
871 		this.solver.reset();
872 		if (this.objLiterals != null) {
873 			this.objLiterals.clear();
874 			this.objCoefs.clear();
875 		}
876 	}
877 
878 	
879 
880 
881 
882 
883 
884 
885 
886 
887 
888 
889 
890 
891 
892 	public void impliedBy(Collection<T> assumptions, Collection<T> satisfied,
893 			Collection<T> falsified) throws TimeoutException {
894 		IVecInt assump = new VecInt(assumptions.size());
895 		for (T thing : assumptions) {
896 			assump.push(getIntValue(thing));
897 		}
898 		IVecInt implied = Backbone.compute(solver, assump);
899 		int p;
900 		for (IteratorInt it = implied.iterator(); it.hasNext();) {
901 			p = it.next();
902 			if (p > 0) {
903 				satisfied.add(mapToDomain.get(p));
904 			} else {
905 				falsified.add(mapToDomain.get(-p));
906 			}
907 		}
908 	}
909 }