View Javadoc

1   /*******************************************************************************
2    * SAT4J: a SATisfiability library for Java Copyright (C) 2004, 2012 Artois University and CNRS
3    *
4    * All rights reserved. This program and the accompanying materials
5    * are made available under the terms of the Eclipse Public License v1.0
6    * which accompanies this distribution, and is available at
7    *  http://www.eclipse.org/legal/epl-v10.html
8    *
9    * Alternatively, the contents of this file may be used under the terms of
10   * either the GNU Lesser General Public License Version 2.1 or later (the
11   * "LGPL"), in which case the provisions of the LGPL are applicable instead
12   * of those above. If you wish to allow use of your version of this file only
13   * under the terms of the LGPL, and not to allow others to use your version of
14   * this file under the terms of the EPL, indicate your decision by deleting
15   * the provisions above and replace them with the notice and other provisions
16   * required by the LGPL. If you do not delete the provisions above, a recipient
17   * may use your version of this file under the terms of the EPL or the LGPL.
18   *
19   * Based on the original MiniSat specification from:
20   *
21   * An extensible SAT solver. Niklas Een and Niklas Sorensson. Proceedings of the
22   * Sixth International Conference on Theory and Applications of Satisfiability
23   * Testing, LNCS 2919, pp 502-518, 2003.
24   *
25   * See www.minisat.se for the original solver in C++.
26   *
27   * Contributors:
28   *   CRIL - initial API and implementation
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   * The backbone of the library providing the modular implementation of a MiniSAT
64   * (Chaff) like solver.
65   * 
66   * @author leberre
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       * Set of original constraints.
81       */
82      protected final IVec<Constr> constrs = new Vec<Constr>();
83  
84      /**
85       * Set of learned constraints.
86       */
87      protected final IVec<Constr> learnts = new Vec<Constr>();
88  
89      /**
90       * Increment for clause activity.
91       */
92      private double claInc = 1.0;
93  
94      /**
95       * decay factor pour l'activit? des clauses.
96       */
97      private double claDecay = 1.0;
98  
99      /**
100      * propagation queue
101      */
102     // head of the queue in trail ... (taken from MiniSAT 1.14)
103     private int qhead = 0;
104 
105     /**
106      * variable assignments (literals) in chronological order.
107      */
108     protected final IVecInt trail = new VecInt();
109 
110     /**
111      * position of the decision levels on the trail.
112      */
113     protected final IVecInt trailLim = new VecInt();
114 
115     /**
116      * position of assumptions before starting the search.
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      * @since 2.3.1
178      */
179     public void registerLiteral(int p) {
180         this.voc.getFromPool(p);
181     }
182 
183     /**
184      * creates a Solver without LearningListener. A learningListener must be
185      * added to the solver, else it won't backtrack!!! A data structure factory
186      * must be provided, else it won't work either.
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         // should be called after dsf has been set up
207         setLearningStrategy(learner);
208     }
209 
210     /*
211      * (non-Javadoc)
212      * 
213      * @see org.sat4j.minisat.core.ICDCL#setDataStructureFactory(D)
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      * @since 2.2
225      */
226     public boolean isVerbose() {
227         return this.verbose;
228     }
229 
230     /**
231      * @param value
232      * @since 2.2
233      */
234     public void setVerbose(boolean value) {
235         this.verbose = value;
236     }
237 
238     /*
239      * (non-Javadoc)
240      * 
241      * @see
242      * org.sat4j.minisat.core.ICDCL#setSearchListener(org.sat4j.specs.SearchListener
243      * )
244      */
245     public <S extends ISolverService> void setSearchListener(
246             SearchListener<S> sl) {
247         this.slistener = sl;
248     }
249 
250     /*
251      * (non-Javadoc)
252      * 
253      * @see org.sat4j.minisat.core.ICDCL#getSearchListener()
254      */
255     public <S extends ISolverService> SearchListener<S> getSearchListener() {
256         return this.slistener;
257     }
258 
259     /*
260      * (non-Javadoc)
261      * 
262      * @see org.sat4j.minisat.core.ICDCL#setLearner(org.sat4j.minisat.core.
263      * LearningStrategy)
264      */
265     public void setLearner(LearningStrategy<D> strategy) {
266         setLearningStrategy(strategy);
267     }
268 
269     /*
270      * (non-Javadoc)
271      * 
272      * @see
273      * org.sat4j.minisat.core.ICDCL#setLearningStrategy(org.sat4j.minisat.core.
274      * LearningStrategy)
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      * (non-Javadoc)
301      * 
302      * @see org.sat4j.minisat.core.ICDCL#setSearchParams(org.sat4j.minisat.core.
303      * SearchParams)
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      * (non-Javadoc)
315      * 
316      * @see
317      * org.sat4j.minisat.core.ICDCL#setRestartStrategy(org.sat4j.minisat.core
318      * .RestartStrategy)
319      */
320     public void setRestartStrategy(RestartStrategy restarter) {
321         this.restarter = restarter;
322     }
323 
324     /*
325      * (non-Javadoc)
326      * 
327      * @see org.sat4j.minisat.core.ICDCL#getRestartStrategy()
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             // do nothing
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!"); //$NON-NLS-1$
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      * @since 2.1
411      */
412     public boolean removeSubsumedConstr(IConstr co) {
413         if (co == null) {
414             throw new IllegalArgumentException(
415                     "Reference to the constraint to remove needed!"); //$NON-NLS-1$
416         }
417         if (this.constrs.last() != co) {
418             throw new IllegalArgumentException(
419                     "Can only remove latest added constraint!!!"); //$NON-NLS-1$
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         // Simplifie la base de clauses apres la premiere propagation des
465         // clauses unitaires
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                     // enleve les contraintes satisfaites de la base
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      * Si un mod?le est trouv?, ce vecteur contient le mod?le.
484      * 
485      * @return un mod?le de la formule.
486      */
487     public int[] model() {
488         if (this.model == null) {
489             throw new UnsupportedOperationException(
490                     "Call the solve method first!!!"); //$NON-NLS-1$
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      * (non-Javadoc)
499      * 
500      * @see org.sat4j.minisat.core.ICDCL#enqueue(int)
501      */
502     public boolean enqueue(int p) {
503         return enqueue(p, null);
504     }
505 
506     /*
507      * (non-Javadoc)
508      * 
509      * @see org.sat4j.minisat.core.ICDCL#enqueue(int,
510      * org.sat4j.minisat.core.Constr)
511      */
512     public boolean enqueue(int p, Constr from) {
513         assert p > 1;
514         if (this.voc.isSatisfied(p)) {
515             // literal is already satisfied. Skipping.
516             return true;
517         }
518         if (this.voc.isFalsified(p)) {
519             // conflicting enqueued assignment
520             return false;
521         }
522         // new fact, store it
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      * @throws TimeoutException
541      *             if the timeout is reached during conflict analysis.
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         // reserve de la place pour le litteral falsifie
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                 // Trace reason for p
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                             // only literals assigned after decision level 0
582                             // part of
583                             // the explanation
584                             outLearnt.push(q ^ 1);
585                             outBtlevel = Math.max(outBtlevel,
586                                     this.voc.getLevel(q));
587                         }
588                     }
589                 }
590             }
591             prevConfl = confl;
592             // select next reason to look at
593             do {
594                 p = this.trail.last();
595                 confl = this.voc.getReason(p);
596                 undoOne();
597             } while (!seen[p >> 1]);
598             // seen[p.var] indique que p se trouve dans outLearnt ou dans
599             // le dernier niveau de d?cision
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         // slistener.learn(c);
607         this.learnedConstraintsDeletionStrategy.onClauseLearning(c);
608         results.reason = c;
609 
610         assert outBtlevel > -1;
611         results.backtrackLevel = outBtlevel;
612     }
613 
614     /**
615      * Derive a subset of the assumptions causing the inconistency.
616      * 
617      * @param confl
618      *            the last conflict of the search, occuring at root level.
619      * @param assumps
620      *            the set of assumption literals
621      * @param conflictingLiteral
622      *            the literal detected conflicting while propagating
623      *            assumptions.
624      * @return a subset of assumps causing the inconsistency.
625      * @since 2.2
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             // conflict detected when assuming a value
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             // conflict detected on unit clauses
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             // Trace reason for p
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             // select next reason to look at
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"; //$NON-NLS-1$
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"; //$NON-NLS-1$
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"; //$NON-NLS-1$
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"; //$NON-NLS-1$
766         }
767     };
768 
769     private ISimplifier simplifier = NO_SIMPLIFICATION;
770 
771     /*
772      * (non-Javadoc)
773      * 
774      * @see org.sat4j.minisat.core.ICDCL#setSimplifier(java.lang.String)
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      * (non-Javadoc)
789      * 
790      * @see
791      * org.sat4j.minisat.core.ICDCL#setSimplifier(org.sat4j.minisat.core.Solver
792      * .ISimplifier)
793      */
794     public void setSimplifier(ISimplifier simp) {
795         this.simplifier = simp;
796     }
797 
798     /*
799      * (non-Javadoc)
800      * 
801      * @see org.sat4j.minisat.core.ICDCL#getSimplifier()
802      */
803     public ISimplifier getSimplifier() {
804         return this.simplifier;
805     }
806 
807     // MiniSat -- Copyright (c) 2003-2005, Niklas Een, Niklas Sorensson
808     //
809     // Permission is hereby granted, free of charge, to any person obtaining a
810     // copy of this software and associated documentation files (the
811     // "Software"), to deal in the Software without restriction, including
812     // without limitation the rights to use, copy, modify, merge, publish,
813     // distribute, sublicense, and/or sell copies of the Software, and to
814     // permit persons to whom the Software is furnished to do so, subject to
815     // the following conditions:
816     //
817     // The above copyright notice and this permission notice shall be included
818     // in all copies or substantial portions of the Software.
819     //
820     // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
821     // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
822     // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
823     // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
824     // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
825     // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
826     // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
827 
828     // Taken from MiniSAT 1.14: Simplify conflict clause (a little):
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     // Taken from MiniSAT 1.14
857     private void expensiveSimplification(IVecInt conflictToReduce) {
858         // Simplify conflict clause (a lot):
859         //
860         int i, j;
861         // (maintain an abstraction of levels involved in conflict)
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     // Check if 'p' can be removed.' min_level' is used to abort early if
875     // visiting literals at a level that cannot be removed.
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     // Taken from MiniSAT 1.14
921     private void expensiveSimplificationWLOnly(IVecInt conflictToReduce) {
922         // Simplify conflict clause (a lot):
923         //
924         int i, j;
925         // (maintain an abstraction of levels involved in conflict)
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     // Check if 'p' can be removed.' min_level' is used to abort early if
939     // visiting literals at a level that cannot be removed.
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     // END Minisat 1.14 cut and paste
974 
975     /**
976      * 
977      */
978     protected void undoOne() {
979         // gather last assigned literal
980         int p = this.trail.last();
981         assert p > 1;
982         assert this.voc.getLevel(p) >= 0;
983         int x = p >> 1;
984         // unassign variable
985         this.voc.unassign(p);
986         this.voc.setReason(p, null);
987         this.voc.setLevel(p, -1);
988         // update heuristics value
989         this.order.undo(x);
990         // remove literal from the trail
991         this.trail.pop();
992         // update constraints on backtrack.
993         // not used if the solver uses watched literals.
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      * Propagate activity to a constraint
1004      * 
1005      * @param confl
1006      *            a constraint
1007      */
1008     public void claBumpActivity(Constr confl) {
1009         confl.incActivity(this.claInc);
1010         if (confl.getActivity() > CLAUSE_RESCALE_BOUND) {
1011             claRescalActivity();
1012             // for (int i = 0; i < confl.size(); i++) {
1013             // varBumpActivity(confl.get(i));
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      * @return null if not conflict is found, else a conflicting constraint.
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         // ltrail.size() changes due to propagation
1040         // cannot cache that value.
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         // p is the literal to propagate
1056         // Moved original MiniSAT code to dsfactory to avoid
1057         // watches manipulation in counter Based clauses for instance.
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             // try shortcut
1066             // shortcut = shortcuts.get(i);
1067             // if (shortcut != ILits.UNDEFINED && voc.isSatisfied(shortcut))
1068             // {
1069             // voc.watch(p, watched.get(i), shortcut);
1070             // stats.shortcuts++;
1071             // continue;
1072             // }
1073             if (!lwatched.get(i).propagate(this, p)) {
1074                 // Constraint is conflicting: copy remaining watches to
1075                 // watches[p]
1076                 // and return constraint
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(); // propQ.clear();
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      * @return false ssi conflit imm?diat.
1100      */
1101     public boolean assume(int p) {
1102         // Precondition: assume propagation queue is empty
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      * Revert to the state before the last assume()
1111      */
1112     private void cancel() {
1113         // assert trail.size() == qhead || !undertimeout;
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      * Restore literals
1125      */
1126     private void cancelLearntLiterals(int learnedLiteralsLimit) {
1127         this.learnedLiterals.clear();
1128         // assert trail.size() == qhead || !undertimeout;
1129         while (this.trail.size() > learnedLiteralsLimit) {
1130             this.learnedLiterals.push(this.trail.last());
1131             undoOne();
1132         }
1133         // qhead = 0;
1134         // learnedLiterals = 0;
1135     }
1136 
1137     /**
1138      * Cancel several levels of assumptions
1139      * 
1140      * @param level
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         // varDecay = 1 / params.varDecay;
1160         this.order.setVarDecay(1 / this.params.getVarDecay());
1161         this.claDecay = 1 / this.params.getClaDecay();
1162 
1163         do {
1164             this.slistener.beginLoop();
1165             // propage les clauses unitaires
1166             Constr confl = propagate();
1167             assert this.trail.size() == this.qhead;
1168 
1169             if (confl == null) {
1170                 // No conflict found
1171                 // simpliFYDB() prevents a correct use of
1172                 // constraints removal.
1173                 if (decisionLevel() == 0 && this.isDBSimplificationAllowed) {
1174                     // // Simplify the set of problem clause
1175                     // // iff rootLevel==0
1176                     this.stats.rootSimplifications++;
1177                     boolean ret = simplifyDB();
1178                     assert ret;
1179                 }
1180                 // was learnts.size() - nAssigns() > nofLearnts
1181                 // if (nofLearnts.obj >= 0 && learnts.size() > nofLearnts.obj) {
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                         // listener called ISolverService.backtrack()
1193                         confl = this.sharedConflict;
1194                         this.sharedConflict = null;
1195                     }
1196                 } else {
1197                     if (this.restarter.shouldRestart()) {
1198                         // Reached bound on number of conflicts
1199                         // Force a restart
1200                         cancelUntil(this.rootLevel);
1201                         return Lbool.UNDEFINED;
1202                     }
1203                     if (this.needToReduceDB) {
1204                         reduceDB();
1205                         this.needToReduceDB = false;
1206                         // Runtime.getRuntime().gc();
1207                     }
1208                     if (this.sharedConflict == null) {
1209                         // New variable decision
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                         // listener called ISolverService.backtrack()
1223                         confl = this.sharedConflict;
1224                         this.sharedConflict = null;
1225                     }
1226                 }
1227             }
1228             if (confl != null) {
1229                 // un conflit apparait
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                         // conflict at root level, the formula is inconsistent
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                 // analyze conflict
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; // timeout occured
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      * Forget a variable in the formula by falsifying both its positive and
1341      * negative literals.
1342      * 
1343      * @param var
1344      *            a variable
1345      * @return a conflicting constraint resulting from the disparition of those
1346      *         literals.
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      * Assume literal p and perform unit propagation
1364      * 
1365      * @param p
1366      *            a literal
1367      * @return true if no conflict is reached, false if a conflict is found.
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                 // d has been propagated
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                     // it is not a necessary literal
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                 // conflict, literal is necessary
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!"); //$NON-NLS-1$
1470         }
1471         if (this.prime == null) {
1472             throw new UnsupportedOperationException(
1473                     "Call the primeImplicant method first!!!"); //$NON-NLS-1$
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!"); //$NON-NLS-1$
1482         }
1483         if (this.userbooleanmodel == null) {
1484             throw new UnsupportedOperationException(
1485                     "Call the solve method first!!!"); //$NON-NLS-1$
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      * @param learnts
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      * @return true iff the set of constraints is satisfiable, else false.
1530      */
1531     public boolean isSatisfiable() throws TimeoutException {
1532         return isSatisfiable(VecInt.EMPTY);
1533     }
1534 
1535     /**
1536      * @return true iff the set of constraints is satisfiable, else false.
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) //$NON-NLS-1$
1588                             + " clauses out of " + Solver.this.learnts.size()); //$NON-NLS-1$ 
1589                     // out.flush();
1590                 }
1591                 Solver.this.learnts.shrinkTo(j);
1592             }
1593 
1594             public void onConflictAnalysis(Constr reason) {
1595                 // TODO Auto-generated method stub
1596 
1597             }
1598 
1599             public void onClauseLearning(Constr outLearnt) {
1600                 // TODO Auto-generated method stub
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                 // TODO Auto-generated method stub
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) //$NON-NLS-1$
1650                             + " clauses out of " + Solver.this.learnts.size()); //$NON-NLS-1$ 
1651                     // out.flush();
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                 // do nothing
1667             }
1668 
1669             public void onClauseLearning(Constr constr) {
1670                 // do nothing
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                 // do nothing
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             // System.out.println("c Free memory "+freemem);
1694             if (freemem < this.memorybound) {
1695                 // Reduce the set of learnt clauses
1696                 Solver.this.needToReduceDB = true;
1697             }
1698         }
1699     };
1700 
1701     /**
1702      * @since 2.1
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         // private int wall = 0;
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) //$NON-NLS-1$
1734                                 + " clauses out of " + learnedConstrs.size() + " with flag " + this.flag + "/" + Solver.this.stats.conflicts); //$NON-NLS-1$ //$NON-NLS-2$
1735                 // out.flush();
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             // wall = constrs.size() > 10000 ? constrs.size() : 10000;
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                 // if (nextbound > wall) {
1830                 // nextbound = wall;
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      * @since 2.1
1850      */
1851     public final LearnedConstraintsDeletionStrategy glucose = new Glucose2LCDS(
1852             this.lbdTimer);
1853 
1854     protected LearnedConstraintsDeletionStrategy learnedConstraintsDeletionStrategy = this.glucose;
1855 
1856     /*
1857      * (non-Javadoc)
1858      * 
1859      * @see
1860      * org.sat4j.minisat.core.ICDCL#setLearnedConstraintsDeletionStrategy(org
1861      * .sat4j.minisat.core.Solver.LearnedConstraintsDeletionStrategy)
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; // forget about previous model
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         // Fix for Bug SAT37
1902         this.qhead = 0;
1903         // Apply undos on unit literals because they are getting propagated
1904         // again now that qhead is 0.
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         // push previously learned literals
1915         for (IteratorInt iterator = this.learnedLiterals.iterator(); iterator
1916                 .hasNext();) {
1917             enqueue(iterator.next());
1918         }
1919 
1920         // propagate constraints
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         // push incremental assumptions
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         // moved initialization here if new literals are added in the
1957         // assumptions.
1958         if (!alreadylaunched || !this.keepHot) {
1959             this.order.init(); // duplicated on purpose
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         // this is used to allow the solver to be incomplete,
2006         // when using a heuristics limited to a subset of variables
2007         this.lastConflictMeansUnsat = true;
2008         // Solve
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         // When using a search enumerator (to compute all models)
2035         // the final answer is FALSE, however we are aware of at least one model
2036         // (the last one)
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      * @since 2.1
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      * @param myStats
2085      * @since 2.2
2086      */
2087     protected void initStats(SolverStats myStats) {
2088         this.stats = myStats;
2089     }
2090 
2091     /*
2092      * (non-Javadoc)
2093      * 
2094      * @see org.sat4j.minisat.core.ICDCL#getOrder()
2095      */
2096     public IOrder getOrder() {
2097         return this.order;
2098     }
2099 
2100     /*
2101      * (non-Javadoc)
2102      * 
2103      * @see org.sat4j.minisat.core.ICDCL#setOrder(org.sat4j.minisat.core.IOrder)
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      * @param constr
2143      *            a constraint implementing the Constr interface.
2144      * @return a reference to the constraint for external use.
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      * returns the ith constraint in the solver.
2179      * 
2180      * @param i
2181      *            the constraint number (begins at 0)
2182      * @return the ith constraint
2183      */
2184     public IConstr getIthConstr(int i) {
2185         return this.constrs.get(i);
2186     }
2187 
2188     /*
2189      * (non-Javadoc)
2190      * 
2191      * @see org.sat4j.specs.ISolver#printStat(java.io.PrintStream,
2192      * java.lang.String)
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 //$NON-NLS-1$
2207                 / cputime);
2208         this.order.printStat(out, prefix);
2209         printLearntClausesInfos(out, prefix);
2210     }
2211 
2212     /*
2213      * (non-Javadoc)
2214      * 
2215      * @see java.lang.Object#toString()
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 ---"); //$NON-NLS-1$
2224         stb.append("\n"); //$NON-NLS-1$
2225         for (Object o : objs) {
2226             stb.append(prefix);
2227             stb.append(o.toString());
2228             stb.append("\n"); //$NON-NLS-1$
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 ---"); //$NON-NLS-1$
2253         return stb.toString();
2254     }
2255 
2256     /*
2257      * (non-Javadoc)
2258      * 
2259      * @see java.lang.Object#toString()
2260      */
2261     @Override
2262     public String toString() {
2263         return toString(""); //$NON-NLS-1$
2264     }
2265 
2266     public int getTimeout() {
2267         return (int) (this.timeBasedTimeout ? this.timeout / 1000
2268                 : this.timeout);
2269     }
2270 
2271     /**
2272      * @since 2.1
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         // DLB findbugs ok
2295         // A zero length array would mean that the formula is a tautology.
2296         return null;
2297     }
2298 
2299     public int[] findModel(IVecInt assumps) throws TimeoutException {
2300         if (isSatisfiable(assumps)) {
2301             return model();
2302         }
2303         // DLB findbugs ok
2304         // A zero length array would mean that the formula is a tautology.
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      * @since 2.1
2318      */
2319     public int nextFreeVarId(boolean reserve) {
2320         return this.voc.nextFreeVarId(reserve);
2321     }
2322 
2323     /**
2324      * @since 2.1
2325      */
2326     public IConstr addBlockingClause(IVecInt literals)
2327             throws ContradictionException {
2328         return addClause(literals);
2329     }
2330 
2331     /**
2332      * @since 2.1
2333      */
2334     public void unset(int p) {
2335         // the literal might already have been
2336         // removed from the trail.
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      * @since 2.2
2354      */
2355     public void setLogPrefix(String prefix) {
2356         this.prefix = prefix;
2357     }
2358 
2359     /**
2360      * @since 2.2
2361      */
2362     public String getLogPrefix() {
2363         return this.prefix;
2364     }
2365 
2366     /**
2367      * @since 2.2
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      * @since 2.3.1
2378      */
2379     public int[] modelWithInternalVariables() {
2380         if (this.model == null) {
2381             throw new UnsupportedOperationException(
2382                     "Call the solve method first!!!"); //$NON-NLS-1$
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      * @since 2.3.1
2398      */
2399     public int realNumberOfVariables() {
2400         return this.voc.nVars();
2401     }
2402 
2403     /**
2404      * @since 2.3.2
2405      */
2406     public void stop() {
2407         expireTimeout();
2408     }
2409 
2410     protected Constr sharedConflict;
2411 
2412     /**
2413      * @since 2.3.2
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      * @since 2.3.2
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      * @since 2.3.2
2440      */
2441     public int currentDecisionLevel() {
2442         return decisionLevel();
2443     }
2444 
2445     /**
2446      * @since 2.3.2
2447      */
2448     public int[] getLiteralsPropagatedAt(int decisionLevel) {
2449         throw new UnsupportedOperationException("Not implemented yet!");
2450     }
2451 
2452     /**
2453      * @since 2.3.2
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      * @since 2.3.2
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      * @since 2.3.2
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      * @param literals
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         // backtrack to the first decision level with a reason
2580         // for falsifying that constraint
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 }