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.TimeoutException;
51 import org.sat4j.tools.GateTranslator;
52
53
54
55
56
57
58
59
60
61
62
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
124
125
126 public DependencyHelper(IPBSolver solver) {
127 this(solver, true);
128 }
129
130
131
132
133
134
135
136
137
138
139
140 public DependencyHelper(IPBSolver solver, boolean explanationEnabled) {
141 this(solver, explanationEnabled, true);
142 }
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
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
180
181
182
183
184
185 protected int getIntValue(T thing) {
186 return getIntValue(thing, true);
187 }
188
189
190
191
192
193
194
195
196
197
198
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
227
228
229
230
231
232
233
234
235
236
237
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
254
255
256
257
258
259
260
261
262
263
264
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
285
286
287
288
289
290
291
292
293
294
295 public boolean getBooleanValueFor(T t) {
296 return this.solver.model(getIntValue(t, false));
297 }
298
299
300
301
302
303
304
305 public boolean hasASolution() throws TimeoutException {
306 return this.solver.isSatisfiable();
307 }
308
309
310
311
312
313
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
326
327
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
339
340
341
342
343
344
345
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
364
365
366
367
368
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
378
379
380
381
382
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
399
400
401
402
403
404
405
406
407
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
418
419
420
421
422
423
424
425
426
427
428 public void setFalse(T thing, C name) throws ContradictionException {
429 IConstr constr = this.gator.gateFalse(getIntValue(thing));
430
431 if (constr != null) {
432 this.descs.put(constr, name);
433 }
434
435 }
436
437
438
439
440
441
442
443
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
463
464
465
466
467
468
469
470
471
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
484
485
486
487
488
489
490
491
492
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
507
508
509
510
511
512
513
514
515
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
528
529
530
531
532
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
541 if (constr != null) {
542 this.descs.put(constr, name);
543 }
544
545 }
546
547
548
549
550
551
552
553
554
555
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
573
574
575
576
577
578
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
596
597
598
599
600
601
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
619
620
621
622
623
624
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
642
643
644
645
646
647
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
663
664
665
666
667
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
701
702
703
704
705 public void addToObjectiveFunction(T thing, int weight) {
706 addToObjectiveFunction(thing, BigInteger.valueOf(weight));
707 }
708
709
710
711
712
713
714
715 public void addToObjectiveFunction(T thing, BigInteger weight) {
716 createObjectivetiveFunctionIfNeeded(20);
717 addProperly(thing, weight);
718 }
719
720
721
722
723
724
725
726
727
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
744
745
746
747
748
749
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
771
772
773 public void stopSolver() {
774 this.solver.expireTimeout();
775 }
776
777
778
779
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
837
838
839 public IPBSolver getSolver() {
840 if (this.explanationEnabled) {
841 return this.xplain.decorated();
842 }
843 return this.solver;
844 }
845
846
847
848
849
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 }