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