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.core;
31
32 import static org.sat4j.core.LiteralsUtils.neg;
33 import static org.sat4j.core.LiteralsUtils.toDimacs;
34 import static org.sat4j.core.LiteralsUtils.toInternal;
35 import static org.sat4j.core.LiteralsUtils.var;
36
37 import java.io.PrintStream;
38 import java.io.PrintWriter;
39 import java.lang.reflect.Field;
40 import java.util.HashMap;
41 import java.util.Iterator;
42 import java.util.Map;
43 import java.util.Timer;
44 import java.util.TimerTask;
45
46 import org.sat4j.core.ConstrGroup;
47 import org.sat4j.core.LiteralsUtils;
48 import org.sat4j.core.Vec;
49 import org.sat4j.core.VecInt;
50 import org.sat4j.specs.ContradictionException;
51 import org.sat4j.specs.IConstr;
52 import org.sat4j.specs.ILogAble;
53 import org.sat4j.specs.ISolver;
54 import org.sat4j.specs.ISolverService;
55 import org.sat4j.specs.IVec;
56 import org.sat4j.specs.IVecInt;
57 import org.sat4j.specs.IteratorInt;
58 import org.sat4j.specs.Lbool;
59 import org.sat4j.specs.SearchListener;
60 import org.sat4j.specs.TimeoutException;
61
62
63
64
65
66
67
68 public class Solver<D extends DataStructureFactory> implements ISolverService,
69 ICDCL<D> {
70
71 private static final long serialVersionUID = 1L;
72
73 private static final double CLAUSE_RESCALE_FACTOR = 1e-20;
74
75 private static final double CLAUSE_RESCALE_BOUND = 1 / CLAUSE_RESCALE_FACTOR;
76
77 protected ILogAble out;
78
79
80
81
82 protected final IVec<Constr> constrs = new Vec<Constr>();
83
84
85
86
87 protected final IVec<Constr> learnts = new Vec<Constr>();
88
89
90
91
92 private double claInc = 1.0;
93
94
95
96
97 private double claDecay = 1.0;
98
99
100
101
102
103 private int qhead = 0;
104
105
106
107
108 protected final IVecInt trail = new VecInt();
109
110
111
112
113 protected final IVecInt trailLim = new VecInt();
114
115
116
117
118 protected int rootLevel;
119
120 private int[] model = null;
121
122 protected ILits voc;
123
124 private IOrder order;
125
126 private final ActivityComparator comparator = new ActivityComparator();
127
128 private SolverStats stats = new SolverStats();
129
130 private LearningStrategy<D> learner;
131
132 protected volatile boolean undertimeout;
133
134 private long timeout = Integer.MAX_VALUE;
135
136 private boolean timeBasedTimeout = true;
137
138 protected D dsfactory;
139
140 private SearchParams params;
141
142 private final IVecInt __dimacs_out = new VecInt();
143
144 protected SearchListener slistener = new VoidTracing();
145
146 private RestartStrategy restarter;
147
148 private final Map<String, Counter> constrTypes = new HashMap<String, Counter>();
149
150 private boolean isDBSimplificationAllowed = false;
151
152 private final IVecInt learnedLiterals = new VecInt();
153
154 private boolean verbose = false;
155
156 private boolean keepHot = false;
157
158 private String prefix = "c ";
159 private int declaredMaxVarId = 0;
160
161 protected IVecInt dimacs2internal(IVecInt in) {
162 this.__dimacs_out.clear();
163 this.__dimacs_out.ensure(in.size());
164 int p;
165 for (int i = 0; i < in.size(); i++) {
166 p = in.get(i);
167 if (p == 0) {
168 throw new IllegalArgumentException(
169 "0 is not a valid variable identifier");
170 }
171 this.__dimacs_out.unsafePush(this.voc.getFromPool(p));
172 }
173 return this.__dimacs_out;
174 }
175
176
177
178
179 public void registerLiteral(int p) {
180 this.voc.getFromPool(p);
181 }
182
183
184
185
186
187
188
189 public Solver(LearningStrategy<D> learner, D dsf, IOrder order,
190 RestartStrategy restarter) {
191 this(learner, dsf, new SearchParams(), order, restarter);
192 }
193
194 public Solver(LearningStrategy<D> learner, D dsf, SearchParams params,
195 IOrder order, RestartStrategy restarter) {
196 this(learner, dsf, params, order, restarter, ILogAble.CONSOLE);
197 }
198
199 public Solver(LearningStrategy<D> learner, D dsf, SearchParams params,
200 IOrder order, RestartStrategy restarter, ILogAble logger) {
201 this.order = order;
202 this.params = params;
203 this.restarter = restarter;
204 this.out = logger;
205 setDataStructureFactory(dsf);
206
207 setLearningStrategy(learner);
208 }
209
210
211
212
213
214
215 public final void setDataStructureFactory(D dsf) {
216 this.dsfactory = dsf;
217 this.dsfactory.setUnitPropagationListener(this);
218 this.dsfactory.setLearner(this);
219 this.voc = dsf.getVocabulary();
220 this.order.setLits(this.voc);
221 }
222
223
224
225
226 public boolean isVerbose() {
227 return this.verbose;
228 }
229
230
231
232
233
234 public void setVerbose(boolean value) {
235 this.verbose = value;
236 }
237
238
239
240
241
242
243
244
245 public <S extends ISolverService> void setSearchListener(
246 SearchListener<S> sl) {
247 this.slistener = sl;
248 }
249
250
251
252
253
254
255 public <S extends ISolverService> SearchListener<S> getSearchListener() {
256 return this.slistener;
257 }
258
259
260
261
262
263
264
265 public void setLearner(LearningStrategy<D> strategy) {
266 setLearningStrategy(strategy);
267 }
268
269
270
271
272
273
274
275
276 public void setLearningStrategy(LearningStrategy<D> strategy) {
277 if (this.learner != null) {
278 this.learner.setSolver(null);
279 }
280 this.learner = strategy;
281 strategy.setSolver(this);
282 }
283
284 public void setTimeout(int t) {
285 this.timeout = t * 1000L;
286 this.timeBasedTimeout = true;
287 }
288
289 public void setTimeoutMs(long t) {
290 this.timeout = t;
291 this.timeBasedTimeout = true;
292 }
293
294 public void setTimeoutOnConflicts(int count) {
295 this.timeout = count;
296 this.timeBasedTimeout = false;
297 }
298
299
300
301
302
303
304
305 public void setSearchParams(SearchParams sp) {
306 this.params = sp;
307 }
308
309 public SearchParams getSearchParams() {
310 return this.params;
311 }
312
313
314
315
316
317
318
319
320 public void setRestartStrategy(RestartStrategy restarter) {
321 this.restarter = restarter;
322 }
323
324
325
326
327
328
329 public RestartStrategy getRestartStrategy() {
330 return this.restarter;
331 }
332
333 public void expireTimeout() {
334 this.undertimeout = false;
335 if (this.timeBasedTimeout) {
336 if (this.timer != null) {
337 this.timer.cancel();
338 this.timer = null;
339 }
340 } else {
341 if (this.conflictCount != null) {
342 this.conflictCount = null;
343 }
344 }
345 }
346
347 protected int nAssigns() {
348 return this.trail.size();
349 }
350
351 public int nConstraints() {
352 return this.constrs.size();
353 }
354
355 public void learn(Constr c) {
356 this.slistener.learn(c);
357 this.learnts.push(c);
358 c.setLearnt();
359 c.register();
360 this.stats.learnedclauses++;
361 switch (c.size()) {
362 case 2:
363 this.stats.learnedbinaryclauses++;
364 break;
365 case 3:
366 this.stats.learnedternaryclauses++;
367 break;
368 default:
369
370 }
371 }
372
373 public final int decisionLevel() {
374 return this.trailLim.size();
375 }
376
377 @Deprecated
378 public int newVar() {
379 int index = this.voc.nVars() + 1;
380 this.voc.ensurePool(index);
381 return index;
382 }
383
384 public int newVar(int howmany) {
385 this.voc.ensurePool(howmany);
386 this.declaredMaxVarId = howmany;
387 return howmany;
388 }
389
390 public IConstr addClause(IVecInt literals) throws ContradictionException {
391 IVecInt vlits = dimacs2internal(literals);
392 return addConstr(this.dsfactory.createClause(vlits));
393 }
394
395 public boolean removeConstr(IConstr co) {
396 if (co == null) {
397 throw new IllegalArgumentException(
398 "Reference to the constraint to remove needed!");
399 }
400 Constr c = (Constr) co;
401 c.remove(this);
402 this.constrs.remove(c);
403 clearLearntClauses();
404 String type = c.getClass().getName();
405 this.constrTypes.get(type).dec();
406 return true;
407 }
408
409
410
411
412 public boolean removeSubsumedConstr(IConstr co) {
413 if (co == null) {
414 throw new IllegalArgumentException(
415 "Reference to the constraint to remove needed!");
416 }
417 if (this.constrs.last() != co) {
418 throw new IllegalArgumentException(
419 "Can only remove latest added constraint!!!");
420 }
421 Constr c = (Constr) co;
422 c.remove(this);
423 this.constrs.pop();
424 String type = c.getClass().getName();
425 this.constrTypes.get(type).dec();
426 return true;
427 }
428
429 public void addAllClauses(IVec<IVecInt> clauses)
430 throws ContradictionException {
431 for (Iterator<IVecInt> iterator = clauses.iterator(); iterator
432 .hasNext();) {
433 addClause(iterator.next());
434 }
435 }
436
437 public IConstr addAtMost(IVecInt literals, int degree)
438 throws ContradictionException {
439 int n = literals.size();
440 IVecInt opliterals = new VecInt(n);
441 for (IteratorInt iterator = literals.iterator(); iterator.hasNext();) {
442 opliterals.push(-iterator.next());
443 }
444 return addAtLeast(opliterals, n - degree);
445 }
446
447 public IConstr addAtLeast(IVecInt literals, int degree)
448 throws ContradictionException {
449 IVecInt vlits = dimacs2internal(literals);
450 return addConstr(this.dsfactory.createCardinalityConstraint(vlits,
451 degree));
452 }
453
454 public IConstr addExactly(IVecInt literals, int n)
455 throws ContradictionException {
456 ConstrGroup group = new ConstrGroup(false);
457 group.add(addAtMost(literals, n));
458 group.add(addAtLeast(literals, n));
459 return group;
460 }
461
462 @SuppressWarnings("unchecked")
463 public boolean simplifyDB() {
464
465
466 IVec<Constr>[] cs = new IVec[] { this.constrs, this.learnts };
467 for (int type = 0; type < 2; type++) {
468 int j = 0;
469 for (int i = 0; i < cs[type].size(); i++) {
470 if (cs[type].get(i).simplify()) {
471
472 cs[type].get(i).remove(this);
473 } else {
474 cs[type].moveTo(j++, i);
475 }
476 }
477 cs[type].shrinkTo(j);
478 }
479 return true;
480 }
481
482
483
484
485
486
487 public int[] model() {
488 if (this.model == null) {
489 throw new UnsupportedOperationException(
490 "Call the solve method first!!!");
491 }
492 int[] nmodel = new int[this.model.length];
493 System.arraycopy(this.model, 0, nmodel, 0, this.model.length);
494 return nmodel;
495 }
496
497
498
499
500
501
502 public boolean enqueue(int p) {
503 return enqueue(p, null);
504 }
505
506
507
508
509
510
511
512 public boolean enqueue(int p, Constr from) {
513 assert p > 1;
514 if (this.voc.isSatisfied(p)) {
515
516 return true;
517 }
518 if (this.voc.isFalsified(p)) {
519
520 return false;
521 }
522
523 this.voc.satisfies(p);
524 this.voc.setLevel(p, decisionLevel());
525 this.voc.setReason(p, from);
526 this.trail.push(p);
527 if (from != null && from.learnt()) {
528 this.learnedConstraintsDeletionStrategy.onPropagation(from);
529 }
530 return true;
531 }
532
533 private boolean[] mseen = new boolean[0];
534
535 private final IVecInt mpreason = new VecInt();
536
537 private final IVecInt moutLearnt = new VecInt();
538
539
540
541
542
543 public void analyze(Constr confl, Pair results) throws TimeoutException {
544 assert confl != null;
545
546 final boolean[] seen = this.mseen;
547 final IVecInt outLearnt = this.moutLearnt;
548 final IVecInt preason = this.mpreason;
549
550 outLearnt.clear();
551 assert outLearnt.size() == 0;
552 for (int i = 0; i < seen.length; i++) {
553 seen[i] = false;
554 }
555
556 int counter = 0;
557 int p = ILits.UNDEFINED;
558
559 outLearnt.push(ILits.UNDEFINED);
560
561 int outBtlevel = 0;
562 IConstr prevConfl = null;
563
564 do {
565 preason.clear();
566 assert confl != null;
567 if (prevConfl != confl) {
568 confl.calcReason(p, preason);
569 this.learnedConstraintsDeletionStrategy
570 .onConflictAnalysis(confl);
571
572 for (int j = 0; j < preason.size(); j++) {
573 int q = preason.get(j);
574 this.order.updateVar(q);
575 if (!seen[q >> 1]) {
576 seen[q >> 1] = true;
577 if (this.voc.getLevel(q) == decisionLevel()) {
578 counter++;
579 this.order.updateVarAtDecisionLevel(q);
580 } else if (this.voc.getLevel(q) > 0) {
581
582
583
584 outLearnt.push(q ^ 1);
585 outBtlevel = Math.max(outBtlevel,
586 this.voc.getLevel(q));
587 }
588 }
589 }
590 }
591 prevConfl = confl;
592
593 do {
594 p = this.trail.last();
595 confl = this.voc.getReason(p);
596 undoOne();
597 } while (!seen[p >> 1]);
598
599
600 } while (--counter > 0);
601
602 outLearnt.set(0, p ^ 1);
603 this.simplifier.simplify(outLearnt);
604
605 Constr c = this.dsfactory.createUnregisteredClause(outLearnt);
606
607 this.learnedConstraintsDeletionStrategy.onClauseLearning(c);
608 results.reason = c;
609
610 assert outBtlevel > -1;
611 results.backtrackLevel = outBtlevel;
612 }
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627 public IVecInt analyzeFinalConflictInTermsOfAssumptions(Constr confl,
628 IVecInt assumps, int conflictingLiteral) {
629 if (assumps.size() == 0) {
630 return null;
631 }
632 while (!this.trailLim.isEmpty()
633 && this.trailLim.last() == this.trail.size()) {
634
635 this.trailLim.pop();
636 }
637 final boolean[] seen = this.mseen;
638 final IVecInt outLearnt = this.moutLearnt;
639 final IVecInt preason = this.mpreason;
640
641 outLearnt.clear();
642 if (this.trailLim.size() == 0) {
643
644 return outLearnt;
645 }
646
647 assert outLearnt.size() == 0;
648 for (int i = 0; i < seen.length; i++) {
649 seen[i] = false;
650 }
651
652 if (confl == null) {
653 seen[conflictingLiteral >> 1] = true;
654 }
655
656 int p = ILits.UNDEFINED;
657 while (confl == null && this.trail.size() > 0
658 && this.trailLim.size() > 0) {
659 p = this.trail.last();
660 confl = this.voc.getReason(p);
661 undoOne();
662 if (confl == null && p == (conflictingLiteral ^ 1)) {
663 outLearnt.push(toDimacs(p));
664 }
665 if (this.trail.size() <= this.trailLim.last()) {
666 this.trailLim.pop();
667 }
668 }
669 if (confl == null) {
670 return outLearnt;
671 }
672 do {
673
674 preason.clear();
675 confl.calcReason(p, preason);
676
677 for (int j = 0; j < preason.size(); j++) {
678 int q = preason.get(j);
679 if (!seen[q >> 1]) {
680 seen[q >> 1] = true;
681 if (this.voc.getReason(q) == null
682 && this.voc.getLevel(q) > 0) {
683 assert assumps.contains(toDimacs(q));
684 outLearnt.push(toDimacs(q));
685 }
686 }
687 }
688
689
690 do {
691 p = this.trail.last();
692 confl = this.voc.getReason(p);
693 undoOne();
694 if (decisionLevel() > 0
695 && this.trail.size() <= this.trailLim.last()) {
696 this.trailLim.pop();
697 }
698 } while (this.trail.size() > 0 && decisionLevel() > 0
699 && (!seen[p >> 1] || confl == null));
700 } while (decisionLevel() > 0);
701 return outLearnt;
702 }
703
704 public static final ISimplifier NO_SIMPLIFICATION = new ISimplifier() {
705
706
707
708 private static final long serialVersionUID = 1L;
709
710 public void simplify(IVecInt outLearnt) {
711 }
712
713 @Override
714 public String toString() {
715 return "No reason simplification";
716 }
717 };
718
719 public final ISimplifier SIMPLE_SIMPLIFICATION = new ISimplifier() {
720
721
722
723 private static final long serialVersionUID = 1L;
724
725 public void simplify(IVecInt conflictToReduce) {
726 simpleSimplification(conflictToReduce);
727 }
728
729 @Override
730 public String toString() {
731 return "Simple reason simplification";
732 }
733 };
734
735 public final ISimplifier EXPENSIVE_SIMPLIFICATION = new ISimplifier() {
736
737
738
739
740 private static final long serialVersionUID = 1L;
741
742 public void simplify(IVecInt conflictToReduce) {
743 expensiveSimplification(conflictToReduce);
744 }
745
746 @Override
747 public String toString() {
748 return "Expensive reason simplification";
749 }
750 };
751
752 public final ISimplifier EXPENSIVE_SIMPLIFICATION_WLONLY = new ISimplifier() {
753
754
755
756
757 private static final long serialVersionUID = 1L;
758
759 public void simplify(IVecInt conflictToReduce) {
760 expensiveSimplificationWLOnly(conflictToReduce);
761 }
762
763 @Override
764 public String toString() {
765 return "Expensive reason simplification specific for WL data structure";
766 }
767 };
768
769 private ISimplifier simplifier = NO_SIMPLIFICATION;
770
771
772
773
774
775
776 public void setSimplifier(SimplificationType simp) {
777 Field f;
778 try {
779 f = Solver.class.getDeclaredField(simp.toString());
780 this.simplifier = (ISimplifier) f.get(this);
781 } catch (Exception e) {
782 e.printStackTrace();
783 this.simplifier = NO_SIMPLIFICATION;
784 }
785 }
786
787
788
789
790
791
792
793
794 public void setSimplifier(ISimplifier simp) {
795 this.simplifier = simp;
796 }
797
798
799
800
801
802
803 public ISimplifier getSimplifier() {
804 return this.simplifier;
805 }
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829 private void simpleSimplification(IVecInt conflictToReduce) {
830 int i, j, p;
831 final boolean[] seen = this.mseen;
832 IConstr r;
833 for (i = j = 1; i < conflictToReduce.size(); i++) {
834 r = this.voc.getReason(conflictToReduce.get(i));
835 if (r == null || r.canBePropagatedMultipleTimes()) {
836 conflictToReduce.moveTo(j++, i);
837 } else {
838 for (int k = 0; k < r.size(); k++) {
839 p = r.get(k);
840 if (!seen[p >> 1] && this.voc.isFalsified(p)
841 && this.voc.getLevel(p) != 0) {
842 conflictToReduce.moveTo(j++, i);
843 break;
844 }
845 }
846 }
847 }
848 conflictToReduce.shrink(i - j);
849 this.stats.reducedliterals += i - j;
850 }
851
852 private final IVecInt analyzetoclear = new VecInt();
853
854 private final IVecInt analyzestack = new VecInt();
855
856
857 private void expensiveSimplification(IVecInt conflictToReduce) {
858
859
860 int i, j;
861
862 this.analyzetoclear.clear();
863 conflictToReduce.copyTo(this.analyzetoclear);
864 for (i = 1, j = 1; i < conflictToReduce.size(); i++) {
865 if (this.voc.getReason(conflictToReduce.get(i)) == null
866 || !analyzeRemovable(conflictToReduce.get(i))) {
867 conflictToReduce.moveTo(j++, i);
868 }
869 }
870 conflictToReduce.shrink(i - j);
871 this.stats.reducedliterals += i - j;
872 }
873
874
875
876
877 private boolean analyzeRemovable(int p) {
878 assert this.voc.getReason(p) != null;
879 ILits lvoc = this.voc;
880 IVecInt lanalyzestack = this.analyzestack;
881 IVecInt lanalyzetoclear = this.analyzetoclear;
882 lanalyzestack.clear();
883 lanalyzestack.push(p);
884 final boolean[] seen = this.mseen;
885 int top = lanalyzetoclear.size();
886 while (lanalyzestack.size() > 0) {
887 int q = lanalyzestack.last();
888 assert lvoc.getReason(q) != null;
889 Constr c = lvoc.getReason(q);
890 lanalyzestack.pop();
891 if (c.canBePropagatedMultipleTimes()) {
892 for (int j = top; j < lanalyzetoclear.size(); j++) {
893 seen[lanalyzetoclear.get(j) >> 1] = false;
894 }
895 lanalyzetoclear.shrink(lanalyzetoclear.size() - top);
896 return false;
897 }
898 for (int i = 0; i < c.size(); i++) {
899 int l = c.get(i);
900 if (!seen[var(l)] && lvoc.isFalsified(l)
901 && lvoc.getLevel(l) != 0) {
902 if (lvoc.getReason(l) == null) {
903 for (int j = top; j < lanalyzetoclear.size(); j++) {
904 seen[lanalyzetoclear.get(j) >> 1] = false;
905 }
906 lanalyzetoclear.shrink(lanalyzetoclear.size() - top);
907 return false;
908 }
909 seen[l >> 1] = true;
910 lanalyzestack.push(l);
911 lanalyzetoclear.push(l);
912 }
913 }
914
915 }
916
917 return true;
918 }
919
920
921 private void expensiveSimplificationWLOnly(IVecInt conflictToReduce) {
922
923
924 int i, j;
925
926 this.analyzetoclear.clear();
927 conflictToReduce.copyTo(this.analyzetoclear);
928 for (i = 1, j = 1; i < conflictToReduce.size(); i++) {
929 if (this.voc.getReason(conflictToReduce.get(i)) == null
930 || !analyzeRemovableWLOnly(conflictToReduce.get(i))) {
931 conflictToReduce.moveTo(j++, i);
932 }
933 }
934 conflictToReduce.shrink(i - j);
935 this.stats.reducedliterals += i - j;
936 }
937
938
939
940
941 private boolean analyzeRemovableWLOnly(int p) {
942 assert this.voc.getReason(p) != null;
943 this.analyzestack.clear();
944 this.analyzestack.push(p);
945 final boolean[] seen = this.mseen;
946 int top = this.analyzetoclear.size();
947 while (this.analyzestack.size() > 0) {
948 int q = this.analyzestack.last();
949 assert this.voc.getReason(q) != null;
950 Constr c = this.voc.getReason(q);
951 this.analyzestack.pop();
952 for (int i = 1; i < c.size(); i++) {
953 int l = c.get(i);
954 if (!seen[var(l)] && this.voc.getLevel(l) != 0) {
955 if (this.voc.getReason(l) == null) {
956 for (int j = top; j < this.analyzetoclear.size(); j++) {
957 seen[this.analyzetoclear.get(j) >> 1] = false;
958 }
959 this.analyzetoclear.shrink(this.analyzetoclear.size()
960 - top);
961 return false;
962 }
963 seen[l >> 1] = true;
964 this.analyzestack.push(l);
965 this.analyzetoclear.push(l);
966 }
967 }
968 }
969
970 return true;
971 }
972
973
974
975
976
977
978 protected void undoOne() {
979
980 int p = this.trail.last();
981 assert p > 1;
982 assert this.voc.getLevel(p) >= 0;
983 int x = p >> 1;
984
985 this.voc.unassign(p);
986 this.voc.setReason(p, null);
987 this.voc.setLevel(p, -1);
988
989 this.order.undo(x);
990
991 this.trail.pop();
992
993
994 IVec<Undoable> undos = this.voc.undos(p);
995 assert undos != null;
996 for (int size = undos.size(); size > 0; size--) {
997 undos.last().undo(p);
998 undos.pop();
999 }
1000 }
1001
1002
1003
1004
1005
1006
1007
1008 public void claBumpActivity(Constr confl) {
1009 confl.incActivity(this.claInc);
1010 if (confl.getActivity() > CLAUSE_RESCALE_BOUND) {
1011 claRescalActivity();
1012
1013
1014
1015 }
1016 }
1017
1018 public void varBumpActivity(int p) {
1019 this.order.updateVar(p);
1020 }
1021
1022 private void claRescalActivity() {
1023 for (int i = 0; i < this.learnts.size(); i++) {
1024 this.learnts.get(i).rescaleBy(CLAUSE_RESCALE_FACTOR);
1025 }
1026 this.claInc *= CLAUSE_RESCALE_FACTOR;
1027 }
1028
1029 private final IVec<Propagatable> watched = new Vec<Propagatable>();
1030
1031
1032
1033
1034 public final Constr propagate() {
1035 IVecInt ltrail = this.trail;
1036 SolverStats lstats = this.stats;
1037 IOrder lorder = this.order;
1038 SearchListener lslistener = this.slistener;
1039
1040
1041 while (this.qhead < ltrail.size()) {
1042 lstats.propagations++;
1043 int p = ltrail.get(this.qhead++);
1044 lslistener.propagating(toDimacs(p), null);
1045 lorder.assignLiteral(p);
1046 Constr confl = reduceClausesForFalsifiedLiteral(p);
1047 if (confl != null) {
1048 return confl;
1049 }
1050 }
1051 return null;
1052 }
1053
1054 private Constr reduceClausesForFalsifiedLiteral(int p) {
1055
1056
1057
1058 assert p > 1;
1059 IVec<Propagatable> lwatched = this.watched;
1060 lwatched.clear();
1061 this.voc.watches(p).moveTo(lwatched);
1062 final int size = lwatched.size();
1063 for (int i = 0; i < size; i++) {
1064 this.stats.inspects++;
1065
1066
1067
1068
1069
1070
1071
1072
1073 if (!lwatched.get(i).propagate(this, p)) {
1074
1075
1076
1077 final int sizew = lwatched.size();
1078 for (int j = i + 1; j < sizew; j++) {
1079 this.voc.watch(p, lwatched.get(j));
1080 }
1081 this.qhead = this.trail.size();
1082 return lwatched.get(i).toConstraint();
1083 }
1084 }
1085 return null;
1086 }
1087
1088 void record(Constr constr) {
1089 constr.assertConstraint(this);
1090 this.slistener.adding(toDimacs(constr.get(0)));
1091 if (constr.size() == 1) {
1092 this.stats.learnedliterals++;
1093 } else {
1094 this.learner.learns(constr);
1095 }
1096 }
1097
1098
1099
1100
1101 public boolean assume(int p) {
1102
1103 assert this.trail.size() == this.qhead;
1104 assert !this.trailLim.contains(this.trail.size());
1105 this.trailLim.push(this.trail.size());
1106 return enqueue(p);
1107 }
1108
1109
1110
1111
1112 private void cancel() {
1113
1114 int decisionvar = this.trail.unsafeGet(this.trailLim.last());
1115 this.slistener.backtracking(toDimacs(decisionvar));
1116 for (int c = this.trail.size() - this.trailLim.last(); c > 0; c--) {
1117 undoOne();
1118 }
1119 this.trailLim.pop();
1120 this.qhead = this.trail.size();
1121 }
1122
1123
1124
1125
1126 private void cancelLearntLiterals(int learnedLiteralsLimit) {
1127 this.learnedLiterals.clear();
1128
1129 while (this.trail.size() > learnedLiteralsLimit) {
1130 this.learnedLiterals.push(this.trail.last());
1131 undoOne();
1132 }
1133
1134
1135 }
1136
1137
1138
1139
1140
1141
1142 protected void cancelUntil(int level) {
1143 while (decisionLevel() > level) {
1144 cancel();
1145 }
1146 }
1147
1148 private final Pair analysisResult = new Pair();
1149
1150 private boolean[] userbooleanmodel;
1151
1152 private IVecInt unsatExplanationInTermsOfAssumptions;
1153
1154 Lbool search(IVecInt assumps) {
1155 assert this.rootLevel == decisionLevel();
1156 this.stats.starts++;
1157 int backjumpLevel;
1158
1159
1160 this.order.setVarDecay(1 / this.params.getVarDecay());
1161 this.claDecay = 1 / this.params.getClaDecay();
1162
1163 do {
1164 this.slistener.beginLoop();
1165
1166 Constr confl = propagate();
1167 assert this.trail.size() == this.qhead;
1168
1169 if (confl == null) {
1170
1171
1172
1173 if (decisionLevel() == 0 && this.isDBSimplificationAllowed) {
1174
1175
1176 this.stats.rootSimplifications++;
1177 boolean ret = simplifyDB();
1178 assert ret;
1179 }
1180
1181
1182 assert nAssigns() <= this.voc.realnVars();
1183 if (nAssigns() == this.voc.realnVars()) {
1184 modelFound();
1185 this.slistener
1186 .solutionFound((this.fullmodel != null) ? this.fullmodel
1187 : this.model, this);
1188 if (this.sharedConflict == null) {
1189 cancelUntil(this.rootLevel);
1190 return Lbool.TRUE;
1191 } else {
1192
1193 confl = this.sharedConflict;
1194 this.sharedConflict = null;
1195 }
1196 } else {
1197 if (this.restarter.shouldRestart()) {
1198
1199
1200 cancelUntil(this.rootLevel);
1201 return Lbool.UNDEFINED;
1202 }
1203 if (this.needToReduceDB) {
1204 reduceDB();
1205 this.needToReduceDB = false;
1206
1207 }
1208 if (this.sharedConflict == null) {
1209
1210 this.stats.decisions++;
1211 int p = this.order.select();
1212 if (p == ILits.UNDEFINED) {
1213 confl = preventTheSameDecisionsToBeMade();
1214 this.lastConflictMeansUnsat = false;
1215 } else {
1216 assert p > 1;
1217 this.slistener.assuming(toDimacs(p));
1218 boolean ret = assume(p);
1219 assert ret;
1220 }
1221 } else {
1222
1223 confl = this.sharedConflict;
1224 this.sharedConflict = null;
1225 }
1226 }
1227 }
1228 if (confl != null) {
1229
1230 this.stats.conflicts++;
1231 this.slistener.conflictFound(confl, decisionLevel(),
1232 this.trail.size());
1233 this.conflictCount.newConflict();
1234
1235 if (decisionLevel() == this.rootLevel) {
1236 if (this.lastConflictMeansUnsat) {
1237
1238 this.unsatExplanationInTermsOfAssumptions = analyzeFinalConflictInTermsOfAssumptions(
1239 confl, assumps, ILits.UNDEFINED);
1240 return Lbool.FALSE;
1241 }
1242 return Lbool.UNDEFINED;
1243 }
1244 int conflictTrailLevel = this.trail.size();
1245
1246 try {
1247 analyze(confl, this.analysisResult);
1248 } catch (TimeoutException e) {
1249 return Lbool.UNDEFINED;
1250 }
1251 assert this.analysisResult.backtrackLevel < decisionLevel();
1252 backjumpLevel = Math.max(this.analysisResult.backtrackLevel,
1253 this.rootLevel);
1254 this.slistener.backjump(backjumpLevel);
1255 cancelUntil(backjumpLevel);
1256 if (backjumpLevel == this.rootLevel) {
1257 this.restarter.onBackjumpToRootLevel();
1258 }
1259 assert decisionLevel() >= this.rootLevel
1260 && decisionLevel() >= this.analysisResult.backtrackLevel;
1261 if (this.analysisResult.reason == null) {
1262 return Lbool.FALSE;
1263 }
1264 record(this.analysisResult.reason);
1265 this.restarter.newLearnedClause(this.analysisResult.reason,
1266 conflictTrailLevel);
1267 this.analysisResult.reason = null;
1268 decayActivities();
1269 }
1270 } while (this.undertimeout);
1271 return Lbool.UNDEFINED;
1272 }
1273
1274 private Constr preventTheSameDecisionsToBeMade() {
1275 IVecInt clause = new VecInt(nVars());
1276 int p;
1277 for (int i = this.trail.size() - 1; i >= this.rootLevel; i--) {
1278 p = this.trail.get(i);
1279 if (this.voc.getReason(p) == null) {
1280 clause.push(p ^ 1);
1281 }
1282 }
1283 return this.dsfactory.createUnregisteredClause(clause);
1284 }
1285
1286 protected void analyzeAtRootLevel(Constr conflict) {
1287 }
1288
1289 private final IVecInt implied = new VecInt();
1290 private final IVecInt decisions = new VecInt();
1291
1292 private int[] fullmodel;
1293
1294
1295
1296
1297 void modelFound() {
1298 IVecInt tempmodel = new VecInt(nVars());
1299 this.userbooleanmodel = new boolean[realNumberOfVariables()];
1300 this.fullmodel = null;
1301 for (int i = 1; i <= nVars(); i++) {
1302 if (this.voc.belongsToPool(i)) {
1303 int p = this.voc.getFromPool(i);
1304 if (!this.voc.isUnassigned(p)) {
1305 tempmodel.push(this.voc.isSatisfied(p) ? i : -i);
1306 this.userbooleanmodel[i - 1] = this.voc.isSatisfied(p);
1307 if (this.voc.getReason(p) == null && voc.getLevel(p) > 0) {
1308 this.decisions.push(tempmodel.last());
1309 } else {
1310 this.implied.push(tempmodel.last());
1311 }
1312 }
1313 }
1314 }
1315 this.model = new int[tempmodel.size()];
1316 tempmodel.copyTo(this.model);
1317 if (realNumberOfVariables() > nVars()) {
1318 for (int i = nVars() + 1; i <= realNumberOfVariables(); i++) {
1319 if (this.voc.belongsToPool(i)) {
1320 int p = this.voc.getFromPool(i);
1321 if (!this.voc.isUnassigned(p)) {
1322 tempmodel.push(this.voc.isSatisfied(p) ? i : -i);
1323 this.userbooleanmodel[i - 1] = this.voc.isSatisfied(p);
1324 if (this.voc.getReason(p) == null) {
1325 this.decisions.push(tempmodel.last());
1326 } else {
1327 this.implied.push(tempmodel.last());
1328 }
1329 }
1330 }
1331 }
1332 this.fullmodel = new int[tempmodel.size()];
1333 tempmodel.moveTo(this.fullmodel);
1334 } else {
1335 this.fullmodel = this.model;
1336 }
1337 }
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348 private Constr forget(int var) {
1349 boolean satisfied = this.voc.isSatisfied(toInternal(var));
1350 this.voc.forgets(var);
1351 Constr confl;
1352 if (satisfied) {
1353 confl = reduceClausesForFalsifiedLiteral(LiteralsUtils
1354 .toInternal(-var));
1355 } else {
1356 confl = reduceClausesForFalsifiedLiteral(LiteralsUtils
1357 .toInternal(var));
1358 }
1359 return confl;
1360 }
1361
1362
1363
1364
1365
1366
1367
1368
1369 private boolean setAndPropagate(int p) {
1370 if (voc.isUnassigned(p)) {
1371 assert !trail.contains(p);
1372 assert !trail.contains(neg(p));
1373 return assume(p) && propagate() == null;
1374 }
1375 return voc.isSatisfied(p);
1376 }
1377
1378 private int[] prime;
1379
1380 public int[] primeImplicant() {
1381 assert this.qhead == this.trail.size() + this.learnedLiterals.size();
1382 if (this.learnedLiterals.size() > 0) {
1383 this.qhead = trail.size();
1384 }
1385 System.out.printf("%s implied: %d, decision: %d %n", getLogPrefix(),
1386 implied.size(), decisions.size());
1387 this.prime = new int[realNumberOfVariables() + 1];
1388 int p, d;
1389 for (int i = 0; i < this.prime.length; i++) {
1390 this.prime[i] = 0;
1391 }
1392 boolean noproblem;
1393 for (IteratorInt it = this.implied.iterator(); it.hasNext();) {
1394 d = it.next();
1395 p = toInternal(d);
1396 this.prime[Math.abs(d)] = d;
1397 noproblem = setAndPropagate(p);
1398 assert noproblem;
1399 }
1400 boolean canBeRemoved;
1401 int rightlevel;
1402 int removed = 0;
1403 int propagated = 0;
1404 int tested = 0;
1405 int l2propagation = 0;
1406
1407 for (int i = 0; i < this.decisions.size(); i++) {
1408 d = this.decisions.get(i);
1409 assert !this.voc.isFalsified(toInternal(d));
1410 if (this.voc.isSatisfied(toInternal(d))) {
1411
1412 this.prime[Math.abs(d)] = d;
1413 propagated++;
1414 } else if (setAndPropagate(toInternal(-d))) {
1415 canBeRemoved = true;
1416 tested++;
1417 rightlevel = currentDecisionLevel();
1418 for (int j = i + 1; j < this.decisions.size(); j++) {
1419 l2propagation++;
1420 if (!setAndPropagate(toInternal(this.decisions.get(j)))) {
1421 canBeRemoved = false;
1422 break;
1423 }
1424 }
1425 cancelUntil(rightlevel);
1426 if (canBeRemoved) {
1427
1428 forget(Math.abs(d));
1429 IConstr confl = propagate();
1430 assert confl == null;
1431 removed++;
1432 } else {
1433 this.prime[Math.abs(d)] = d;
1434 cancel();
1435 assert voc.isUnassigned(toInternal(d));
1436 noproblem = setAndPropagate(toInternal(d));
1437 assert noproblem;
1438 }
1439 } else {
1440
1441 this.prime[Math.abs(d)] = d;
1442 cancel();
1443 noproblem = setAndPropagate(toInternal(d));
1444 assert noproblem;
1445 }
1446 }
1447 cancelUntil(0);
1448 int[] implicant = new int[this.prime.length - removed - 1];
1449 int index = 0;
1450 for (int i : this.prime) {
1451 if (i != 0) {
1452 implicant[index++] = i;
1453 }
1454 }
1455 if (isVerbose()) {
1456 System.out.printf("%s prime implicant computation statistics%n",
1457 getLogPrefix());
1458 System.out
1459 .printf("%s implied: %d, decision: %d (removed %d, tested %d, propagated %d), l2 propagation:%d%n",
1460 getLogPrefix(), implied.size(), decisions.size(),
1461 removed, tested, propagated, l2propagation);
1462 }
1463 return implicant;
1464 }
1465
1466 public boolean primeImplicant(int p) {
1467 if (p == 0 || Math.abs(p) > realNumberOfVariables()) {
1468 throw new IllegalArgumentException(
1469 "Use a valid Dimacs var id as argument!");
1470 }
1471 if (this.prime == null) {
1472 throw new UnsupportedOperationException(
1473 "Call the primeImplicant method first!!!");
1474 }
1475 return this.prime[Math.abs(p)] == p;
1476 }
1477
1478 public boolean model(int var) {
1479 if (var <= 0 || var > realNumberOfVariables()) {
1480 throw new IllegalArgumentException(
1481 "Use a valid Dimacs var id as argument!");
1482 }
1483 if (this.userbooleanmodel == null) {
1484 throw new UnsupportedOperationException(
1485 "Call the solve method first!!!");
1486 }
1487 return this.userbooleanmodel[var - 1];
1488 }
1489
1490 public void clearLearntClauses() {
1491 for (Iterator<Constr> iterator = this.learnts.iterator(); iterator
1492 .hasNext();) {
1493 iterator.next().remove(this);
1494 }
1495 this.learnts.clear();
1496 this.learnedLiterals.clear();
1497 }
1498
1499 protected final void reduceDB() {
1500 this.stats.reduceddb++;
1501 this.slistener.cleaning();
1502 this.learnedConstraintsDeletionStrategy.reduce(this.learnts);
1503 System.gc();
1504 }
1505
1506
1507
1508
1509 protected void sortOnActivity() {
1510 this.learnts.sort(this.comparator);
1511 }
1512
1513
1514
1515
1516 protected void decayActivities() {
1517 this.order.varDecayActivity();
1518 claDecayActivity();
1519 }
1520
1521
1522
1523
1524 private void claDecayActivity() {
1525 this.claInc *= this.claDecay;
1526 }
1527
1528
1529
1530
1531 public boolean isSatisfiable() throws TimeoutException {
1532 return isSatisfiable(VecInt.EMPTY);
1533 }
1534
1535
1536
1537
1538 public boolean isSatisfiable(boolean global) throws TimeoutException {
1539 return isSatisfiable(VecInt.EMPTY, global);
1540 }
1541
1542 private double timebegin = 0;
1543
1544 private boolean needToReduceDB;
1545
1546 private ConflictTimerContainer conflictCount;
1547
1548 private transient Timer timer;
1549
1550 public boolean isSatisfiable(IVecInt assumps) throws TimeoutException {
1551 return isSatisfiable(assumps, false);
1552 }
1553
1554 public final LearnedConstraintsDeletionStrategy fixedSize(final int maxsize) {
1555 return new LearnedConstraintsDeletionStrategy() {
1556
1557 private static final long serialVersionUID = 1L;
1558 private final ConflictTimer aTimer = new ConflictTimerAdapter(
1559 maxsize) {
1560
1561 private static final long serialVersionUID = 1L;
1562
1563 @Override
1564 public void run() {
1565 Solver.this.needToReduceDB = true;
1566 }
1567 };
1568
1569 public void reduce(IVec<Constr> learnedConstrs) {
1570 int i, j, k;
1571 for (i = j = k = 0; i < Solver.this.learnts.size()
1572 && Solver.this.learnts.size() - k > maxsize; i++) {
1573 Constr c = Solver.this.learnts.get(i);
1574 if (c.locked() || c.size() == 2) {
1575 Solver.this.learnts
1576 .set(j++, Solver.this.learnts.get(i));
1577 } else {
1578 c.remove(Solver.this);
1579 k++;
1580 }
1581 }
1582 for (; i < Solver.this.learnts.size(); i++) {
1583 Solver.this.learnts.set(j++, Solver.this.learnts.get(i));
1584 }
1585 if (Solver.this.verbose) {
1586 Solver.this.out.log(getLogPrefix()
1587 + "cleaning " + (Solver.this.learnts.size() - j)
1588 + " clauses out of " + Solver.this.learnts.size());
1589
1590 }
1591 Solver.this.learnts.shrinkTo(j);
1592 }
1593
1594 public void onConflictAnalysis(Constr reason) {
1595
1596
1597 }
1598
1599 public void onClauseLearning(Constr outLearnt) {
1600
1601
1602 }
1603
1604 @Override
1605 public String toString() {
1606 return "Fixed size (" + maxsize
1607 + ") learned constraints deletion strategy";
1608 }
1609
1610 public void init() {
1611 }
1612
1613 public ConflictTimer getTimer() {
1614 return this.aTimer;
1615 }
1616
1617 public void onPropagation(Constr from) {
1618
1619
1620 }
1621 };
1622 }
1623
1624 private LearnedConstraintsDeletionStrategy activityBased(
1625 final ConflictTimer timer) {
1626 return new LearnedConstraintsDeletionStrategy() {
1627
1628 private static final long serialVersionUID = 1L;
1629
1630 private final ConflictTimer freeMem = timer;
1631
1632 public void reduce(IVec<Constr> learnedConstrs) {
1633 sortOnActivity();
1634 int i, j;
1635 for (i = j = 0; i < Solver.this.learnts.size() / 2; i++) {
1636 Constr c = Solver.this.learnts.get(i);
1637 if (c.locked() || c.size() == 2) {
1638 Solver.this.learnts
1639 .set(j++, Solver.this.learnts.get(i));
1640 } else {
1641 c.remove(Solver.this);
1642 }
1643 }
1644 for (; i < Solver.this.learnts.size(); i++) {
1645 Solver.this.learnts.set(j++, Solver.this.learnts.get(i));
1646 }
1647 if (Solver.this.verbose) {
1648 Solver.this.out.log(getLogPrefix()
1649 + "cleaning " + (Solver.this.learnts.size() - j)
1650 + " clauses out of " + Solver.this.learnts.size());
1651
1652 }
1653 Solver.this.learnts.shrinkTo(j);
1654 }
1655
1656 public ConflictTimer getTimer() {
1657 return this.freeMem;
1658 }
1659
1660 @Override
1661 public String toString() {
1662 return "Memory based learned constraints deletion strategy";
1663 }
1664
1665 public void init() {
1666
1667 }
1668
1669 public void onClauseLearning(Constr constr) {
1670
1671
1672 }
1673
1674 public void onConflictAnalysis(Constr reason) {
1675 if (reason.learnt()) {
1676 claBumpActivity(reason);
1677 }
1678 }
1679
1680 public void onPropagation(Constr from) {
1681
1682 }
1683 };
1684 }
1685
1686 private final ConflictTimer memoryTimer = new ConflictTimerAdapter(500) {
1687 private static final long serialVersionUID = 1L;
1688 final long memorybound = Runtime.getRuntime().freeMemory() / 10;
1689
1690 @Override
1691 public void run() {
1692 long freemem = Runtime.getRuntime().freeMemory();
1693
1694 if (freemem < this.memorybound) {
1695
1696 Solver.this.needToReduceDB = true;
1697 }
1698 }
1699 };
1700
1701
1702
1703
1704 public final LearnedConstraintsDeletionStrategy memory_based = activityBased(this.memoryTimer);
1705
1706 private class GlucoseLCDS implements LearnedConstraintsDeletionStrategy {
1707
1708 private static final long serialVersionUID = 1L;
1709 private int[] flags = new int[0];
1710 private int flag = 0;
1711
1712
1713 private final ConflictTimer clauseManagement;
1714
1715 GlucoseLCDS(ConflictTimer timer) {
1716 this.clauseManagement = timer;
1717 }
1718
1719 public void reduce(IVec<Constr> learnedConstrs) {
1720 sortOnActivity();
1721 int i, j;
1722 for (i = j = learnedConstrs.size() / 2; i < learnedConstrs.size(); i++) {
1723 Constr c = learnedConstrs.get(i);
1724 if (c.locked() || c.getActivity() <= 2.0) {
1725 learnedConstrs.set(j++, Solver.this.learnts.get(i));
1726 } else {
1727 c.remove(Solver.this);
1728 }
1729 }
1730 if (Solver.this.verbose) {
1731 Solver.this.out
1732 .log(getLogPrefix()
1733 + "cleaning " + (learnedConstrs.size() - j)
1734 + " clauses out of " + learnedConstrs.size() + " with flag " + this.flag + "/" + Solver.this.stats.conflicts);
1735
1736 }
1737 Solver.this.learnts.shrinkTo(j);
1738
1739 }
1740
1741 public ConflictTimer getTimer() {
1742 return this.clauseManagement;
1743 }
1744
1745 @Override
1746 public String toString() {
1747 return "Glucose learned constraints deletion strategy";
1748 }
1749
1750 public void init() {
1751 final int howmany = Solver.this.voc.nVars();
1752
1753 if (this.flags.length <= howmany) {
1754 this.flags = new int[howmany + 1];
1755 }
1756 this.flag = 0;
1757 this.clauseManagement.reset();
1758 }
1759
1760 public void onClauseLearning(Constr constr) {
1761 int nblevel = computeLBD(constr);
1762 constr.incActivity(nblevel);
1763 }
1764
1765 protected int computeLBD(Constr constr) {
1766 int nblevel = 1;
1767 this.flag++;
1768 int currentLevel;
1769 for (int i = 1; i < constr.size(); i++) {
1770 currentLevel = Solver.this.voc.getLevel(constr.get(i));
1771 if (this.flags[currentLevel] != this.flag) {
1772 this.flags[currentLevel] = this.flag;
1773 nblevel++;
1774 }
1775 }
1776 return nblevel;
1777 }
1778
1779 public void onConflictAnalysis(Constr reason) {
1780
1781 }
1782
1783 public void onPropagation(Constr from) {
1784
1785 }
1786 }
1787
1788 private class Glucose2LCDS extends GlucoseLCDS {
1789
1790
1791
1792
1793 private static final long serialVersionUID = 1L;
1794
1795 Glucose2LCDS(ConflictTimer timer) {
1796 super(timer);
1797 }
1798
1799 @Override
1800 public String toString() {
1801 return "Glucose 2 learned constraints deletion strategy";
1802 }
1803
1804 @Override
1805 public void onPropagation(Constr from) {
1806 if (from.getActivity() > 2.0) {
1807 int nblevel = computeLBD(from);
1808 if (nblevel < from.getActivity()) {
1809 Solver.this.stats.updateLBD++;
1810 from.setActivity(nblevel);
1811 }
1812 }
1813 }
1814
1815 }
1816
1817 private final ConflictTimer lbdTimer = new ConflictTimerAdapter(1000) {
1818 private static final long serialVersionUID = 1L;
1819 private int nbconflict = 0;
1820 private static final int MAX_CLAUSE = 5000;
1821 private static final int INC_CLAUSE = 1000;
1822 private int nextbound = MAX_CLAUSE;
1823
1824 @Override
1825 public void run() {
1826 this.nbconflict += bound();
1827 if (this.nbconflict >= this.nextbound) {
1828 this.nextbound += INC_CLAUSE;
1829
1830
1831
1832 this.nbconflict = 0;
1833 Solver.this.needToReduceDB = true;
1834 }
1835 }
1836
1837 @Override
1838 public void reset() {
1839 super.reset();
1840 this.nextbound = MAX_CLAUSE;
1841 if (this.nbconflict >= this.nextbound) {
1842 this.nbconflict = 0;
1843 Solver.this.needToReduceDB = true;
1844 }
1845 }
1846 };
1847
1848
1849
1850
1851 public final LearnedConstraintsDeletionStrategy glucose = new Glucose2LCDS(
1852 this.lbdTimer);
1853
1854 protected LearnedConstraintsDeletionStrategy learnedConstraintsDeletionStrategy = this.glucose;
1855
1856
1857
1858
1859
1860
1861
1862
1863 public void setLearnedConstraintsDeletionStrategy(
1864 LearnedConstraintsDeletionStrategy lcds) {
1865 if (this.conflictCount != null) {
1866 this.conflictCount.add(lcds.getTimer());
1867 assert this.learnedConstraintsDeletionStrategy != null;
1868 this.conflictCount.remove(this.learnedConstraintsDeletionStrategy
1869 .getTimer());
1870 }
1871 this.learnedConstraintsDeletionStrategy = lcds;
1872 }
1873
1874 private boolean lastConflictMeansUnsat;
1875
1876 public boolean isSatisfiable(IVecInt assumps, boolean global)
1877 throws TimeoutException {
1878 Lbool status = Lbool.UNDEFINED;
1879 boolean alreadylaunched = this.conflictCount != null;
1880 final int howmany = this.voc.nVars();
1881 if (this.mseen.length <= howmany) {
1882 this.mseen = new boolean[howmany + 1];
1883 }
1884 this.trail.ensure(howmany);
1885 this.trailLim.ensure(howmany);
1886 this.learnedLiterals.ensure(howmany);
1887 this.decisions.clear();
1888 this.implied.clear();
1889 this.slistener.init(this);
1890 this.slistener.start();
1891 this.model = null;
1892 this.userbooleanmodel = null;
1893 this.prime = null;
1894 this.unsatExplanationInTermsOfAssumptions = null;
1895 if (!alreadylaunched || !this.keepHot) {
1896 this.order.init();
1897 }
1898 this.learnedConstraintsDeletionStrategy.init();
1899 int learnedLiteralsLimit = this.trail.size();
1900
1901
1902 this.qhead = 0;
1903
1904
1905 for (int i = learnedLiteralsLimit - 1; i >= 0; i--) {
1906 int p = this.trail.get(i);
1907 IVec<Undoable> undos = this.voc.undos(p);
1908 assert undos != null;
1909 for (int size = undos.size(); size > 0; size--) {
1910 undos.last().undo(p);
1911 undos.pop();
1912 }
1913 }
1914
1915 for (IteratorInt iterator = this.learnedLiterals.iterator(); iterator
1916 .hasNext();) {
1917 enqueue(iterator.next());
1918 }
1919
1920
1921 Constr confl = propagate();
1922 if (confl != null) {
1923 analyzeAtRootLevel(confl);
1924 this.slistener.conflictFound(confl, 0, 0);
1925 this.slistener.end(Lbool.FALSE);
1926 cancelUntil(0);
1927 cancelLearntLiterals(learnedLiteralsLimit);
1928 return false;
1929 }
1930
1931
1932 for (IteratorInt iterator = assumps.iterator(); iterator.hasNext();) {
1933 int assump = iterator.next();
1934 int p = this.voc.getFromPool(assump);
1935 if (!this.voc.isSatisfied(p) && !assume(p)
1936 || (confl = propagate()) != null) {
1937 if (confl == null) {
1938 this.slistener.conflictFound(p);
1939 this.unsatExplanationInTermsOfAssumptions = analyzeFinalConflictInTermsOfAssumptions(
1940 null, assumps, p);
1941 this.unsatExplanationInTermsOfAssumptions.push(assump);
1942 } else {
1943 this.slistener.conflictFound(confl, decisionLevel(),
1944 this.trail.size());
1945 this.unsatExplanationInTermsOfAssumptions = analyzeFinalConflictInTermsOfAssumptions(
1946 confl, assumps, ILits.UNDEFINED);
1947 }
1948
1949 this.slistener.end(Lbool.FALSE);
1950 cancelUntil(0);
1951 cancelLearntLiterals(learnedLiteralsLimit);
1952 return false;
1953 }
1954 }
1955 this.rootLevel = decisionLevel();
1956
1957
1958 if (!alreadylaunched || !this.keepHot) {
1959 this.order.init();
1960 }
1961 this.learner.init();
1962
1963 if (!alreadylaunched) {
1964 this.conflictCount = new ConflictTimerContainer();
1965 this.conflictCount.add(this.restarter);
1966 this.conflictCount.add(this.learnedConstraintsDeletionStrategy
1967 .getTimer());
1968 }
1969 boolean firstTimeGlobal = false;
1970 if (this.timeBasedTimeout) {
1971 if (!global || this.timer == null) {
1972 firstTimeGlobal = true;
1973 this.undertimeout = true;
1974 TimerTask stopMe = new TimerTask() {
1975 @Override
1976 public void run() {
1977 Solver.this.undertimeout = false;
1978 }
1979 };
1980 this.timer = new Timer(true);
1981 this.timer.schedule(stopMe, this.timeout);
1982
1983 }
1984 } else {
1985 if (!global || !alreadylaunched) {
1986 firstTimeGlobal = true;
1987 this.undertimeout = true;
1988 ConflictTimer conflictTimeout = new ConflictTimerAdapter(
1989 (int) this.timeout) {
1990 private static final long serialVersionUID = 1L;
1991
1992 @Override
1993 public void run() {
1994 Solver.this.undertimeout = false;
1995 }
1996 };
1997 this.conflictCount.add(conflictTimeout);
1998 }
1999 }
2000 if (!global || firstTimeGlobal) {
2001 this.restarter.init(this.params, this.stats);
2002 this.timebegin = System.currentTimeMillis();
2003 }
2004 this.needToReduceDB = false;
2005
2006
2007 this.lastConflictMeansUnsat = true;
2008
2009 while (status == Lbool.UNDEFINED && this.undertimeout
2010 && this.lastConflictMeansUnsat) {
2011 status = search(assumps);
2012 if (status == Lbool.UNDEFINED) {
2013 this.restarter.onRestart();
2014 this.slistener.restarting();
2015 }
2016 }
2017
2018 cancelUntil(0);
2019 cancelLearntLiterals(learnedLiteralsLimit);
2020 if (!global && this.timeBasedTimeout && this.timer != null) {
2021 this.timer.cancel();
2022 this.timer = null;
2023 }
2024 this.slistener.end(status);
2025 if (!this.undertimeout) {
2026 String message = " Timeout (" + this.timeout
2027 + (this.timeBasedTimeout ? "s" : " conflicts")
2028 + ") exceeded";
2029 throw new TimeoutException(message);
2030 }
2031 if (status == Lbool.UNDEFINED && !this.lastConflictMeansUnsat) {
2032 throw new TimeoutException("Cannot decide the satisfiability");
2033 }
2034
2035
2036
2037 return model != null;
2038 }
2039
2040 public void printInfos(PrintWriter out) {
2041 printInfos(out, prefix);
2042 }
2043
2044 public void printInfos(PrintWriter out, String prefix) {
2045 out.print(prefix);
2046 out.println("constraints type ");
2047 long total = 0;
2048 for (Map.Entry<String, Counter> entry : this.constrTypes.entrySet()) {
2049 out.println(prefix + entry.getKey() + " => " + entry.getValue());
2050 total += entry.getValue().getValue();
2051 }
2052 out.print(prefix);
2053 out.print(total);
2054 out.println(" constraints processed.");
2055 }
2056
2057
2058
2059
2060 public void printLearntClausesInfos(PrintWriter out, String prefix) {
2061 Map<String, Counter> learntTypes = new HashMap<String, Counter>();
2062 for (Iterator<Constr> it = this.learnts.iterator(); it.hasNext();) {
2063 String type = it.next().getClass().getName();
2064 Counter count = learntTypes.get(type);
2065 if (count == null) {
2066 learntTypes.put(type, new Counter());
2067 } else {
2068 count.inc();
2069 }
2070 }
2071 out.print(prefix);
2072 out.println("learnt constraints type ");
2073 for (Map.Entry<String, Counter> entry : learntTypes.entrySet()) {
2074 out.println(prefix + entry.getKey() + " => " + entry.getValue());
2075 }
2076 }
2077
2078 public SolverStats getStats() {
2079 return this.stats;
2080 }
2081
2082
2083
2084
2085
2086
2087 protected void initStats(SolverStats myStats) {
2088 this.stats = myStats;
2089 }
2090
2091
2092
2093
2094
2095
2096 public IOrder getOrder() {
2097 return this.order;
2098 }
2099
2100
2101
2102
2103
2104
2105 public void setOrder(IOrder h) {
2106 this.order = h;
2107 this.order.setLits(this.voc);
2108 }
2109
2110 public ILits getVocabulary() {
2111 return this.voc;
2112 }
2113
2114 public void reset() {
2115 if (this.timer != null) {
2116 this.timer.cancel();
2117 this.timer = null;
2118 }
2119 this.trail.clear();
2120 this.trailLim.clear();
2121 this.qhead = 0;
2122 for (Iterator<Constr> iterator = this.constrs.iterator(); iterator
2123 .hasNext();) {
2124 iterator.next().remove(this);
2125 }
2126 this.constrs.clear();
2127 clearLearntClauses();
2128 this.voc.resetPool();
2129 this.dsfactory.reset();
2130 this.stats.reset();
2131 this.constrTypes.clear();
2132 }
2133
2134 public int nVars() {
2135 if (this.declaredMaxVarId == 0) {
2136 return this.voc.nVars();
2137 }
2138 return this.declaredMaxVarId;
2139 }
2140
2141
2142
2143
2144
2145
2146 protected IConstr addConstr(Constr constr) {
2147 if (constr == null) {
2148 Counter count = this.constrTypes
2149 .get("ignored satisfied constraints");
2150 if (count == null) {
2151 this.constrTypes.put("ignored satisfied constraints",
2152 new Counter());
2153 } else {
2154 count.inc();
2155 }
2156 } else {
2157 this.constrs.push(constr);
2158 String type = constr.getClass().getName();
2159 Counter count = this.constrTypes.get(type);
2160 if (count == null) {
2161 this.constrTypes.put(type, new Counter());
2162 } else {
2163 count.inc();
2164 }
2165 }
2166 return constr;
2167 }
2168
2169 public DataStructureFactory getDSFactory() {
2170 return this.dsfactory;
2171 }
2172
2173 public IVecInt getOutLearnt() {
2174 return this.moutLearnt;
2175 }
2176
2177
2178
2179
2180
2181
2182
2183
2184 public IConstr getIthConstr(int i) {
2185 return this.constrs.get(i);
2186 }
2187
2188
2189
2190
2191
2192
2193
2194 public void printStat(PrintStream out, String prefix) {
2195 printStat(new PrintWriter(out, true), prefix);
2196 }
2197
2198 public void printStat(PrintWriter out) {
2199 printStat(out, prefix);
2200 }
2201
2202 public void printStat(PrintWriter out, String prefix) {
2203 this.stats.printStat(out, prefix);
2204 double cputime = (System.currentTimeMillis() - this.timebegin) / 1000;
2205 out.println(prefix
2206 + "speed (assignments/second)\t: " + this.stats.propagations
2207 / cputime);
2208 this.order.printStat(out, prefix);
2209 printLearntClausesInfos(out, prefix);
2210 }
2211
2212
2213
2214
2215
2216
2217 public String toString(String prefix) {
2218 StringBuffer stb = new StringBuffer();
2219 Object[] objs = { this.dsfactory, this.learner, this.params,
2220 this.order, this.simplifier, this.restarter,
2221 this.learnedConstraintsDeletionStrategy };
2222 stb.append(prefix);
2223 stb.append("--- Begin Solver configuration ---");
2224 stb.append("\n");
2225 for (Object o : objs) {
2226 stb.append(prefix);
2227 stb.append(o.toString());
2228 stb.append("\n");
2229 }
2230 stb.append(prefix);
2231 stb.append("timeout=");
2232 if (this.timeBasedTimeout) {
2233 stb.append(this.timeout / 1000);
2234 stb.append("s\n");
2235 } else {
2236 stb.append(this.timeout);
2237 stb.append(" conflicts\n");
2238 }
2239 stb.append(prefix);
2240 stb.append("DB Simplification allowed=");
2241 stb.append(this.isDBSimplificationAllowed);
2242 stb.append("\n");
2243 stb.append(prefix);
2244 if (isSolverKeptHot()) {
2245 stb.append("Heuristics kept accross calls (keep the solver \"hot\")\n");
2246 stb.append(prefix);
2247 }
2248 stb.append("Listener: ");
2249 stb.append(slistener);
2250 stb.append("\n");
2251 stb.append(prefix);
2252 stb.append("--- End Solver configuration ---");
2253 return stb.toString();
2254 }
2255
2256
2257
2258
2259
2260
2261 @Override
2262 public String toString() {
2263 return toString("");
2264 }
2265
2266 public int getTimeout() {
2267 return (int) (this.timeBasedTimeout ? this.timeout / 1000
2268 : this.timeout);
2269 }
2270
2271
2272
2273
2274 public long getTimeoutMs() {
2275 if (!this.timeBasedTimeout) {
2276 throw new UnsupportedOperationException(
2277 "The timeout is given in number of conflicts!");
2278 }
2279 return this.timeout;
2280 }
2281
2282 public void setExpectedNumberOfClauses(int nb) {
2283 this.constrs.ensure(nb);
2284 }
2285
2286 public Map<String, Number> getStat() {
2287 return this.stats.toMap();
2288 }
2289
2290 public int[] findModel() throws TimeoutException {
2291 if (isSatisfiable()) {
2292 return model();
2293 }
2294
2295
2296 return null;
2297 }
2298
2299 public int[] findModel(IVecInt assumps) throws TimeoutException {
2300 if (isSatisfiable(assumps)) {
2301 return model();
2302 }
2303
2304
2305 return null;
2306 }
2307
2308 public boolean isDBSimplificationAllowed() {
2309 return this.isDBSimplificationAllowed;
2310 }
2311
2312 public void setDBSimplificationAllowed(boolean status) {
2313 this.isDBSimplificationAllowed = status;
2314 }
2315
2316
2317
2318
2319 public int nextFreeVarId(boolean reserve) {
2320 return this.voc.nextFreeVarId(reserve);
2321 }
2322
2323
2324
2325
2326 public IConstr addBlockingClause(IVecInt literals)
2327 throws ContradictionException {
2328 return addClause(literals);
2329 }
2330
2331
2332
2333
2334 public void unset(int p) {
2335
2336
2337 if (this.voc.isUnassigned(p) || this.trail.isEmpty()) {
2338 return;
2339 }
2340 int current = this.trail.last();
2341 while (current != p) {
2342 undoOne();
2343 if (this.trail.isEmpty()) {
2344 return;
2345 }
2346 current = this.trail.last();
2347 }
2348 undoOne();
2349 this.qhead = this.trail.size();
2350 }
2351
2352
2353
2354
2355 public void setLogPrefix(String prefix) {
2356 this.prefix = prefix;
2357 }
2358
2359
2360
2361
2362 public String getLogPrefix() {
2363 return this.prefix;
2364 }
2365
2366
2367
2368
2369 public IVecInt unsatExplanation() {
2370 IVecInt copy = new VecInt(
2371 this.unsatExplanationInTermsOfAssumptions.size());
2372 this.unsatExplanationInTermsOfAssumptions.copyTo(copy);
2373 return copy;
2374 }
2375
2376
2377
2378
2379 public int[] modelWithInternalVariables() {
2380 if (this.model == null) {
2381 throw new UnsupportedOperationException(
2382 "Call the solve method first!!!");
2383 }
2384 int[] nmodel;
2385 if (nVars() == realNumberOfVariables()) {
2386 nmodel = new int[this.model.length];
2387 System.arraycopy(this.model, 0, nmodel, 0, nmodel.length);
2388 } else {
2389 nmodel = new int[this.fullmodel.length];
2390 System.arraycopy(this.fullmodel, 0, nmodel, 0, nmodel.length);
2391 }
2392
2393 return nmodel;
2394 }
2395
2396
2397
2398
2399 public int realNumberOfVariables() {
2400 return this.voc.nVars();
2401 }
2402
2403
2404
2405
2406 public void stop() {
2407 expireTimeout();
2408 }
2409
2410 protected Constr sharedConflict;
2411
2412
2413
2414
2415 public void backtrack(int[] reason) {
2416 IVecInt clause = new VecInt(reason.length);
2417 for (int d : reason) {
2418 clause.push(LiteralsUtils.toInternal(d));
2419 }
2420 this.sharedConflict = this.dsfactory.createUnregisteredClause(clause);
2421 learn(this.sharedConflict);
2422 }
2423
2424
2425
2426
2427 public Lbool truthValue(int literal) {
2428 int p = LiteralsUtils.toInternal(literal);
2429 if (this.voc.isFalsified(p)) {
2430 return Lbool.FALSE;
2431 }
2432 if (this.voc.isSatisfied(p)) {
2433 return Lbool.TRUE;
2434 }
2435 return Lbool.UNDEFINED;
2436 }
2437
2438
2439
2440
2441 public int currentDecisionLevel() {
2442 return decisionLevel();
2443 }
2444
2445
2446
2447
2448 public int[] getLiteralsPropagatedAt(int decisionLevel) {
2449 throw new UnsupportedOperationException("Not implemented yet!");
2450 }
2451
2452
2453
2454
2455 public void suggestNextLiteralToBranchOn(int l) {
2456 throw new UnsupportedOperationException("Not implemented yet!");
2457 }
2458
2459 protected boolean isNeedToReduceDB() {
2460 return this.needToReduceDB;
2461 }
2462
2463 public void setNeedToReduceDB(boolean needToReduceDB) {
2464 this.needToReduceDB = needToReduceDB;
2465 }
2466
2467 public void setLogger(ILogAble out) {
2468 this.out = out;
2469 }
2470
2471 public ILogAble getLogger() {
2472 return this.out;
2473 }
2474
2475 public double[] getVariableHeuristics() {
2476 return this.order.getVariableHeuristics();
2477 }
2478
2479 public IVec<Constr> getLearnedConstraints() {
2480 return this.learnts;
2481 }
2482
2483
2484
2485
2486 public void setLearnedConstraintsDeletionStrategy(ConflictTimer timer,
2487 LearnedConstraintsEvaluationType evaluation) {
2488 if (this.conflictCount != null) {
2489 this.conflictCount.add(timer);
2490 this.conflictCount.remove(this.learnedConstraintsDeletionStrategy
2491 .getTimer());
2492 }
2493 switch (evaluation) {
2494 case ACTIVITY:
2495 this.learnedConstraintsDeletionStrategy = activityBased(timer);
2496 break;
2497 case LBD:
2498 this.learnedConstraintsDeletionStrategy = new GlucoseLCDS(timer);
2499 break;
2500 case LBD2:
2501 this.learnedConstraintsDeletionStrategy = new Glucose2LCDS(timer);
2502 break;
2503 }
2504 if (this.conflictCount != null) {
2505 this.learnedConstraintsDeletionStrategy.init();
2506 }
2507 }
2508
2509
2510
2511
2512 public void setLearnedConstraintsDeletionStrategy(
2513 LearnedConstraintsEvaluationType evaluation) {
2514 ConflictTimer aTimer = this.learnedConstraintsDeletionStrategy
2515 .getTimer();
2516 switch (evaluation) {
2517 case ACTIVITY:
2518 this.learnedConstraintsDeletionStrategy = activityBased(aTimer);
2519 break;
2520 case LBD:
2521 this.learnedConstraintsDeletionStrategy = new GlucoseLCDS(aTimer);
2522 break;
2523 case LBD2:
2524 this.learnedConstraintsDeletionStrategy = new Glucose2LCDS(aTimer);
2525 break;
2526 }
2527 if (this.conflictCount != null) {
2528 this.learnedConstraintsDeletionStrategy.init();
2529 }
2530 }
2531
2532 public boolean isSolverKeptHot() {
2533 return this.keepHot;
2534 }
2535
2536 public void setKeepSolverHot(boolean keepHot) {
2537 this.keepHot = keepHot;
2538 }
2539
2540 public IConstr addClauseOnTheFly(int[] literals) {
2541 IVecInt clause = new VecInt(literals.length);
2542 for (int d : literals) {
2543 clause.push(LiteralsUtils.toInternal(d));
2544 }
2545 this.sharedConflict = this.dsfactory.createUnregisteredClause(clause);
2546 this.sharedConflict.register();
2547 addConstr(this.sharedConflict);
2548 IVecInt reason = new VecInt();
2549 this.sharedConflict.calcReasonOnTheFly(ILits.UNDEFINED, trail, reason);
2550 while (!trail.isEmpty() && !reason.contains(trail.last())) {
2551 undoOne();
2552 if (!trailLim.isEmpty() && trailLim.last() == trail.size()) {
2553 trailLim.pop();
2554 }
2555 }
2556 return this.sharedConflict;
2557 }
2558
2559 public ISolver getSolvingEngine() {
2560 return this;
2561 }
2562
2563
2564
2565
2566
2567 public IConstr addAtMostOnTheFly(int[] literals, int degree) {
2568 IVecInt clause = new VecInt(literals.length);
2569 for (int d : literals) {
2570 clause.push(LiteralsUtils.toInternal(-d));
2571 }
2572 IVecInt copy = new VecInt(clause.size());
2573 clause.copyTo(copy);
2574 this.sharedConflict = this.dsfactory
2575 .createUnregisteredCardinalityConstraint(copy, literals.length
2576 - degree);
2577 this.sharedConflict.register();
2578 addConstr(this.sharedConflict);
2579
2580
2581 IVecInt reason = new VecInt();
2582 this.sharedConflict.calcReasonOnTheFly(ILits.UNDEFINED, trail, reason);
2583 while (!trail.isEmpty() && !reason.contains(trail.last())) {
2584 undoOne();
2585 if (!trailLim.isEmpty() && trailLim.last() == trail.size()) {
2586 trailLim.pop();
2587 }
2588 }
2589 return this.sharedConflict;
2590 }
2591 }