1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.sat4j.pb.tools;
21
22 import java.math.BigInteger;
23 import java.util.Collection;
24 import java.util.Collections;
25 import java.util.HashMap;
26 import java.util.Iterator;
27 import java.util.Map;
28 import java.util.Set;
29 import java.util.TreeSet;
30
31 import org.sat4j.core.Vec;
32 import org.sat4j.core.VecInt;
33 import org.sat4j.pb.IPBSolver;
34 import org.sat4j.pb.ObjectiveFunction;
35 import org.sat4j.specs.ContradictionException;
36 import org.sat4j.specs.IConstr;
37 import org.sat4j.specs.IVec;
38 import org.sat4j.specs.IVecInt;
39 import org.sat4j.specs.TimeoutException;
40 import org.sat4j.tools.GateTranslator;
41
42
43
44
45
46
47
48
49
50
51
52
53 public class DependencyHelper<T, C> {
54
55 public final INegator<T> NO_NEGATION = new INegator<T>() {
56
57 public boolean isNegated(T thing) {
58 return false;
59 }
60
61 public T unNegate(T thing) {
62 return thing;
63 }
64 };
65
66
67
68
69 private static final long serialVersionUID = 1L;
70
71 private final Map<T, Integer> mapToDimacs = new HashMap<T, Integer>();
72 private final Map<Integer, T> mapToDomain = new HashMap<Integer, T>();
73 final Map<IConstr, C> descs = new HashMap<IConstr, C>();
74
75 private final XplainPB xplain;
76 private final GateTranslator gator;
77 final IPBSolver solver;
78 private INegator<T> negator = NO_NEGATION;
79
80 private ObjectiveFunction objFunction;
81 private IVecInt objLiterals;
82 private IVec<BigInteger> objCoefs;
83
84 public boolean explanationEnabled = true;
85
86
87
88
89
90
91 public DependencyHelper(IPBSolver solver) {
92 this(solver, true);
93 }
94
95 public DependencyHelper(IPBSolver solver, boolean explanationEnabled) {
96 if (explanationEnabled) {
97 this.xplain = new XplainPB(solver);
98 this.solver = this.xplain;
99 } else {
100 this.xplain = null;
101 this.solver = solver;
102 }
103 this.gator = new GateTranslator(this.solver);
104 }
105
106 public void setNegator(INegator<T> negator) {
107 this.negator = negator;
108 }
109
110
111
112
113
114
115
116
117 int getIntValue(T thing) {
118 T myThing;
119 boolean negated = negator.isNegated(thing);
120 if (negated) {
121 myThing = negator.unNegate(thing);
122 } else {
123 myThing = thing;
124 }
125 Integer intValue = mapToDimacs.get(myThing);
126 if (intValue == null) {
127 intValue = solver.nextFreeVarId(true);
128 mapToDomain.put(intValue, thing);
129 mapToDimacs.put(thing, intValue);
130 }
131 if (negated) {
132 return -intValue;
133 }
134 return intValue;
135 }
136
137
138
139
140
141
142
143
144
145
146 public IVec<T> getSolution() {
147 int[] model = solver.model();
148 IVec<T> toInstall = new Vec<T>();
149 for (int i : model) {
150 if (i > 0) {
151 toInstall.push(mapToDomain.get(i));
152 }
153 }
154 return toInstall;
155 }
156
157 public BigInteger getSolutionCost() {
158 return objFunction.calculateDegree(solver.model());
159 }
160
161
162
163
164
165
166
167
168
169
170
171 public boolean getBooleanValueFor(T t) {
172 return solver.model(getIntValue(t));
173 }
174
175
176
177
178
179
180
181 public boolean hasASolution() throws TimeoutException {
182 return solver.isSatisfiable();
183 }
184
185
186
187
188
189
190
191 public boolean hasASolution(IVec<T> assumps) throws TimeoutException {
192 IVecInt assumptions = new VecInt();
193 for (Iterator<T> it = assumps.iterator(); it.hasNext();) {
194 assumptions.push(getIntValue(it.next()));
195 }
196 return solver.isSatisfiable(assumptions);
197 }
198
199
200
201
202
203
204
205 public boolean hasASolution(Collection<T> assumps) throws TimeoutException {
206 IVecInt assumptions = new VecInt();
207 for (T t : assumps) {
208 assumptions.push(getIntValue(t));
209 }
210 return solver.isSatisfiable(assumptions);
211 }
212
213
214
215
216
217
218
219
220
221
222
223 public Set<C> why() throws TimeoutException {
224 if (!explanationEnabled) {
225 throw new UnsupportedOperationException("Explanation not enabled!");
226 }
227 Collection<IConstr> explanation = xplain.explain();
228 Set<C> ezexplain = new TreeSet<C>();
229 for (IConstr constr : explanation) {
230 C desc = descs.get(constr);
231 if (desc != null) {
232 ezexplain.add(desc);
233 }
234 }
235 return ezexplain;
236 }
237
238
239
240
241
242
243
244
245
246 public Set<C> why(T thing) throws TimeoutException {
247 IVecInt assumps = new VecInt();
248 assumps.push(-getIntValue(thing));
249 return why(assumps);
250 }
251
252
253
254
255
256
257
258
259
260 public Set<C> whyNot(T thing) throws TimeoutException {
261 IVecInt assumps = new VecInt();
262 assumps.push(getIntValue(thing));
263 return why(assumps);
264 }
265
266 private Set<C> why(IVecInt assumps) throws TimeoutException {
267 if (xplain.isSatisfiable(assumps)) {
268 return Collections.emptySet();
269 }
270 return why();
271 }
272
273
274
275
276
277
278
279
280
281
282
283
284
285 public void setTrue(T thing, C name) throws ContradictionException {
286 descs.put(gator.gateTrue(getIntValue(thing)), name);
287 }
288
289
290
291
292
293
294
295
296
297
298
299
300
301 public void setFalse(T thing, C name) throws ContradictionException {
302 descs.put(gator.gateFalse(getIntValue(thing)), name);
303 }
304
305
306
307
308
309
310
311
312
313 public ImplicationRHS<T, C> implication(T... lhs) {
314 IVecInt clause = new VecInt();
315 for (T t : lhs) {
316 clause.push(-getIntValue(t));
317 }
318 return new ImplicationRHS<T, C>(this, clause);
319 }
320
321 public DisjunctionRHS<T, C> disjunction(T... lhs) {
322 IVecInt literals = new VecInt();
323 for (T t : lhs) {
324 literals.push(-getIntValue(t));
325 }
326 return new DisjunctionRHS<T, C>(this, literals);
327 }
328
329
330
331
332
333
334
335
336
337
338
339
340
341 public ImplicationNamer<T, C> atMost(int i, T... things)
342 throws ContradictionException {
343 IVec<IConstr> toName = new Vec<IConstr>();
344 IVecInt literals = new VecInt();
345 for (T t : things) {
346 literals.push(getIntValue(t));
347 }
348 toName.push(solver.addAtMost(literals, i));
349 return new ImplicationNamer<T, C>(this, toName);
350 }
351
352
353
354
355
356
357
358
359
360 public void clause(C name, T... things) throws ContradictionException {
361 IVecInt literals = new VecInt(things.length);
362 for (T t : things) {
363 literals.push(getIntValue(t));
364 }
365 descs.put(gator.addClause(literals), name);
366 }
367
368
369
370
371
372
373
374
375
376
377
378 public void iff(C name, T thing, T... otherThings)
379 throws ContradictionException {
380 IVecInt literals = new VecInt(otherThings.length);
381 for (T t : otherThings) {
382 literals.push(getIntValue(t));
383 }
384 IConstr[] constrs = gator.iff(getIntValue(thing), literals);
385 for (IConstr constr : constrs) {
386 descs.put(constr, name);
387 }
388 }
389
390
391
392
393
394
395
396
397
398
399 public void and(C name, T thing, T... otherThings)
400 throws ContradictionException {
401 IVecInt literals = new VecInt(otherThings.length);
402 for (T t : otherThings) {
403 literals.push(getIntValue(t));
404 }
405 IConstr[] constrs = gator.and(getIntValue(thing), literals);
406 for (IConstr constr : constrs) {
407 descs.put(constr, name);
408 }
409 }
410
411
412
413
414
415
416
417
418
419
420 public void or(C name, T thing, T... otherThings)
421 throws ContradictionException {
422 IVecInt literals = new VecInt(otherThings.length);
423 for (T t : otherThings) {
424 literals.push(getIntValue(t));
425 }
426 IConstr[] constrs = gator.or(getIntValue(thing), literals);
427 for (IConstr constr : constrs) {
428 descs.put(constr, name);
429 }
430 }
431
432
433
434
435
436
437
438
439
440
441 public void ifThenElse(C name, T thing, T conditionThing, T thenThing,
442 T elseThing) throws ContradictionException {
443 IConstr[] constrs = gator.ite(getIntValue(thing),
444 getIntValue(conditionThing), getIntValue(thenThing),
445 getIntValue(elseThing));
446 for (IConstr constr : constrs) {
447 descs.put(constr, name);
448 }
449 }
450
451
452
453
454
455
456
457
458
459 public void setObjectiveFunction(WeightedObject<T>... wobj) {
460 createObjectivetiveFunctionIfNeeded(wobj.length);
461 for (WeightedObject<T> wo : wobj) {
462 objLiterals.push(getIntValue(wo.thing));
463 objCoefs.push(wo.getWeight());
464 }
465
466 }
467
468 private void createObjectivetiveFunctionIfNeeded(int n) {
469 if (objFunction == null) {
470 objLiterals = new VecInt(n);
471 objCoefs = new Vec<BigInteger>(n);
472 objFunction = new ObjectiveFunction(objLiterals, objCoefs);
473 solver.setObjectiveFunction(objFunction);
474 }
475 }
476
477
478
479
480
481
482
483 public void addToObjectiveFunction(T thing, int weight) {
484 addToObjectiveFunction(thing, BigInteger.valueOf(weight));
485 }
486
487
488
489
490
491
492
493 public void addToObjectiveFunction(T thing, BigInteger weight) {
494 createObjectivetiveFunctionIfNeeded(20);
495 objLiterals.push(getIntValue(thing));
496 objCoefs.push(weight);
497 }
498
499
500
501
502
503 public void stopSolver() {
504 solver.expireTimeout();
505 }
506
507
508
509
510
511 public void stopExplanation() {
512 if (!explanationEnabled) {
513 throw new UnsupportedOperationException("Explanation not enabled!");
514 }
515 xplain.cancelExplanation();
516 }
517
518 public void discard(IVec<T> things) throws ContradictionException {
519 IVecInt literals = new VecInt(things.size());
520 for (Iterator<T> it = things.iterator(); it.hasNext();) {
521 literals.push(-getIntValue(it.next()));
522 }
523 solver.addClause(literals);
524 }
525
526 public String getObjectiveFunction() {
527 ObjectiveFunction obj = solver.getObjectiveFunction();
528 StringBuffer stb = new StringBuffer();
529 for (int i = 0; i < obj.getVars().size(); i++) {
530 stb.append(obj.getCoeffs().get(i)
531 + (obj.getVars().get(i) > 0 ? " " : "~")
532 + mapToDomain.get(Math.abs(obj.getVars().get(i))) + " ");
533 }
534 return stb.toString();
535 }
536
537 public int getNumberOfVariables() {
538 return mapToDimacs.size();
539 }
540
541 public int getNumberOfConstraints() {
542 return descs.size();
543 }
544 }