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 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 throw new UnsupportedOperationException();
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 protected void computeWatches() {
490 int indSwap = this.lits.length;
491 int tmpInt;
492 for (int i = 0; i <= this.degree && i < indSwap; i++) {
493 while (this.voc.isFalsified(this.lits[i]) && --indSwap > i) {
494 tmpInt = this.lits[i];
495 this.lits[i] = this.lits[indSwap];
496 this.lits[indSwap] = tmpInt;
497 }
498
499
500 if (!this.voc.isFalsified(this.lits[i])) {
501 this.watchCumul++;
502 this.voc.watch(this.lits[i] ^ 1, this);
503 }
504 }
505 if (learnt()) {
506
507
508 int free = 1;
509 while (this.watchCumul <= this.degree && free > 0) {
510 free = 0;
511
512 int maxlevel = -1, maxi = -1;
513 for (int i = this.watchCumul; i < this.lits.length; i++) {
514 if (this.voc.isFalsified(this.lits[i])) {
515 free++;
516 int level = this.voc.getLevel(this.lits[i]);
517 if (level > maxlevel) {
518 maxi = i;
519 maxlevel = level;
520 }
521 }
522 }
523 if (free > 0) {
524 assert maxi >= 0;
525 this.voc.watch(this.lits[maxi] ^ 1, this);
526 tmpInt = this.lits[maxi];
527 this.lits[maxi] = this.lits[this.watchCumul];
528 this.lits[this.watchCumul] = tmpInt;
529 this.watchCumul++;
530 free--;
531 assert free >= 0;
532 }
533 }
534 assert this.lits.length == 1 || this.watchCumul > 1;
535 }
536
537 }
538
539 protected MinWatchCard computePropagation(UnitPropagationListener s)
540 throws ContradictionException {
541
542
543 if (this.watchCumul == this.degree) {
544 for (int i = 0; i < this.lits.length; i++) {
545 if (!s.enqueue(this.lits[i])) {
546 throw new ContradictionException();
547 }
548 }
549 return null;
550 }
551
552
553 if (this.watchCumul < this.degree) {
554 throw new ContradictionException();
555 }
556 return this;
557 }
558
559 public int[] getLits() {
560 int[] tmp = new int[size()];
561 System.arraycopy(this.lits, 0, tmp, 0, size());
562 return tmp;
563 }
564
565 public ILits getVocabulary() {
566 return this.voc;
567 }
568
569 @Override
570 public boolean equals(Object card) {
571 if (card == null) {
572 return false;
573 }
574 try {
575 MinWatchCard mcard = (MinWatchCard) card;
576 if (mcard.degree != this.degree) {
577 return false;
578 }
579 if (this.lits.length != mcard.lits.length) {
580 return false;
581 }
582 boolean ok;
583 for (int lit : this.lits) {
584 ok = false;
585 for (int lit2 : mcard.lits) {
586 if (lit == lit2) {
587 ok = true;
588 break;
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 sum += this.degree;
608 return (int) sum / (this.lits.length + 1);
609 }
610
611
612
613
614 public void forwardActivity(double claInc) {
615
616 }
617
618 public boolean canBePropagatedMultipleTimes() {
619 return true;
620 }
621
622 public Constr toConstraint() {
623 return this;
624 }
625
626 public void calcReasonOnTheFly(int p, IVecInt trail, IVecInt outReason) {
627 throw new UnsupportedOperationException("Not implemented yet!");
628 }
629 }