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 package org.sat4j.maxsat;
31
32 import java.math.BigInteger;
33 import java.util.HashSet;
34 import java.util.Set;
35
36 import org.sat4j.core.ConstrGroup;
37 import org.sat4j.core.Vec;
38 import org.sat4j.core.VecInt;
39 import org.sat4j.pb.IPBSolver;
40 import org.sat4j.pb.ObjectiveFunction;
41 import org.sat4j.pb.PBSolverDecorator;
42 import org.sat4j.specs.ContradictionException;
43 import org.sat4j.specs.IConstr;
44 import org.sat4j.specs.IVec;
45 import org.sat4j.specs.IVecInt;
46 import org.sat4j.specs.IteratorInt;
47
48
49
50
51
52
53
54
55
56
57 public class WeightedMaxSatDecorator extends PBSolverDecorator {
58
59 public static final BigInteger SAT4J_MAX_BIG_INTEGER = new BigInteger(
60 "100000000000000000000000000000000000000000");
61
62 protected int nbnewvar;
63
64 private static final long serialVersionUID = 1L;
65
66 private BigInteger falsifiedWeight = BigInteger.ZERO;
67
68 private boolean maxVarIdFixed = false;
69 private final boolean equivalence;
70
71 private final IVecInt lits = new VecInt();
72
73 private final IVec<BigInteger> coefs = new Vec<BigInteger>();
74
75 private final ObjectiveFunction obj = new ObjectiveFunction(this.lits,
76 this.coefs);
77
78 private final Set<Integer> unitClauses = new HashSet<Integer>();
79
80 private boolean noNewVarForUnitSoftClauses = true;
81
82 public WeightedMaxSatDecorator(IPBSolver solver) {
83 this(solver, false);
84 }
85
86 public WeightedMaxSatDecorator(IPBSolver solver, boolean equivalence) {
87 super(solver);
88 solver.setObjectiveFunction(this.obj);
89 this.equivalence = equivalence;
90 }
91
92 @Override
93 public int newVar(int howmany) {
94 int res = super.newVar(howmany);
95 this.maxVarIdFixed = true;
96 return res;
97 }
98
99 @Override
100 public void setExpectedNumberOfClauses(int nb) {
101 this.lits.ensure(nb);
102 this.falsifiedWeight = BigInteger.ZERO;
103 super.setExpectedNumberOfClauses(nb);
104 }
105
106 protected BigInteger top = SAT4J_MAX_BIG_INTEGER;
107
108 public void setTopWeight(BigInteger top) {
109 this.top = top;
110 }
111
112 protected void checkMaxVarId() {
113 if (!this.maxVarIdFixed) {
114 throw new IllegalStateException(
115 "Please call newVar(int) before adding constraints!!!");
116 }
117 }
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134 @Override
135 public IConstr addClause(IVecInt literals) throws ContradictionException {
136 return addSoftClause(1, literals);
137 }
138
139
140
141
142
143
144
145
146
147 public IConstr addHardClause(IVecInt literals)
148 throws ContradictionException {
149 return super.addClause(literals);
150 }
151
152
153
154
155
156
157
158
159
160 public IConstr addSoftClause(IVecInt literals)
161 throws ContradictionException {
162 return addSoftClause(1, literals);
163 }
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178 public IConstr addSoftClause(int weight, IVecInt literals)
179 throws ContradictionException {
180 return addSoftClause(BigInteger.valueOf(weight), literals);
181 }
182
183 public IConstr addSoftClause(BigInteger weight, IVecInt literals)
184 throws ContradictionException {
185 checkMaxVarId();
186 if (weight.compareTo(this.top) < 0) {
187
188 if (literals.size() == 1 && noNewVarForUnitSoftClauses) {
189
190
191
192
193 int lit = -literals.get(0);
194 int index = this.lits.containsAt(lit);
195
196 this.unitClauses.add(-lit);
197
198 if (index == -1) {
199
200 index = this.lits.containsAt(-lit);
201 if (index != -1) {
202 this.falsifiedWeight = this.falsifiedWeight.add(weight);
203 BigInteger oldw = this.coefs.get(index);
204 BigInteger diff = oldw.subtract(weight);
205 if (diff.signum() > 0) {
206 this.coefs.set(index, diff);
207 } else if (diff.signum() < 0) {
208 this.lits.set(index, lit);
209 this.coefs.set(index, diff.abs());
210
211
212
213 this.falsifiedWeight = this.falsifiedWeight
214 .add(diff);
215 } else {
216 assert diff.signum() == 0;
217 this.lits.delete(index);
218 this.coefs.delete(index);
219 }
220 this.obj.setCorrection(this.falsifiedWeight);
221
222 } else {
223 registerLiteral(lit);
224 this.lits.push(lit);
225 this.coefs.push(weight);
226 }
227 } else {
228 this.coefs.set(index, this.coefs.get(index).add(weight));
229 }
230 return UnitWeightedClause.instance();
231 }
232 this.coefs.push(weight);
233 int newvar = nextFreeVarId(true);
234 literals.push(newvar);
235 this.lits.push(newvar);
236 if (this.equivalence) {
237 ConstrGroup constrs = new ConstrGroup();
238 IConstr constr = super.addClause(literals);
239 if (constr==null&&isVerbose()) {
240 System.out.println(getLogPrefix()+" solft constraint "+literals+"("+weight+") is ignored");
241 }
242 if (constr!=null) {
243 constrs.add(constr);
244 IVecInt clause = new VecInt(2);
245 clause.push(-newvar);
246 for (int i = 0; i < literals.size() - 1; i++) {
247 clause.push(-literals.get(i));
248 constrs.add(super.addClause(clause));
249 clause.pop();
250 }
251 }
252 return constrs;
253 }
254 }
255 IConstr constr = super.addClause(literals);
256 if (constr==null&&isVerbose()) {
257 System.out.println(getLogPrefix()+" hard constraint "+literals+"("+weight+") is ignored");
258 }
259 return constr;
260 }
261
262
263
264
265
266
267
268
269
270
271
272
273
274 public IConstr addSoftAtLeast(IVecInt literals, int degree)
275 throws ContradictionException {
276 return addSoftAtLeast(BigInteger.ONE, literals, degree);
277 }
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293 public IConstr addSoftAtLeast(int weight, IVecInt literals, int degree)
294 throws ContradictionException {
295 return addSoftAtLeast(BigInteger.valueOf(weight), literals, degree);
296 }
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312 public IConstr addSoftAtLeast(BigInteger weight, IVecInt literals,
313 int degree) throws ContradictionException {
314 checkMaxVarId();
315 if (weight.compareTo(this.top) < 0) {
316 this.coefs.push(weight);
317 int newvar = nextFreeVarId(true);
318 this.lits.push(newvar);
319 IVec<BigInteger> cardcoeffs = new Vec<BigInteger>(
320 literals.size() + 1);
321 cardcoeffs.growTo(literals.size(), BigInteger.ONE);
322 literals.push(newvar);
323 BigInteger bigDegree = BigInteger.valueOf(degree);
324 cardcoeffs.push(bigDegree);
325 return addPseudoBoolean(literals, cardcoeffs, true, bigDegree);
326 } else {
327 return addAtLeast(literals, degree);
328 }
329 }
330
331
332
333
334
335
336
337
338
339
340
341
342
343 public IConstr addSoftAtMost(IVecInt literals, int degree)
344 throws ContradictionException {
345 return addSoftAtMost(BigInteger.ONE, literals, degree);
346 }
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362 public IConstr addSoftAtMost(int weight, IVecInt literals, int degree)
363 throws ContradictionException {
364 return addSoftAtMost(BigInteger.valueOf(weight), literals, degree);
365 }
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381 public IConstr addSoftAtMost(BigInteger weight, IVecInt literals, int degree)
382 throws ContradictionException {
383 checkMaxVarId();
384 if (weight.compareTo(this.top) < 0) {
385 this.coefs.push(weight);
386 int newvar = nextFreeVarId(true);
387 this.lits.push(newvar);
388 IVec<BigInteger> cardcoeffs = new Vec<BigInteger>(
389 literals.size() + 1);
390 cardcoeffs.growTo(literals.size(), BigInteger.ONE);
391 literals.push(newvar);
392 BigInteger bigDegree = BigInteger.valueOf(degree);
393 cardcoeffs.push(bigDegree.negate());
394 return addPseudoBoolean(literals, cardcoeffs, true, bigDegree);
395 } else {
396 return addAtMost(literals, degree);
397 }
398 }
399
400
401
402
403
404
405
406 public void addLiteralsToMinimize(IVecInt literals) {
407 for (IteratorInt it = literals.iterator(); it.hasNext();) {
408 this.lits.push(it.next());
409 this.coefs.push(BigInteger.ONE);
410 }
411 }
412
413
414
415
416
417
418
419
420
421 public void addWeightedLiteralsToMinimize(IVecInt literals,
422 IVec<BigInteger> coefficients) {
423 if (literals.size() != this.coefs.size()) {
424 throw new IllegalArgumentException();
425 }
426 for (int i = 0; i < literals.size(); i++) {
427 this.lits.push(literals.get(i));
428 this.coefs.push(coefficients.get(i));
429 }
430 }
431
432
433
434
435
436
437
438
439
440 public void addWeightedLiteralsToMinimize(IVecInt literals,
441 IVecInt coefficients) {
442 if (literals.size() != coefficients.size()) {
443 throw new IllegalArgumentException();
444 }
445 for (int i = 0; i < literals.size(); i++) {
446 this.lits.push(literals.get(i));
447 this.coefs.push(BigInteger.valueOf(coefficients.get(i)));
448 }
449 }
450
451 @Override
452 public void reset() {
453 this.coefs.clear();
454 this.lits.clear();
455 this.nbnewvar = 0;
456 super.reset();
457 }
458
459
460
461
462
463
464
465
466
467
468 public void forceObjectiveValueTo(Number forcedValue)
469 throws ContradictionException {
470 if (this.lits.size() > 0) {
471
472 super.addPseudoBoolean(this.lits, this.coefs, false,
473 (BigInteger) forcedValue);
474 }
475 }
476
477
478
479
480 public Set<Integer> getUnitClauses() {
481 return this.unitClauses;
482 }
483
484
485
486
487
488
489
490 public boolean isNoNewVarForUnitSoftClauses() {
491 return noNewVarForUnitSoftClauses;
492 }
493
494
495
496
497
498
499
500
501 public void setNoNewVarForUnitSoftClauses(boolean noNewVarForUnitSoftClauses) {
502 this.noNewVarForUnitSoftClauses = noNewVarForUnitSoftClauses;
503 }
504
505 }