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