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.pb.constraints.pb;
31
32 import java.io.Serializable;
33 import java.math.BigInteger;
34 import java.util.ArrayList;
35 import java.util.Collections;
36 import java.util.Comparator;
37 import java.util.List;
38
39 import org.sat4j.core.VecInt;
40 import org.sat4j.minisat.constraints.cnf.Lits;
41 import org.sat4j.minisat.core.Constr;
42 import org.sat4j.minisat.core.ILits;
43 import org.sat4j.minisat.core.Propagatable;
44 import org.sat4j.minisat.core.Undoable;
45 import org.sat4j.specs.ContradictionException;
46 import org.sat4j.specs.IVecInt;
47 import org.sat4j.specs.UnitPropagationListener;
48
49 public abstract class WatchPbLong implements Propagatable, Constr, Undoable,
50 Serializable {
51
52
53
54
55 private static final long serialVersionUID = 1L;
56
57 private static final int LIMIT_SELECTION_SORT = 15;
58
59
60
61 protected double activity;
62
63
64
65
66 protected long[] coefs;
67
68 protected long sumcoefs;
69
70
71
72
73 protected long degree;
74
75
76
77
78 protected int[] lits;
79
80
81
82
83 protected boolean learnt = false;
84
85
86
87
88 protected ILits voc;
89
90
91
92
93 WatchPbLong() {
94 }
95
96
97 WatchPbLong(IDataStructurePB mpb) {
98 int size = mpb.size();
99 this.lits = new int[size];
100 BigInteger[] bigCoefs = new BigInteger[size];
101 mpb.buildConstraintFromMapPb(this.lits, bigCoefs);
102 this.coefs = toLong(bigCoefs);
103
104 this.degree = mpb.getDegree().longValue();
105 this.sumcoefs = 0;
106 for (long c : this.coefs) {
107 this.sumcoefs += c;
108 }
109 this.learnt = true;
110
111 sort();
112 }
113
114
115 WatchPbLong(int[] lits, BigInteger[] coefs, BigInteger degree,
116 BigInteger sumCoefs) {
117 this.lits = lits;
118 this.coefs = toLong(coefs);
119 this.degree = degree.longValue();
120 this.sumcoefs = sumCoefs.longValue();
121
122 sort();
123 }
124
125 public static long[] toLong(BigInteger[] bigValues) {
126 long[] res = new long[bigValues.length];
127 for (int i = 0; i < res.length; i++) {
128 res[i] = bigValues[i].longValue();
129 }
130 return res;
131 }
132
133
134
135
136
137
138
139
140 public boolean isAssertive(int dl) {
141 long slack = 0;
142 for (int i = 0; i < this.lits.length; i++) {
143 if (this.coefs[i] > 0
144 && (!this.voc.isFalsified(this.lits[i]) || this.voc
145 .getLevel(this.lits[i]) >= dl)) {
146 slack = slack + this.coefs[i];
147 }
148 }
149 slack = slack - this.degree;
150 if (slack < 0) {
151 return false;
152 }
153 for (int i = 0; i < this.lits.length; i++) {
154 if (this.coefs[i] > 0
155 && (this.voc.isUnassigned(this.lits[i]) || this.voc
156 .getLevel(this.lits[i]) >= dl)
157 && slack < this.coefs[i]) {
158 return true;
159 }
160 }
161 return false;
162 }
163
164
165
166
167
168
169
170
171
172
173
174 public void calcReason(int p, IVecInt outReason) {
175 long sumfalsified = 0;
176 long tous = 0;
177 final int[] mlits = this.lits;
178 boolean ok = true;
179 for (int i = 0; i < mlits.length; i++) {
180 int q = mlits[i];
181 if (this.voc.isFalsified(q)) {
182 if (ok) {
183 outReason.push(q ^ 1);
184 sumfalsified += this.coefs[i];
185 if (this.sumcoefs - sumfalsified < this.degree) {
186 ok = false;
187 tous = sumfalsified;
188
189 }
190 } else {
191 tous += this.coefs[i];
192 }
193 }
194 }
195 }
196
197 protected abstract void computeWatches() throws ContradictionException;
198
199 protected abstract void computePropagation(UnitPropagationListener s)
200 throws ContradictionException;
201
202
203
204
205
206
207
208
209 public int get(int i) {
210 return this.lits[i];
211 }
212
213
214
215
216
217
218
219 public double getActivity() {
220 return this.activity;
221 }
222
223
224
225
226
227
228 public void incActivity(double claInc) {
229 if (this.learnt) {
230 this.activity += claInc;
231 }
232 }
233
234 public void setActivity(double d) {
235 if (this.learnt) {
236 this.activity = d;
237 }
238 }
239
240
241
242
243
244
245
246 public long slackConstraint() {
247 return computeLeftSide() - this.degree;
248 }
249
250
251
252
253
254
255
256
257
258
259
260 public long slackConstraint(long[] theCoefs, long theDegree) {
261 return computeLeftSide(theCoefs) - theDegree;
262 }
263
264
265
266
267
268
269
270
271
272 public long computeLeftSide(long[] theCoefs) {
273 long poss = 0;
274
275 for (int i = 0; i < this.lits.length; i++) {
276 if (!this.voc.isFalsified(this.lits[i])) {
277 assert theCoefs[i] >= 0;
278 poss = poss + theCoefs[i];
279 }
280 }
281 return poss;
282 }
283
284
285
286
287
288
289
290 public long computeLeftSide() {
291 return computeLeftSide(this.coefs);
292 }
293
294
295
296
297
298
299
300
301 protected boolean isSatisfiable() {
302 return computeLeftSide() >= this.degree;
303 }
304
305
306
307
308
309
310
311 public boolean learnt() {
312 return this.learnt;
313 }
314
315
316
317
318
319
320 public boolean locked() {
321 for (int p : this.lits) {
322 if (this.voc.getReason(p) == this) {
323 return true;
324 }
325 }
326 return false;
327 }
328
329
330
331
332
333
334
335
336
337
338
339 protected static BigInteger ppcm(BigInteger a, BigInteger b) {
340 return a.divide(a.gcd(b)).multiply(b);
341 }
342
343
344
345
346
347
348
349 public void rescaleBy(double d) {
350 this.activity *= d;
351 }
352
353 void selectionSort(int from, int to) {
354 int i, j, bestIndex;
355 long tmp;
356 int tmp2;
357
358 for (i = from; i < to - 1; i++) {
359 bestIndex = i;
360 for (j = i + 1; j < to; j++) {
361 if (this.coefs[j] > this.coefs[bestIndex]
362 || this.coefs[j] == this.coefs[bestIndex]
363 && this.lits[j] > this.lits[bestIndex]) {
364 bestIndex = j;
365 }
366 }
367 tmp = this.coefs[i];
368 this.coefs[i] = this.coefs[bestIndex];
369 this.coefs[bestIndex] = tmp;
370 tmp2 = this.lits[i];
371 this.lits[i] = this.lits[bestIndex];
372 this.lits[bestIndex] = tmp2;
373 }
374 }
375
376
377
378
379 public void setLearnt() {
380 this.learnt = true;
381 }
382
383
384
385
386
387
388 public boolean simplify() {
389 long cumul = 0;
390
391 int i = 0;
392 while (i < this.lits.length && cumul < this.degree) {
393 if (this.voc.isSatisfied(this.lits[i])) {
394
395 cumul = cumul + this.coefs[i];
396 }
397 i++;
398 }
399
400 return cumul >= this.degree;
401 }
402
403 public final int size() {
404 return this.lits.length;
405 }
406
407
408
409
410 protected final void sort() {
411 assert this.lits != null;
412 if (this.coefs.length > 0) {
413 this.sort(0, size());
414 long buffInt = this.coefs[0];
415 for (int i = 1; i < this.coefs.length; i++) {
416 assert buffInt >= this.coefs[i];
417 buffInt = this.coefs[i];
418 }
419 }
420 }
421
422
423
424
425
426
427
428
429
430 protected final void sort(int from, int to) {
431 int width = to - from;
432 if (width <= LIMIT_SELECTION_SORT) {
433 selectionSort(from, to);
434 } else {
435 int indPivot = width / 2 + from;
436 long pivot = this.coefs[indPivot];
437 int litPivot = this.lits[indPivot];
438 long tmp;
439 int i = from - 1;
440 int j = to;
441 int tmp2;
442
443 for (;;) {
444 do {
445 i++;
446 } while (this.coefs[i] > pivot || this.coefs[i] == pivot
447 && this.lits[i] > litPivot);
448 do {
449 j--;
450 } while (pivot > this.coefs[j] || this.coefs[j] == pivot
451 && this.lits[j] < litPivot);
452
453 if (i >= j) {
454 break;
455 }
456
457 tmp = this.coefs[i];
458 this.coefs[i] = this.coefs[j];
459 this.coefs[j] = tmp;
460 tmp2 = this.lits[i];
461 this.lits[i] = this.lits[j];
462 this.lits[j] = tmp2;
463 }
464
465 sort(from, i);
466 sort(i, to);
467 }
468
469 }
470
471 @Override
472 public String toString() {
473 StringBuffer stb = new StringBuffer();
474
475 if (this.lits.length > 0) {
476 for (int i = 0; i < this.lits.length; i++) {
477 stb.append(" + ");
478 stb.append(this.coefs[i]);
479 stb.append(".");
480 stb.append(Lits.toString(this.lits[i]));
481 stb.append("[");
482 stb.append(this.voc.valueToString(this.lits[i]));
483 stb.append("@");
484 stb.append(this.voc.getLevel(this.lits[i]));
485 stb.append("]");
486 stb.append(" ");
487 }
488 stb.append(">= ");
489 stb.append(this.degree);
490 }
491 return stb.toString();
492 }
493
494 public void assertConstraint(UnitPropagationListener s) {
495 long tmp = slackConstraint();
496 for (int i = 0; i < this.lits.length; i++) {
497 if (this.voc.isUnassigned(this.lits[i]) && tmp < this.coefs[i]) {
498 boolean ret = s.enqueue(this.lits[i], this);
499 assert ret;
500 }
501 }
502 }
503
504 public void assertConstraintIfNeeded(UnitPropagationListener s) {
505 assertConstraint(s);
506 }
507
508 public void register() {
509 assert this.learnt;
510 try {
511 computeWatches();
512 } catch (ContradictionException e) {
513 System.out.println(this);
514 assert false;
515 }
516 }
517
518
519
520
521
522
523 public int[] getLits() {
524 int[] litsBis = new int[this.lits.length];
525 System.arraycopy(this.lits, 0, litsBis, 0, this.lits.length);
526 return litsBis;
527 }
528
529 public ILits getVocabulary() {
530 return this.voc;
531 }
532
533
534
535
536
537
538 public IVecInt computeAnImpliedClause() {
539 long cptCoefs = 0;
540 int index = this.coefs.length;
541 while (cptCoefs > this.degree && index > 0) {
542 cptCoefs = cptCoefs + this.coefs[--index];
543 }
544 if (index > 0 && index < size() / 2) {
545 IVecInt literals = new VecInt(index);
546 for (int j = 0; j <= index; j++) {
547 literals.push(this.lits[j]);
548 }
549 return literals;
550 }
551 return null;
552 }
553
554 public boolean coefficientsEqualToOne() {
555 return false;
556 }
557
558 @Override
559 public boolean equals(Object pb) {
560 if (pb == null) {
561 return false;
562 }
563
564
565
566
567 try {
568
569 WatchPbLong wpb = (WatchPbLong) pb;
570 if (this.degree != wpb.degree
571 || this.coefs.length != wpb.coefs.length
572 || this.lits.length != wpb.lits.length) {
573 return false;
574 }
575 int lit;
576 boolean ok;
577 for (int ilit = 0; ilit < this.coefs.length; ilit++) {
578 lit = this.lits[ilit];
579 ok = false;
580 for (int ilit2 = 0; ilit2 < this.coefs.length; ilit2++) {
581 if (wpb.lits[ilit2] == lit) {
582 if (wpb.coefs[ilit2] != this.coefs[ilit]) {
583 return false;
584 }
585
586 ok = true;
587 break;
588
589 }
590 }
591 if (!ok) {
592 return false;
593 }
594 }
595 return true;
596 } catch (ClassCastException e) {
597 return false;
598 }
599 }
600
601 @Override
602 public int hashCode() {
603 long sum = 0;
604 for (int p : this.lits) {
605 sum += p;
606 }
607 return (int) sum / this.lits.length;
608 }
609
610 public void forwardActivity(double claInc) {
611 if (!this.learnt) {
612 this.activity += claInc;
613 }
614 }
615
616 public void remove(UnitPropagationListener upl) {
617 }
618
619 public boolean propagate(UnitPropagationListener s, int p) {
620 return false;
621 }
622
623 public void undo(int p) {
624 }
625
626 public boolean canBePropagatedMultipleTimes() {
627 return true;
628 }
629
630 public Constr toConstraint() {
631 return this;
632 }
633
634 public void calcReasonOnTheFly(int p, IVecInt trail, IVecInt outReason) {
635 long sumfalsified = 0;
636 List<Integer> sortedList = new ArrayList<Integer>();
637 for (int q : this.lits) {
638 sortedList.add(q);
639 }
640 Collections.sort(sortedList, levelBased);
641 IVecInt vlits = new VecInt(this.lits);
642 int index;
643 for (int q : sortedList) {
644 if (voc.isFalsified(q)) {
645 outReason.push(q ^ 1);
646 index = vlits.indexOf(q);
647 sumfalsified += coefs[index];
648 if (this.sumcoefs - sumfalsified < this.degree) {
649 return;
650 }
651 }
652 }
653 }
654
655 private final Comparator<Integer> levelBased = new Comparator<Integer>() {
656
657 public int compare(Integer o1, Integer o2) {
658 return voc.getLevel(o1) - voc.getLevel(o2);
659 }
660
661 };
662 }