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.minisat.core.UnitPropagationListener;
41 import org.sat4j.specs.ContradictionException;
42 import org.sat4j.specs.IVecInt;
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
256 return true;
257 }
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277 public static Constr minWatchCardNew(UnitPropagationListener s, ILits voc,
278 IVecInt ps, boolean moreThan, int degree)
279 throws ContradictionException {
280
281 int mydegree = degree + linearisation(voc, ps);
282
283 if (ps.size() < mydegree) {
284 throw new ContradictionException();
285 } else if (ps.size() == mydegree) {
286 for (int i = 0; i < ps.size(); i++) {
287 if (!s.enqueue(ps.get(i))) {
288 throw new ContradictionException();
289 }
290 }
291 return new UnitClauses(ps);
292 }
293
294
295 MinWatchCard retour = new MinWatchCard(voc, ps, moreThan, mydegree);
296
297 if (retour.degree <= 0) {
298 return null;
299 }
300
301 retour.computeWatches();
302
303 retour.computePropagation(s);
304
305 return retour;
306 }
307
308
309
310
311 public final void normalize() {
312
313 if (!this.moreThan) {
314
315 this.degree = 0 - this.degree;
316
317 for (int indLit = 0; indLit < this.lits.length; indLit++) {
318 this.lits[indLit] = this.lits[indLit] ^ 1;
319 this.degree++;
320 }
321 this.moreThan = true;
322 }
323 }
324
325
326
327
328
329
330
331
332
333
334 public boolean propagate(UnitPropagationListener s, int p) {
335
336
337 if (this.watchCumul == this.degree) {
338 this.voc.watch(p, this);
339 return false;
340 }
341
342
343 int indFalsified = 0;
344 while ((this.lits[indFalsified] ^ 1) != p) {
345 indFalsified++;
346 }
347 assert this.watchCumul > this.degree;
348
349
350 int indSwap = this.degree + 1;
351 while (indSwap < this.lits.length
352 && this.voc.isFalsified(this.lits[indSwap])) {
353 indSwap++;
354 }
355
356
357 if (indSwap == this.lits.length) {
358
359 this.voc.watch(p, this);
360
361 this.watchCumul--;
362 assert this.watchCumul == this.degree;
363 this.voc.undos(p).push(this);
364
365
366 for (int i = 0; i <= this.degree; i++) {
367 if (p != (this.lits[i] ^ 1) && !s.enqueue(this.lits[i], this)) {
368 return false;
369 }
370 }
371
372 return true;
373 }
374
375 int tmpInt = this.lits[indSwap];
376 this.lits[indSwap] = this.lits[indFalsified];
377 this.lits[indFalsified] = tmpInt;
378
379
380 this.voc.watch(tmpInt ^ 1, this);
381
382 return true;
383 }
384
385
386
387
388
389
390 public void remove(UnitPropagationListener upl) {
391 for (int i = 0; i < Math.min(this.degree + 1, this.lits.length); i++) {
392 this.voc.watches(this.lits[i] ^ 1).remove(this);
393 }
394 }
395
396
397
398
399
400
401
402 public void rescaleBy(double d) {
403
404 }
405
406
407
408
409
410
411 public boolean simplify() {
412
413 for (int i = 0, count = 0; i < this.lits.length; i++) {
414 if (this.voc.isSatisfied(this.lits[i]) && ++count == this.degree) {
415 return true;
416 }
417 }
418
419 return false;
420 }
421
422
423
424
425
426
427 @Override
428 public String toString() {
429 StringBuffer stb = new StringBuffer();
430 stb.append("Card (" + this.lits.length + ") : ");
431 if (this.lits.length > 0) {
432
433 stb.append(Lits.toString(this.lits[0]));
434 stb.append("[");
435 stb.append(this.voc.valueToString(this.lits[0]));
436 stb.append("@");
437 stb.append(this.voc.getLevel(this.lits[0]));
438 stb.append("]");
439 stb.append(" ");
440
441 for (int i = 1; i < this.lits.length; i++) {
442
443 stb.append(" + ");
444 stb.append(Lits.toString(this.lits[i]));
445 stb.append("[");
446 stb.append(this.voc.valueToString(this.lits[i]));
447 stb.append("@");
448 stb.append(this.voc.getLevel(this.lits[i]));
449 stb.append("]");
450 stb.append(" ");
451
452 }
453 stb.append(">= ");
454 stb.append(this.degree);
455 }
456 return stb.toString();
457 }
458
459
460
461
462
463
464
465 public void undo(int p) {
466
467 this.watchCumul++;
468 }
469
470 public void setLearnt() {
471 throw new UnsupportedOperationException();
472 }
473
474 public void register() {
475 throw new UnsupportedOperationException();
476 }
477
478 public int size() {
479 return this.lits.length;
480 }
481
482 public int get(int i) {
483 return this.lits[i];
484 }
485
486 public void assertConstraint(UnitPropagationListener s) {
487 throw new UnsupportedOperationException();
488 }
489
490 protected void computeWatches() {
491 int indSwap = this.lits.length;
492 int tmpInt;
493 for (int i = 0; i <= this.degree && i < indSwap; i++) {
494 while (this.voc.isFalsified(this.lits[i]) && --indSwap > i) {
495 tmpInt = this.lits[i];
496 this.lits[i] = this.lits[indSwap];
497 this.lits[indSwap] = tmpInt;
498 }
499
500
501 if (!this.voc.isFalsified(this.lits[i])) {
502 this.watchCumul++;
503 this.voc.watch(this.lits[i] ^ 1, this);
504 }
505 }
506 if (learnt()) {
507
508
509 int free = 1;
510 while (this.watchCumul <= this.degree && free > 0) {
511 free = 0;
512
513 int maxlevel = -1, maxi = -1;
514 for (int i = this.watchCumul; i < this.lits.length; i++) {
515 if (this.voc.isFalsified(this.lits[i])) {
516 free++;
517 int level = this.voc.getLevel(this.lits[i]);
518 if (level > maxlevel) {
519 maxi = i;
520 maxlevel = level;
521 }
522 }
523 }
524 if (free > 0) {
525 assert maxi >= 0;
526 this.voc.watch(this.lits[maxi] ^ 1, this);
527 tmpInt = this.lits[maxi];
528 this.lits[maxi] = this.lits[this.watchCumul];
529 this.lits[this.watchCumul] = tmpInt;
530 this.watchCumul++;
531 free--;
532 assert free >= 0;
533 }
534 }
535 assert this.lits.length == 1 || this.watchCumul > 1;
536 }
537
538 }
539
540 protected MinWatchCard computePropagation(UnitPropagationListener s)
541 throws ContradictionException {
542
543
544 if (this.watchCumul == this.degree) {
545 for (int i = 0; i < this.lits.length; i++) {
546 if (!s.enqueue(this.lits[i])) {
547 throw new ContradictionException();
548 }
549 }
550 return null;
551 }
552
553
554 if (this.watchCumul < this.degree) {
555 throw new ContradictionException();
556 }
557 return this;
558 }
559
560 public int[] getLits() {
561 int[] tmp = new int[size()];
562 System.arraycopy(this.lits, 0, tmp, 0, size());
563 return tmp;
564 }
565
566 public ILits getVocabulary() {
567 return this.voc;
568 }
569
570 @Override
571 public boolean equals(Object card) {
572 if (card == null) {
573 return false;
574 }
575 try {
576 MinWatchCard mcard = (MinWatchCard) card;
577 if (mcard.degree != this.degree) {
578 return false;
579 }
580 if (this.lits.length != mcard.lits.length) {
581 return false;
582 }
583 boolean ok;
584 for (int lit : this.lits) {
585 ok = false;
586 for (int lit2 : mcard.lits) {
587 if (lit == lit2) {
588 ok = true;
589 break;
590 }
591 }
592 if (!ok) {
593 return false;
594 }
595 }
596 return true;
597 } catch (ClassCastException e) {
598 return false;
599 }
600 }
601
602 @Override
603 public int hashCode() {
604 long sum = 0;
605 for (int p : this.lits) {
606 sum += p;
607 }
608 sum += this.degree;
609 return (int) sum / (this.lits.length + 1);
610 }
611
612
613
614
615 public void forwardActivity(double claInc) {
616
617 }
618
619 public boolean canBePropagatedMultipleTimes() {
620 return true;
621 }
622
623 public Constr toConstraint() {
624 return this;
625 }
626 }