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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50 package org.sat4j.minisat.core;
51
52 import static org.sat4j.core.LiteralsUtils.toDimacs;
53 import static org.sat4j.core.LiteralsUtils.var;
54
55 import java.io.PrintStream;
56 import java.io.PrintWriter;
57 import java.io.Serializable;
58 import java.lang.reflect.Field;
59 import java.util.Comparator;
60 import java.util.HashMap;
61 import java.util.Iterator;
62 import java.util.Map;
63 import java.util.Timer;
64 import java.util.TimerTask;
65
66 import org.sat4j.core.Vec;
67 import org.sat4j.core.VecInt;
68 import org.sat4j.specs.ContradictionException;
69 import org.sat4j.specs.IConstr;
70 import org.sat4j.specs.ISolver;
71 import org.sat4j.specs.IVec;
72 import org.sat4j.specs.IVecInt;
73 import org.sat4j.specs.IteratorInt;
74 import org.sat4j.specs.Lbool;
75 import org.sat4j.specs.SearchListener;
76 import org.sat4j.specs.TimeoutException;
77
78
79
80
81
82
83
84 public class Solver<D extends DataStructureFactory> implements ISolver,
85 UnitPropagationListener, ActivityListener, Learner {
86
87 private static final long serialVersionUID = 1L;
88
89 private static final double CLAUSE_RESCALE_FACTOR = 1e-20;
90
91 private static final double CLAUSE_RESCALE_BOUND = 1 / CLAUSE_RESCALE_FACTOR;
92
93
94
95
96 private final IVec<Constr> constrs = new Vec<Constr>();
97
98
99
100
101 private final IVec<Constr> learnts = new Vec<Constr>();
102
103
104
105
106 private double claInc = 1.0;
107
108
109
110
111 private double claDecay = 1.0;
112
113
114
115
116
117 private int qhead = 0;
118
119
120
121
122
123
124 protected final IVecInt trail = new VecInt();
125
126
127
128
129
130
131 protected final IVecInt trailLim = new VecInt();
132
133
134
135
136
137
138 protected int rootLevel;
139
140 private int[] model = null;
141
142 protected ILits voc;
143
144 private IOrder order;
145
146 private final ActivityComparator comparator = new ActivityComparator();
147
148 private SolverStats stats = new SolverStats();
149
150 private LearningStrategy<D> learner;
151
152 protected final AssertingClauseGenerator analyzer;
153
154 private volatile boolean undertimeout;
155
156 private long timeout = Integer.MAX_VALUE;
157
158 private boolean timeBasedTimeout = true;
159
160 protected D dsfactory;
161
162 private SearchParams params;
163
164 private final IVecInt __dimacs_out = new VecInt();
165
166 private SearchListener slistener = new VoidTracing();
167
168 private RestartStrategy restarter;
169
170 private final Map<String, Counter> constrTypes = new HashMap<String, Counter>();
171
172 private boolean isDBSimplificationAllowed = false;
173
174 private final IVecInt learnedLiterals = new VecInt();
175
176 private boolean verbose = true;
177
178 private String prefix = "c ";
179
180 protected IVecInt dimacs2internal(IVecInt in) {
181 __dimacs_out.clear();
182 __dimacs_out.ensure(in.size());
183 for (int i = 0; i < in.size(); i++) {
184 assert (in.get(i) != 0);
185 __dimacs_out.unsafePush(voc.getFromPool(in.get(i)));
186 }
187 return __dimacs_out;
188 }
189
190
191
192
193
194
195
196
197
198
199 public Solver(AssertingClauseGenerator acg, LearningStrategy<D> learner,
200 D dsf, IOrder order, RestartStrategy restarter) {
201 this(acg, learner, dsf, new SearchParams(), order, restarter);
202 }
203
204 public Solver(AssertingClauseGenerator acg, LearningStrategy<D> learner,
205 D dsf, SearchParams params, IOrder order, RestartStrategy restarter) {
206 analyzer = acg;
207 this.learner = learner;
208 this.order = order;
209 this.params = params;
210 setDataStructureFactory(dsf);
211 this.restarter = restarter;
212 }
213
214
215
216
217
218
219
220
221 public final void setDataStructureFactory(D dsf) {
222 dsfactory = dsf;
223 dsfactory.setUnitPropagationListener(this);
224 dsfactory.setLearner(this);
225 voc = dsf.getVocabulary();
226 order.setLits(voc);
227 }
228
229
230
231
232 public boolean isVerbose() {
233 return verbose;
234 }
235
236
237
238
239
240 public void setVerbose(boolean value) {
241 verbose = value;
242 }
243
244
245
246
247 public void setSearchListener(SearchListener sl) {
248 slistener = sl;
249 }
250
251
252
253
254 public SearchListener getSearchListener() {
255 return slistener;
256 }
257
258
259
260
261 public void setLearner(LearningStrategy<D> learner) {
262 this.learner = learner;
263 }
264
265 public void setTimeout(int t) {
266 timeout = t * 1000L;
267 timeBasedTimeout = true;
268 }
269
270 public void setTimeoutMs(long t) {
271 timeout = t;
272 timeBasedTimeout = true;
273 }
274
275 public void setTimeoutOnConflicts(int count) {
276 timeout = count;
277 timeBasedTimeout = false;
278 }
279
280 public void setSearchParams(SearchParams sp) {
281 params = sp;
282 }
283
284 public void setRestartStrategy(RestartStrategy restarter) {
285 this.restarter = restarter;
286 }
287
288 public void expireTimeout() {
289 undertimeout = false;
290 }
291
292 protected int nAssigns() {
293 return trail.size();
294 }
295
296 public int nConstraints() {
297 return constrs.size() + trail.size();
298 }
299
300 public void learn(Constr c) {
301 learnts.push(c);
302 c.setLearnt();
303 c.register();
304 stats.learnedclauses++;
305 switch (c.size()) {
306 case 2:
307 stats.learnedbinaryclauses++;
308 break;
309 case 3:
310 stats.learnedternaryclauses++;
311 break;
312 default:
313
314 }
315 }
316
317 public final int decisionLevel() {
318 return trailLim.size();
319 }
320
321 @Deprecated
322 public int newVar() {
323 int index = voc.nVars() + 1;
324 voc.ensurePool(index);
325 return index;
326 }
327
328 public int newVar(int howmany) {
329 voc.ensurePool(howmany);
330 return voc.nVars();
331 }
332
333 public IConstr addClause(IVecInt literals) throws ContradictionException {
334 IVecInt vlits = dimacs2internal(literals);
335 return addConstr(dsfactory.createClause(vlits));
336 }
337
338 public boolean removeConstr(IConstr co) {
339 if (co == null) {
340 throw new IllegalArgumentException(
341 "Reference to the constraint to remove needed!");
342 }
343 Constr c = (Constr) co;
344 c.remove(this);
345 constrs.remove(c);
346 clearLearntClauses();
347 String type = c.getClass().getName();
348 constrTypes.get(type).dec();
349 return true;
350 }
351
352
353
354
355 public boolean removeSubsumedConstr(IConstr co) {
356 if (co == null) {
357 throw new IllegalArgumentException(
358 "Reference to the constraint to remove needed!");
359 }
360 if (constrs.last() != co) {
361 throw new IllegalArgumentException(
362 "Can only remove latest added constraint!!!");
363 }
364 Constr c = (Constr) co;
365 c.remove(this);
366 constrs.pop();
367 String type = c.getClass().getName();
368 constrTypes.get(type).dec();
369 return true;
370 }
371
372 public void addAllClauses(IVec<IVecInt> clauses)
373 throws ContradictionException {
374 for (Iterator<IVecInt> iterator = clauses.iterator(); iterator
375 .hasNext();) {
376 addClause(iterator.next());
377 }
378 }
379
380 public IConstr addAtMost(IVecInt literals, int degree)
381 throws ContradictionException {
382 int n = literals.size();
383 IVecInt opliterals = new VecInt(n);
384 for (IteratorInt iterator = literals.iterator(); iterator.hasNext();) {
385 opliterals.push(-iterator.next());
386 }
387 return addAtLeast(opliterals, n - degree);
388 }
389
390 public IConstr addAtLeast(IVecInt literals, int degree)
391 throws ContradictionException {
392 IVecInt vlits = dimacs2internal(literals);
393 return addConstr(dsfactory.createCardinalityConstraint(vlits, degree));
394 }
395
396 @SuppressWarnings("unchecked")
397 public boolean simplifyDB() {
398
399
400 IVec<Constr>[] cs = new IVec[] { constrs, learnts };
401 for (int type = 0; type < 2; type++) {
402 int j = 0;
403 for (int i = 0; i < cs[type].size(); i++) {
404 if (cs[type].get(i).simplify()) {
405
406 cs[type].get(i).remove(this);
407 } else {
408 cs[type].moveTo(j++, i);
409 }
410 }
411 cs[type].shrinkTo(j);
412 }
413 return true;
414 }
415
416
417
418
419
420
421 public int[] model() {
422 if (model == null) {
423 throw new UnsupportedOperationException(
424 "Call the solve method first!!!");
425 }
426 int[] nmodel = new int[model.length];
427 System.arraycopy(model, 0, nmodel, 0, model.length);
428 return nmodel;
429 }
430
431
432
433
434
435
436
437
438 public boolean enqueue(int p) {
439 return enqueue(p, null);
440 }
441
442
443
444
445
446
447
448
449
450
451
452 public boolean enqueue(int p, Constr from) {
453 assert p > 1;
454 if (voc.isSatisfied(p)) {
455
456 return true;
457 }
458 if (voc.isFalsified(p)) {
459
460 return false;
461 }
462
463 voc.satisfies(p);
464 voc.setLevel(p, decisionLevel());
465 voc.setReason(p, from);
466 trail.push(p);
467 return true;
468 }
469
470 private boolean[] mseen = new boolean[0];
471
472 private final IVecInt mpreason = new VecInt();
473
474 private final IVecInt moutLearnt = new VecInt();
475
476 public void analyze(Constr confl, Pair results) {
477 assert confl != null;
478
479 final boolean[] seen = mseen;
480 final IVecInt outLearnt = moutLearnt;
481 final IVecInt preason = mpreason;
482
483 outLearnt.clear();
484 assert outLearnt.size() == 0;
485 for (int i = 0; i < seen.length; i++) {
486 seen[i] = false;
487 }
488
489 analyzer.initAnalyze();
490 int p = ILits.UNDEFINED;
491
492 outLearnt.push(ILits.UNDEFINED);
493
494 int outBtlevel = 0;
495
496 do {
497 preason.clear();
498 assert confl != null;
499 confl.calcReason(p, preason);
500 learnedConstraintsDeletionStrategy.onConflictAnalysis(confl);
501
502 for (int j = 0; j < preason.size(); j++) {
503 int q = preason.get(j);
504 order.updateVar(q);
505 if (!seen[q >> 1]) {
506 seen[q >> 1] = true;
507 if (voc.getLevel(q) == decisionLevel()) {
508 analyzer.onCurrentDecisionLevelLiteral(q);
509 } else if (voc.getLevel(q) > 0) {
510
511
512 outLearnt.push(q ^ 1);
513 outBtlevel = Math.max(outBtlevel, voc.getLevel(q));
514 }
515 }
516 }
517
518
519 do {
520 p = trail.last();
521 confl = voc.getReason(p);
522 undoOne();
523 } while (!seen[p >> 1]);
524
525
526 } while (analyzer.clauseNonAssertive(confl));
527
528 outLearnt.set(0, p ^ 1);
529 simplifier.simplify(outLearnt);
530
531 Constr c = dsfactory.createUnregisteredClause(outLearnt);
532 slistener.learn(c);
533 learnedConstraintsDeletionStrategy.onConflict(c);
534 results.reason = c;
535
536 assert outBtlevel > -1;
537 results.backtrackLevel = outBtlevel;
538 }
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553 public IVecInt analyzeFinalConflictInTermsOfAssumptions(Constr confl,
554 IVecInt assumps, int conflictingLiteral) {
555 if (assumps.size() == 0) {
556 return null;
557 }
558 final boolean[] seen = mseen;
559 final IVecInt outLearnt = moutLearnt;
560 final IVecInt preason = mpreason;
561
562 outLearnt.clear();
563 assert outLearnt.size() == 0;
564 for (int i = 0; i < seen.length; i++) {
565 seen[i] = false;
566 }
567
568 if (confl == null) {
569 seen[conflictingLiteral >> 1] = true;
570 }
571
572 int p = ILits.UNDEFINED;
573 while (confl == null) {
574 p = trail.last();
575 confl = voc.getReason(p);
576 undoOne();
577 if (trail.size() <= trailLim.last()) {
578 trailLim.pop();
579 }
580 }
581 do {
582
583 preason.clear();
584 confl.calcReason(p, preason);
585
586 for (int j = 0; j < preason.size(); j++) {
587 int q = preason.get(j);
588 if (!seen[q >> 1]) {
589 seen[q >> 1] = true;
590 if (voc.getReason(q) == null && voc.getLevel(q) > 0) {
591 assert assumps.contains(toDimacs(q));
592 outLearnt.push(toDimacs(q));
593 }
594 }
595 }
596
597
598 do {
599 p = trail.last();
600 confl = voc.getReason(p);
601 undoOne();
602 if (decisionLevel() > 0 && trail.size() <= trailLim.last()) {
603 trailLim.pop();
604 }
605 } while (trail.size() > 0 && decisionLevel() > 0
606 && (!seen[p >> 1] || confl == null));
607 } while (decisionLevel() > 0);
608 return outLearnt;
609 }
610
611 interface ISimplifier extends Serializable {
612 void simplify(IVecInt outLearnt);
613 }
614
615 public static final ISimplifier NO_SIMPLIFICATION = new ISimplifier() {
616
617
618
619 private static final long serialVersionUID = 1L;
620
621 public void simplify(IVecInt outLearnt) {
622 }
623
624 @Override
625 public String toString() {
626 return "No reason simplification";
627 }
628 };
629
630 public final ISimplifier SIMPLE_SIMPLIFICATION = new ISimplifier() {
631
632
633
634 private static final long serialVersionUID = 1L;
635
636 public void simplify(IVecInt conflictToReduce) {
637 simpleSimplification(conflictToReduce);
638 }
639
640 @Override
641 public String toString() {
642 return "Simple reason simplification";
643 }
644 };
645
646 public final ISimplifier EXPENSIVE_SIMPLIFICATION = new ISimplifier() {
647
648
649
650
651 private static final long serialVersionUID = 1L;
652
653 public void simplify(IVecInt conflictToReduce) {
654 expensiveSimplification(conflictToReduce);
655 }
656
657 @Override
658 public String toString() {
659 return "Expensive reason simplification";
660 }
661 };
662
663 private ISimplifier simplifier = NO_SIMPLIFICATION;
664
665
666
667
668
669
670
671
672
673
674 public void setSimplifier(String simp) {
675 Field f;
676 try {
677 f = Solver.class.getDeclaredField(simp);
678 simplifier = (ISimplifier) f.get(this);
679 } catch (Exception e) {
680 e.printStackTrace();
681 simplifier = NO_SIMPLIFICATION;
682 }
683 }
684
685
686
687
688
689
690
691
692
693
694 public void setSimplifier(ISimplifier simp) {
695 simplifier = simp;
696 }
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720 private void simpleSimplification(IVecInt conflictToReduce) {
721 int i, j;
722 final boolean[] seen = mseen;
723 for (i = j = 1; i < conflictToReduce.size(); i++) {
724 IConstr r = voc.getReason(conflictToReduce.get(i));
725 if (r == null) {
726 conflictToReduce.moveTo(j++, i);
727 } else {
728 for (int k = 0; k < r.size(); k++)
729 if (voc.isFalsified(r.get(k)) && !seen[r.get(k) >> 1]
730 && (voc.getLevel(r.get(k)) != 0)) {
731 conflictToReduce.moveTo(j++, i);
732 break;
733 }
734 }
735 }
736 conflictToReduce.shrink(i - j);
737 stats.reducedliterals += (i - j);
738 }
739
740 private final IVecInt analyzetoclear = new VecInt();
741
742 private final IVecInt analyzestack = new VecInt();
743
744
745 private void expensiveSimplification(IVecInt conflictToReduce) {
746
747
748 int i, j;
749
750 analyzetoclear.clear();
751 conflictToReduce.copyTo(analyzetoclear);
752 for (i = 1, j = 1; i < conflictToReduce.size(); i++)
753 if (voc.getReason(conflictToReduce.get(i)) == null
754 || !analyzeRemovable(conflictToReduce.get(i)))
755 conflictToReduce.moveTo(j++, i);
756 conflictToReduce.shrink(i - j);
757 stats.reducedliterals += (i - j);
758 }
759
760
761
762
763 private boolean analyzeRemovable(int p) {
764 assert voc.getReason(p) != null;
765 analyzestack.clear();
766 analyzestack.push(p);
767 final boolean[] seen = mseen;
768 int top = analyzetoclear.size();
769 while (analyzestack.size() > 0) {
770 int q = analyzestack.last();
771 assert voc.getReason(q) != null;
772 Constr c = voc.getReason(q);
773 analyzestack.pop();
774 for (int i = 0; i < c.size(); i++) {
775 int l = c.get(i);
776 if (voc.isFalsified(l) && !seen[var(l)] && voc.getLevel(l) != 0) {
777 if (voc.getReason(l) == null) {
778 for (int j = top; j < analyzetoclear.size(); j++)
779 seen[analyzetoclear.get(j) >> 1] = false;
780 analyzetoclear.shrink(analyzetoclear.size() - top);
781 return false;
782 }
783 seen[l >> 1] = true;
784 analyzestack.push(l);
785 analyzetoclear.push(l);
786 }
787 }
788 }
789
790 return true;
791 }
792
793
794
795
796
797
798 protected void undoOne() {
799
800 int p = trail.last();
801 assert p > 1;
802 assert voc.getLevel(p) >= 0;
803 int x = p >> 1;
804
805 voc.unassign(p);
806 voc.setReason(p, null);
807 voc.setLevel(p, -1);
808
809 order.undo(x);
810
811 trail.pop();
812
813
814
815 IVec<Undoable> undos = voc.undos(p);
816 assert undos != null;
817 while (undos.size() > 0) {
818 undos.last().undo(p);
819 undos.pop();
820 }
821 }
822
823
824
825
826
827
828
829 public void claBumpActivity(Constr confl) {
830 confl.incActivity(claInc);
831 if (confl.getActivity() > CLAUSE_RESCALE_BOUND)
832 claRescalActivity();
833
834
835
836 }
837
838 public void varBumpActivity(int p) {
839 order.updateVar(p);
840 }
841
842 private void claRescalActivity() {
843 for (int i = 0; i < learnts.size(); i++) {
844 learnts.get(i).rescaleBy(CLAUSE_RESCALE_FACTOR);
845 }
846 claInc *= CLAUSE_RESCALE_FACTOR;
847 }
848
849
850
851
852 public Constr propagate() {
853 while (qhead < trail.size()) {
854 stats.propagations++;
855 int p = trail.get(qhead++);
856 slistener.propagating(toDimacs(p), null);
857 order.assignLiteral(p);
858
859
860
861 assert p > 1;
862 IVec<Propagatable> watched = dsfactory.getWatchesFor(p);
863
864 final int size = watched.size();
865 for (int i = 0; i < size; i++) {
866 stats.inspects++;
867 if (!watched.get(i).propagate(this, p)) {
868
869
870
871 dsfactory.conflictDetectedInWatchesFor(p, i);
872 qhead = trail.size();
873
874 return (Constr) watched.get(i);
875 }
876 }
877 }
878 return null;
879 }
880
881 void record(Constr constr) {
882 constr.assertConstraint(this);
883 slistener.adding(toDimacs(constr.get(0)));
884 if (constr.size() == 1) {
885 stats.learnedliterals++;
886 } else {
887 learner.learns(constr);
888 }
889 }
890
891
892
893
894 public boolean assume(int p) {
895
896 assert trail.size() == qhead;
897 trailLim.push(trail.size());
898 return enqueue(p);
899 }
900
901
902
903
904 private void cancel() {
905
906 int decisionvar = trail.unsafeGet(trailLim.last());
907 slistener.backtracking(toDimacs(decisionvar));
908 for (int c = trail.size() - trailLim.last(); c > 0; c--) {
909 undoOne();
910 }
911 trailLim.pop();
912 }
913
914
915
916
917 private void cancelLearntLiterals(int learnedLiteralsLimit) {
918 learnedLiterals.clear();
919
920 while (trail.size() > learnedLiteralsLimit) {
921 learnedLiterals.push(trail.last());
922 undoOne();
923 }
924 qhead = trail.size();
925
926 }
927
928
929
930
931
932
933 protected void cancelUntil(int level) {
934 while (decisionLevel() > level) {
935 cancel();
936 }
937 qhead = trail.size();
938 }
939
940 private final Pair analysisResult = new Pair();
941
942 private boolean[] fullmodel;
943
944 private IVecInt unsatExplanationInTermsOfAssumptions;
945
946 Lbool search(long nofConflicts, IVecInt assumps) {
947 assert rootLevel == decisionLevel();
948 stats.starts++;
949 int conflictC = 0;
950 int backjumpLevel;
951
952
953 order.setVarDecay(1 / params.getVarDecay());
954 claDecay = 1 / params.getClaDecay();
955
956 do {
957 slistener.beginLoop();
958
959 Constr confl = propagate();
960 assert trail.size() == qhead;
961
962 if (confl == null) {
963
964
965
966 if (decisionLevel() == 0 && isDBSimplificationAllowed) {
967
968
969 stats.rootSimplifications++;
970 boolean ret = simplifyDB();
971 assert ret;
972 }
973
974
975 assert nAssigns() <= voc.realnVars();
976 if (nAssigns() == voc.realnVars()) {
977 slistener.solutionFound();
978 modelFound();
979 return Lbool.TRUE;
980 }
981 if (conflictC >= nofConflicts) {
982
983
984 cancelUntil(rootLevel);
985 return Lbool.UNDEFINED;
986 }
987 if (needToReduceDB) {
988 reduceDB();
989 needToReduceDB = false;
990
991 }
992
993 stats.decisions++;
994 int p = order.select();
995 assert p > 1;
996 slistener.assuming(toDimacs(p));
997 boolean ret = assume(p);
998 assert ret;
999 } else {
1000
1001 stats.conflicts++;
1002 conflictC++;
1003 slistener.conflictFound(confl, decisionLevel(), trail.size());
1004 conflictCount.newConflict();
1005
1006 if (decisionLevel() == rootLevel) {
1007
1008 unsatExplanationInTermsOfAssumptions = analyzeFinalConflictInTermsOfAssumptions(
1009 confl, assumps, ILits.UNDEFINED);
1010 return Lbool.FALSE;
1011 }
1012
1013 analyze(confl, analysisResult);
1014 assert analysisResult.backtrackLevel < decisionLevel();
1015 backjumpLevel = Math.max(analysisResult.backtrackLevel,
1016 rootLevel);
1017 slistener.backjump(backjumpLevel);
1018 cancelUntil(backjumpLevel);
1019 if (backjumpLevel == rootLevel) {
1020 conflictC = 0;
1021 }
1022 assert (decisionLevel() >= rootLevel)
1023 && (decisionLevel() >= analysisResult.backtrackLevel);
1024 if (analysisResult.reason == null) {
1025 return Lbool.FALSE;
1026 }
1027 record(analysisResult.reason);
1028 analysisResult.reason = null;
1029 decayActivities();
1030 }
1031 } while (undertimeout);
1032 return Lbool.UNDEFINED;
1033 }
1034
1035 protected void analyzeAtRootLevel(Constr conflict) {
1036 }
1037
1038
1039
1040
1041 void modelFound() {
1042 model = new int[trail.size()];
1043 fullmodel = new boolean[nVars()];
1044 int index = 0;
1045 for (int i = 1; i <= voc.nVars(); i++) {
1046 if (voc.belongsToPool(i)) {
1047 int p = voc.getFromPool(i);
1048 if (!voc.isUnassigned(p)) {
1049 model[index++] = voc.isSatisfied(p) ? i : -i;
1050 fullmodel[i - 1] = voc.isSatisfied(p);
1051 }
1052 }
1053 }
1054 assert index == model.length;
1055 cancelUntil(rootLevel);
1056 }
1057
1058 public boolean model(int var) {
1059 if (var <= 0 || var > nVars()) {
1060 throw new IllegalArgumentException(
1061 "Use a valid Dimacs var id as argument!");
1062 }
1063 if (fullmodel == null) {
1064 throw new UnsupportedOperationException(
1065 "Call the solve method first!!!");
1066 }
1067 return fullmodel[var - 1];
1068 }
1069
1070 public void clearLearntClauses() {
1071 for (Iterator<Constr> iterator = learnts.iterator(); iterator.hasNext();)
1072 iterator.next().remove(this);
1073 learnts.clear();
1074 learnedLiterals.clear();
1075 }
1076
1077 protected void reduceDB() {
1078 sortOnActivity();
1079 stats.reduceddb++;
1080 learnedConstraintsDeletionStrategy.reduce(learnts);
1081 System.gc();
1082 }
1083
1084
1085
1086
1087 private void sortOnActivity() {
1088 learnts.sort(comparator);
1089 }
1090
1091
1092
1093
1094 protected void decayActivities() {
1095 order.varDecayActivity();
1096 claDecayActivity();
1097 }
1098
1099
1100
1101
1102 private void claDecayActivity() {
1103 claInc *= claDecay;
1104 }
1105
1106
1107
1108
1109 public boolean isSatisfiable() throws TimeoutException {
1110 return isSatisfiable(VecInt.EMPTY);
1111 }
1112
1113
1114
1115
1116 public boolean isSatisfiable(boolean global) throws TimeoutException {
1117 return isSatisfiable(VecInt.EMPTY, global);
1118 }
1119
1120 private double timebegin = 0;
1121
1122 private boolean needToReduceDB;
1123
1124 private ConflictTimer conflictCount;
1125
1126 private transient Timer timer;
1127
1128 public boolean isSatisfiable(IVecInt assumps) throws TimeoutException {
1129 return isSatisfiable(assumps, false);
1130 }
1131
1132 interface LearnedConstraintsDeletionStrategy extends Serializable {
1133
1134 void init();
1135
1136 ConflictTimer getTimer();
1137
1138 void reduce(IVec<Constr> learnedConstrs);
1139
1140 void onConflict(Constr outLearnt);
1141
1142 void onConflictAnalysis(Constr reason);
1143 }
1144
1145
1146
1147
1148 public final LearnedConstraintsDeletionStrategy memory_based = new LearnedConstraintsDeletionStrategy() {
1149
1150
1151
1152
1153 private static final long serialVersionUID = 1L;
1154
1155 final long memorybound = Runtime.getRuntime().freeMemory() / 10;
1156
1157 private final ConflictTimer freeMem = new ConflictTimerAdapter(500) {
1158 private static final long serialVersionUID = 1L;
1159
1160 @Override
1161 void run() {
1162 long freemem = Runtime.getRuntime().freeMemory();
1163
1164 if (freemem < memorybound) {
1165
1166 needToReduceDB = true;
1167 }
1168 }
1169 };
1170
1171 public void reduce(IVec<Constr> learnedConstrs) {
1172 int i, j;
1173 for (i = j = 0; i < learnts.size() / 2; i++) {
1174 Constr c = learnts.get(i);
1175 if (c.locked() || c.size() == 2) {
1176 learnts.set(j++, learnts.get(i));
1177 } else {
1178 c.remove(Solver.this);
1179 }
1180 }
1181 for (; i < learnts.size(); i++) {
1182 learnts.set(j++, learnts.get(i));
1183 }
1184 if (verbose) {
1185 System.out.println(getLogPrefix()
1186 + "cleaning " + (learnts.size() - j)
1187 + " clauses out of " + learnts.size());
1188 }
1189 learnts.shrinkTo(j);
1190 }
1191
1192 public ConflictTimer getTimer() {
1193 return freeMem;
1194 }
1195
1196 @Override
1197 public String toString() {
1198 return "Memory based learned constraints deletion strategy";
1199 }
1200
1201 public void init() {
1202
1203 }
1204
1205 public void onConflict(Constr constr) {
1206
1207
1208 }
1209
1210 public void onConflictAnalysis(Constr reason) {
1211 if (reason.learnt())
1212 claBumpActivity(reason);
1213 }
1214 };
1215
1216
1217
1218
1219 public final LearnedConstraintsDeletionStrategy glucose = new LearnedConstraintsDeletionStrategy() {
1220
1221
1222
1223
1224 private static final long serialVersionUID = 1L;
1225 private int[] flags = new int[0];
1226 private int flag = 0;
1227 private int wall = 0;
1228
1229 private final ConflictTimer clauseManagement = new ConflictTimerAdapter(
1230 1000) {
1231 private static final long serialVersionUID = 1L;
1232 private int nbconflict = 0;
1233 private static final int MAX_CLAUSE = 5000;
1234 private static final int INC_CLAUSE = 1000;
1235 private int nextbound = MAX_CLAUSE;
1236
1237 @Override
1238 void run() {
1239 nbconflict += bound();
1240 if (nbconflict >= nextbound) {
1241 nextbound += INC_CLAUSE;
1242 if (nextbound > wall) {
1243 nextbound = wall;
1244 }
1245 nbconflict = 0;
1246 needToReduceDB = true;
1247 }
1248 }
1249 };
1250
1251 public void reduce(IVec<Constr> learnedConstrs) {
1252 int i, j;
1253 for (i = j = learnedConstrs.size() / 2; i < learnedConstrs.size(); i++) {
1254 Constr c = learnedConstrs.get(i);
1255 if (c.locked() || c.getActivity() <= 2.0) {
1256 learnedConstrs.set(j++, learnts.get(i));
1257 } else {
1258 c.remove(Solver.this);
1259 }
1260 }
1261 if (verbose) {
1262 System.out
1263 .println(getLogPrefix()
1264 + "cleaning " + (learnedConstrs.size() - j)
1265 + " clauses out of " + learnedConstrs.size() + " with flag " + flag + "/" + stats.conflicts);
1266 }
1267 learnts.shrinkTo(j);
1268
1269 }
1270
1271 public ConflictTimer getTimer() {
1272 return clauseManagement;
1273 }
1274
1275 @Override
1276 public String toString() {
1277 return "Glucose learned constraints deletion strategy";
1278 }
1279
1280 public void init() {
1281 final int howmany = voc.nVars();
1282 wall = constrs.size() > 10000 ? constrs.size() : 10000;
1283 if (flags.length <= howmany) {
1284 flags = new int[howmany + 1];
1285 }
1286
1287 }
1288
1289 public void onConflict(Constr constr) {
1290 int nblevel = 1;
1291 flag++;
1292 int currentLevel;
1293 for (int i = 1; i < constr.size(); i++) {
1294 currentLevel = voc.getLevel(constr.get(i));
1295 if (flags[currentLevel] != flag) {
1296 flags[currentLevel] = flag;
1297 nblevel++;
1298 }
1299 }
1300 constr.incActivity(nblevel);
1301 }
1302
1303 public void onConflictAnalysis(Constr reason) {
1304
1305 }
1306 };
1307
1308 private LearnedConstraintsDeletionStrategy learnedConstraintsDeletionStrategy = glucose;
1309
1310
1311
1312
1313
1314 public void setLearnedConstraintsDeletionStrategy(
1315 LearnedConstraintsDeletionStrategy lcds) {
1316 learnedConstraintsDeletionStrategy = lcds;
1317 }
1318
1319 public boolean isSatisfiable(IVecInt assumps, boolean global)
1320 throws TimeoutException {
1321 Lbool status = Lbool.UNDEFINED;
1322 undertimeout = true;
1323 final int howmany = voc.nVars();
1324 if (mseen.length <= howmany) {
1325 mseen = new boolean[howmany + 1];
1326 }
1327 trail.ensure(howmany);
1328 trailLim.ensure(howmany);
1329 learnedLiterals.ensure(howmany);
1330 timebegin = System.currentTimeMillis();
1331 slistener.start();
1332 model = null;
1333 fullmodel = null;
1334 unsatExplanationInTermsOfAssumptions = null;
1335 order.init();
1336 learnedConstraintsDeletionStrategy.init();
1337
1338 int learnedLiteralsLimit = trail.size();
1339
1340
1341 for (IteratorInt iterator = learnedLiterals.iterator(); iterator
1342 .hasNext();) {
1343 enqueue(iterator.next());
1344 }
1345
1346
1347 Constr confl = propagate();
1348 if (confl != null) {
1349 analyzeAtRootLevel(confl);
1350 slistener.conflictFound(confl, 0, 0);
1351 slistener.end(Lbool.FALSE);
1352 cancelUntil(0);
1353 cancelLearntLiterals(learnedLiteralsLimit);
1354 return false;
1355 }
1356
1357
1358 for (IteratorInt iterator = assumps.iterator(); iterator.hasNext();) {
1359 int assump = iterator.next();
1360 int p = voc.getFromPool(assump);
1361 if (!assume(p) || ((confl = propagate()) != null)) {
1362 if (confl == null) {
1363 slistener.conflictFound(p);
1364 unsatExplanationInTermsOfAssumptions = analyzeFinalConflictInTermsOfAssumptions(
1365 null, assumps, p);
1366 unsatExplanationInTermsOfAssumptions.push(assump);
1367 } else {
1368 slistener.conflictFound(confl, decisionLevel(),
1369 trail.size());
1370 unsatExplanationInTermsOfAssumptions = analyzeFinalConflictInTermsOfAssumptions(
1371 confl, assumps, ILits.UNDEFINED);
1372 }
1373
1374 slistener.end(Lbool.FALSE);
1375 cancelUntil(0);
1376 cancelLearntLiterals(learnedLiteralsLimit);
1377 return false;
1378 }
1379 }
1380 rootLevel = decisionLevel();
1381
1382
1383 order.init();
1384 learner.init();
1385
1386 boolean firstTimeGlobal = false;
1387 if (timeBasedTimeout) {
1388 if (!global || timer == null) {
1389 firstTimeGlobal = true;
1390 TimerTask stopMe = new TimerTask() {
1391 @Override
1392 public void run() {
1393 undertimeout = false;
1394 }
1395 };
1396 timer = new Timer(true);
1397 timer.schedule(stopMe, timeout);
1398 conflictCount = learnedConstraintsDeletionStrategy.getTimer();
1399 }
1400 } else {
1401 if (!global || conflictCount == null) {
1402 firstTimeGlobal = true;
1403 ConflictTimer conflictTimeout = new ConflictTimerAdapter(
1404 (int) timeout) {
1405 private static final long serialVersionUID = 1L;
1406
1407 @Override
1408 public void run() {
1409 undertimeout = false;
1410 }
1411 };
1412 conflictCount = new ConflictTimerContainer().add(
1413 conflictTimeout).add(
1414 learnedConstraintsDeletionStrategy.getTimer());
1415 }
1416 }
1417 if (!global || firstTimeGlobal)
1418 restarter.init(params);
1419 needToReduceDB = false;
1420
1421 while ((status == Lbool.UNDEFINED) && undertimeout) {
1422 status = search(restarter.nextRestartNumberOfConflict(), assumps);
1423 if (status == Lbool.UNDEFINED) {
1424 restarter.onRestart();
1425 slistener.restarting();
1426 }
1427 }
1428
1429 cancelUntil(0);
1430 cancelLearntLiterals(learnedLiteralsLimit);
1431 if (!global && timeBasedTimeout) {
1432 timer.cancel();
1433 timer = null;
1434 }
1435 slistener.end(status);
1436 if (!undertimeout) {
1437 String message = " Timeout (" + timeout
1438 + (timeBasedTimeout ? "s" : " conflicts") + ") exceeded";
1439 throw new TimeoutException(message);
1440 }
1441 return status == Lbool.TRUE;
1442 }
1443
1444 public void printInfos(PrintWriter out, String prefix) {
1445 out.print(prefix);
1446 out.println("constraints type ");
1447 for (Map.Entry<String, Counter> entry : constrTypes.entrySet()) {
1448 out.println(prefix + entry.getKey() + " => " + entry.getValue());
1449 }
1450 }
1451
1452
1453
1454
1455 public void printLearntClausesInfos(PrintWriter out, String prefix) {
1456 Map<String, Counter> learntTypes = new HashMap<String, Counter>();
1457 for (Iterator<Constr> it = learnts.iterator(); it.hasNext();) {
1458 String type = it.next().getClass().getName();
1459 Counter count = learntTypes.get(type);
1460 if (count == null) {
1461 learntTypes.put(type, new Counter());
1462 } else {
1463 count.inc();
1464 }
1465 }
1466 out.print(prefix);
1467 out.println("learnt constraints type ");
1468 for (Map.Entry<String, Counter> entry : learntTypes.entrySet()) {
1469 out.println(prefix + entry.getKey() + " => " + entry.getValue());
1470 }
1471 }
1472
1473 public SolverStats getStats() {
1474 return stats;
1475 }
1476
1477
1478
1479
1480
1481
1482 protected void initStats(SolverStats myStats) {
1483 this.stats = myStats;
1484 }
1485
1486 public IOrder getOrder() {
1487 return order;
1488 }
1489
1490 public void setOrder(IOrder h) {
1491 order = h;
1492 order.setLits(voc);
1493 }
1494
1495 public ILits getVocabulary() {
1496 return voc;
1497 }
1498
1499 public void reset() {
1500 trail.clear();
1501 trailLim.clear();
1502 qhead = 0;
1503 for (Iterator<Constr> iterator = constrs.iterator(); iterator.hasNext();)
1504 iterator.next().remove(this);
1505 constrs.clear();
1506 clearLearntClauses();
1507 voc.resetPool();
1508 dsfactory.reset();
1509 stats.reset();
1510 constrTypes.clear();
1511 }
1512
1513 public int nVars() {
1514 return voc.nVars();
1515 }
1516
1517
1518
1519
1520
1521
1522 protected IConstr addConstr(Constr constr) {
1523 if (constr != null) {
1524 constrs.push(constr);
1525 String type = constr.getClass().getName();
1526 Counter count = constrTypes.get(type);
1527 if (count == null) {
1528 constrTypes.put(type, new Counter());
1529 } else {
1530 count.inc();
1531 }
1532 }
1533 return constr;
1534 }
1535
1536 public DataStructureFactory getDSFactory() {
1537 return dsfactory;
1538 }
1539
1540 public IVecInt getOutLearnt() {
1541 return moutLearnt;
1542 }
1543
1544
1545
1546
1547
1548
1549
1550
1551 public IConstr getIthConstr(int i) {
1552 return constrs.get(i);
1553 }
1554
1555
1556
1557
1558
1559
1560
1561 public void printStat(PrintStream out, String prefix) {
1562 printStat(new PrintWriter(out, true), prefix);
1563 }
1564
1565 public void printStat(PrintWriter out, String prefix) {
1566 stats.printStat(out, prefix);
1567 double cputime = (System.currentTimeMillis() - timebegin) / 1000;
1568 out.println(prefix
1569 + "speed (assignments/second)\t: " + stats.propagations
1570 / cputime);
1571 order.printStat(out, prefix);
1572 printLearntClausesInfos(out, prefix);
1573 }
1574
1575
1576
1577
1578
1579
1580 public String toString(String prefix) {
1581 StringBuffer stb = new StringBuffer();
1582 Object[] objs = { analyzer, dsfactory, learner, params, order,
1583 simplifier, restarter, learnedConstraintsDeletionStrategy };
1584 stb.append(prefix);
1585 stb.append("--- Begin Solver configuration ---");
1586 stb.append("\n");
1587 for (Object o : objs) {
1588 stb.append(prefix);
1589 stb.append(o.toString());
1590 stb.append("\n");
1591 }
1592 stb.append(prefix);
1593 stb.append("timeout=");
1594 if (timeBasedTimeout) {
1595 stb.append(timeout / 1000);
1596 stb.append("s\n");
1597 } else {
1598 stb.append(timeout);
1599 stb.append(" conflicts\n");
1600 }
1601 stb.append(prefix);
1602 stb.append("DB Simplification allowed=");
1603 stb.append(isDBSimplificationAllowed);
1604 stb.append("\n");
1605 stb.append(prefix);
1606 stb.append("--- End Solver configuration ---");
1607 return stb.toString();
1608 }
1609
1610
1611
1612
1613
1614
1615 @Override
1616 public String toString() {
1617 return toString("");
1618 }
1619
1620 public int getTimeout() {
1621 return (int) (timeBasedTimeout ? timeout / 1000 : timeout);
1622 }
1623
1624
1625
1626
1627 public long getTimeoutMs() {
1628 if (!timeBasedTimeout) {
1629 throw new UnsupportedOperationException(
1630 "The timeout is given in number of conflicts!");
1631 }
1632 return timeout;
1633 }
1634
1635 public void setExpectedNumberOfClauses(int nb) {
1636 constrs.ensure(nb);
1637 }
1638
1639 public Map<String, Number> getStat() {
1640 return stats.toMap();
1641 }
1642
1643 public int[] findModel() throws TimeoutException {
1644 if (isSatisfiable()) {
1645 return model();
1646 }
1647
1648
1649 return null;
1650 }
1651
1652 public int[] findModel(IVecInt assumps) throws TimeoutException {
1653 if (isSatisfiable(assumps)) {
1654 return model();
1655 }
1656
1657
1658 return null;
1659 }
1660
1661 public boolean isDBSimplificationAllowed() {
1662 return isDBSimplificationAllowed;
1663 }
1664
1665 public void setDBSimplificationAllowed(boolean status) {
1666 isDBSimplificationAllowed = status;
1667 }
1668
1669
1670
1671
1672 public int nextFreeVarId(boolean reserve) {
1673 return voc.nextFreeVarId(reserve);
1674 }
1675
1676
1677
1678
1679 public IConstr addBlockingClause(IVecInt literals)
1680 throws ContradictionException {
1681 return addClause(literals);
1682 }
1683
1684
1685
1686
1687 public void unset(int p) {
1688 int current = trail.last();
1689 while (current != p) {
1690 undoOne();
1691 current = trail.last();
1692 }
1693 undoOne();
1694 }
1695
1696
1697
1698
1699 public void setLogPrefix(String prefix) {
1700 this.prefix = prefix;
1701 }
1702
1703
1704
1705
1706 public String getLogPrefix() {
1707 return prefix;
1708 }
1709
1710
1711
1712
1713 public IVecInt unsatExplanation() {
1714 return unsatExplanationInTermsOfAssumptions;
1715 }
1716
1717 }
1718
1719 class ActivityComparator implements Comparator<Constr>, Serializable {
1720
1721 private static final long serialVersionUID = 1L;
1722
1723
1724
1725
1726
1727
1728 public int compare(Constr c1, Constr c2) {
1729 long delta = Math.round(c1.getActivity() - c2.getActivity());
1730 if (delta == 0) {
1731 return c1.size() - c2.size();
1732 }
1733 return (int) delta;
1734 }
1735 }
1736
1737 interface ConflictTimer {
1738
1739 void reset();
1740
1741 void newConflict();
1742 }
1743
1744 abstract class ConflictTimerAdapter implements Serializable, ConflictTimer {
1745
1746
1747
1748
1749 private static final long serialVersionUID = 1L;
1750
1751 private int counter;
1752
1753 private final int bound;
1754
1755 ConflictTimerAdapter(final int bound) {
1756 this.bound = bound;
1757 counter = 0;
1758 }
1759
1760 public void reset() {
1761 counter = 0;
1762 }
1763
1764 public void newConflict() {
1765 counter++;
1766 if (counter == bound) {
1767 run();
1768 counter = 0;
1769 }
1770 }
1771
1772 abstract void run();
1773
1774 public int bound() {
1775 return bound;
1776 }
1777 }
1778
1779 class ConflictTimerContainer implements Serializable, ConflictTimer {
1780
1781
1782
1783
1784 private static final long serialVersionUID = 1L;
1785
1786 private final IVec<ConflictTimer> timers = new Vec<ConflictTimer>();
1787
1788 ConflictTimerContainer add(ConflictTimer timer) {
1789 timers.push(timer);
1790 return this;
1791 }
1792
1793 public void reset() {
1794 Iterator<ConflictTimer> it = timers.iterator();
1795 while (it.hasNext()) {
1796 it.next().reset();
1797 }
1798 }
1799
1800 public void newConflict() {
1801 Iterator<ConflictTimer> it = timers.iterator();
1802 while (it.hasNext()) {
1803 it.next().newConflict();
1804 }
1805 }
1806 }