View Javadoc

1   /*******************************************************************************
2    * SAT4J: a SATisfiability library for Java Copyright (C) 2004-2008 Daniel Le Berre
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   * The reason simplification methods are coming from MiniSAT 1.14 released under 
28   * the MIT license:
29   * MiniSat -- Copyright (c) 2003-2005, Niklas Een, Niklas Sorensson
30   *
31   * Permission is hereby granted, free of charge, to any person obtaining a
32   * copy of this software and associated documentation files (the
33   * "Software"), to deal in the Software without restriction, including
34   * without limitation the rights to use, copy, modify, merge, publish,
35   * distribute, sublicense, and/or sell copies of the Software, and to
36   * permit persons to whom the Software is furnished to do so, subject to
37   * the following conditions:
38   *
39   * The above copyright notice and this permission notice shall be included
40   * in all copies or substantial portions of the Software.
41   * 
42   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
43   * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
44   * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
45   * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
46   * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
47   * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
48   * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
49   *******************************************************************************/
50  package org.sat4j.minisat.core;
51  
52  import static org.sat4j.core.LiteralsUtils.toDimacs;
53  import static org.sat4j.core.LiteralsUtils.var;
54  
55  import java.io.PrintStream;
56  import java.io.PrintWriter;
57  import java.io.Serializable;
58  import java.lang.reflect.Field;
59  import java.util.Comparator;
60  import java.util.HashMap;
61  import java.util.Iterator;
62  import java.util.Map;
63  import java.util.Timer;
64  import java.util.TimerTask;
65  
66  import org.sat4j.core.Vec;
67  import org.sat4j.core.VecInt;
68  import org.sat4j.specs.ContradictionException;
69  import org.sat4j.specs.IConstr;
70  import org.sat4j.specs.ISolver;
71  import org.sat4j.specs.IVec;
72  import org.sat4j.specs.IVecInt;
73  import org.sat4j.specs.IteratorInt;
74  import org.sat4j.specs.Lbool;
75  import org.sat4j.specs.SearchListener;
76  import org.sat4j.specs.TimeoutException;
77  
78  /**
79   * The backbone of the library providing the modular implementation of a MiniSAT
80   * (Chaff) like solver.
81   * 
82   * @author leberre
83   */
84  public class Solver<D extends DataStructureFactory> implements ISolver,
85  		UnitPropagationListener, ActivityListener, Learner {
86  
87  	private static final long serialVersionUID = 1L;
88  
89  	private static final double CLAUSE_RESCALE_FACTOR = 1e-20;
90  
91  	private static final double CLAUSE_RESCALE_BOUND = 1 / CLAUSE_RESCALE_FACTOR;
92  
93  	/**
94  	 * List des contraintes du probl?me.
95  	 */
96  	private final IVec<Constr> constrs = new Vec<Constr>(); // Constr
97  
98  	/**
99  	 * Liste des clauses apprises.
100 	 */
101 	private final IVec<Constr> learnts = new Vec<Constr>(); // Clause
102 
103 	/**
104 	 * incr?ment pour l'activit? des clauses.
105 	 */
106 	private double claInc = 1.0;
107 
108 	/**
109 	 * decay factor pour l'activit? des clauses.
110 	 */
111 	private double claDecay = 1.0;
112 
113 	/**
114 	 * Queue de propagation
115 	 */
116 	// private final IntQueue propQ = new IntQueue(); // Lit
117 	// head of the queue in trail ... (taken from MiniSAT 1.14)
118 	private int qhead = 0;
119 
120 	// queue
121 
122 	/**
123 	 * affectation en ordre chronologique
124 	 */
125 	protected final IVecInt trail = new VecInt(); // lit
126 
127 	// vector
128 
129 	/**
130 	 * indice des s?parateurs des diff?rents niveau de d?cision dans trail
131 	 */
132 	protected final IVecInt trailLim = new VecInt(); // int
133 
134 	// vector
135 
136 	/**
137 	 * S?pare les hypoth?ses incr?mentale et recherche
138 	 */
139 	protected int rootLevel;
140 
141 	private int[] model = null;
142 
143 	protected ILits voc;
144 
145 	private IOrder order;
146 
147 	private final ActivityComparator comparator = new ActivityComparator();
148 
149 	private final SolverStats stats = new SolverStats();
150 
151 	private final LearningStrategy<D> learner;
152 
153 	protected final AssertingClauseGenerator analyzer;
154 
155 	private volatile boolean undertimeout;
156 
157 	private long timeout = Integer.MAX_VALUE;
158 
159 	private boolean timeBasedTimeout = true;
160 
161 	protected D dsfactory;
162 
163 	private SearchParams params;
164 
165 	private final IVecInt __dimacs_out = new VecInt();
166 
167 	private SearchListener slistener = new NullSearchListener();
168 
169 	private RestartStrategy restarter;
170 
171 	private final Map<String, Counter> constrTypes = new HashMap<String, Counter>();
172 
173 	private boolean isDBSimplificationAllowed = false;
174 
175 	private final IVecInt learnedLiterals = new VecInt();
176 
177 	protected IVecInt dimacs2internal(IVecInt in) {
178 		// if (voc.nVars() == 0) {
179 		// throw new RuntimeException(
180 		// "Please set the number of variables (solver.newVar() or solver.newVar(maxvar)) before adding constraints!"
181 		// );
182 		// }
183 		__dimacs_out.clear();
184 		__dimacs_out.ensure(in.size());
185 		for (int i = 0; i < in.size(); i++) {
186 			assert (in.get(i) != 0); // && (Math.abs(in.get(i)) <= voc.nVars());
187 			__dimacs_out.unsafePush(voc.getFromPool(in.get(i)));
188 		}
189 		return __dimacs_out;
190 	}
191 
192 	/**
193 	 * creates a Solver without LearningListener. A learningListener must be
194 	 * added to the solver, else it won't backtrack!!! A data structure factory
195 	 * must be provided, else it won't work either.
196 	 * 
197 	 * @param acg
198 	 *            an asserting clause generator
199 	 */
200 
201 	public Solver(AssertingClauseGenerator acg, LearningStrategy<D> learner,
202 			D dsf, IOrder order, RestartStrategy restarter) {
203 		this(acg, learner, dsf, new SearchParams(), order, restarter);
204 	}
205 
206 	public Solver(AssertingClauseGenerator acg, LearningStrategy<D> learner,
207 			D dsf, SearchParams params, IOrder order, RestartStrategy restarter) {
208 		analyzer = acg;
209 		this.learner = learner;
210 		this.order = order;
211 		this.params = params;
212 		setDataStructureFactory(dsf);
213 		this.restarter = restarter;
214 	}
215 
216 	/**
217 	 * Change the internal representation of the contraints. Note that the
218 	 * heuristics must be changed prior to calling that method.
219 	 * 
220 	 * @param dsf
221 	 *            the internal factory
222 	 */
223 	public final void setDataStructureFactory(D dsf) {
224 		dsfactory = dsf;
225 		dsfactory.setUnitPropagationListener(this);
226 		dsfactory.setLearner(this);
227 		voc = dsf.getVocabulary();
228 		order.setLits(voc);
229 	}
230 
231 	/**
232 	 * @since 2.1
233 	 */
234 	public void setSearchListener(SearchListener sl) {
235 		slistener = sl;
236 	}
237 
238 	public void setTimeout(int t) {
239 		timeout = t * 1000L;
240 		timeBasedTimeout = true;
241 	}
242 
243 	public void setTimeoutMs(long t) {
244 		timeout = t;
245 		timeBasedTimeout = true;
246 	}
247 
248 	public void setTimeoutOnConflicts(int count) {
249 		timeout = count;
250 		timeBasedTimeout = false;
251 	}
252 
253 	public void setSearchParams(SearchParams sp) {
254 		params = sp;
255 	}
256 
257 	public void setRestartStrategy(RestartStrategy restarter) {
258 		this.restarter = restarter;
259 	}
260 
261 	public void expireTimeout() {
262 		undertimeout = false;
263 	}
264 
265 	protected int nAssigns() {
266 		return trail.size();
267 	}
268 
269 	public int nConstraints() {
270 		return constrs.size() + trail.size();
271 	}
272 
273 	public void learn(Constr c) {
274 		learnts.push(c);
275 		c.setLearnt();
276 		c.register();
277 		stats.learnedclauses++;
278 		switch (c.size()) {
279 		case 2:
280 			stats.learnedbinaryclauses++;
281 			break;
282 		case 3:
283 			stats.learnedternaryclauses++;
284 			break;
285 		default:
286 			// do nothing
287 		}
288 	}
289 
290 	public int decisionLevel() {
291 		return trailLim.size();
292 	}
293 
294 	@Deprecated
295 	public int newVar() {
296 		int index = voc.nVars() + 1;
297 		voc.ensurePool(index);
298 		return index;
299 	}
300 
301 	public int newVar(int howmany) {
302 		voc.ensurePool(howmany);
303 		return voc.nVars();
304 	}
305 
306 	public IConstr addClause(IVecInt literals) throws ContradictionException {
307 		IVecInt vlits = dimacs2internal(literals);
308 		return addConstr(dsfactory.createClause(vlits));
309 	}
310 
311 	public boolean removeConstr(IConstr co) {
312 		if (co == null) {
313 			throw new IllegalArgumentException(
314 					"Reference to the constraint to remove needed!"); //$NON-NLS-1$
315 		}
316 		Constr c = (Constr) co;
317 		c.remove(this);
318 		constrs.remove(c);
319 		clearLearntClauses();
320 		String type = c.getClass().getName();
321 		constrTypes.get(type).dec();
322 		return true;
323 	}
324 
325 	/**
326 	 * @since 2.1
327 	 */
328 	public boolean removeSubsumedConstr(IConstr co) {
329 		if (co == null) {
330 			throw new IllegalArgumentException(
331 					"Reference to the constraint to remove needed!"); //$NON-NLS-1$
332 		}
333 		if (constrs.last() != co) {
334 			throw new IllegalArgumentException(
335 					"Can only remove latest added constraint!!!"); //$NON-NLS-1$
336 		}
337 		Constr c = (Constr) co;
338 		c.remove(this);
339 		constrs.pop();
340 		String type = c.getClass().getName();
341 		constrTypes.get(type).dec();
342 		return true;
343 	}
344 
345 	public void addAllClauses(IVec<IVecInt> clauses)
346 			throws ContradictionException {
347 		for (Iterator<IVecInt> iterator = clauses.iterator(); iterator
348 				.hasNext();) {
349 			addClause(iterator.next());
350 		}
351 	}
352 
353 	public IConstr addAtMost(IVecInt literals, int degree)
354 			throws ContradictionException {
355 		int n = literals.size();
356 		IVecInt opliterals = new VecInt(n);
357 		for (IteratorInt iterator = literals.iterator(); iterator.hasNext();) {
358 			opliterals.push(-iterator.next());
359 		}
360 		return addAtLeast(opliterals, n - degree);
361 	}
362 
363 	public IConstr addAtLeast(IVecInt literals, int degree)
364 			throws ContradictionException {
365 		IVecInt vlits = dimacs2internal(literals);
366 		return addConstr(dsfactory.createCardinalityConstraint(vlits, degree));
367 	}
368 
369 	@SuppressWarnings("unchecked")
370 	public boolean simplifyDB() {
371 		// aucune raison de recommencer un propagate?
372 		// if (propagate() != null) {
373 		// // Un conflit est d?couvert, la base est inconsistante
374 		// return false;
375 		// }
376 
377 		// Simplifie la base de clauses apres la premiere propagation des
378 		// clauses unitaires
379 		IVec<Constr>[] cs = new IVec[] { constrs, learnts };
380 		for (int type = 0; type < 2; type++) {
381 			int j = 0;
382 			for (int i = 0; i < cs[type].size(); i++) {
383 				if (cs[type].get(i).simplify()) {
384 					// enleve les contraintes satisfaites de la base
385 					cs[type].get(i).remove(this);
386 				} else {
387 					cs[type].moveTo(j++, i);
388 				}
389 			}
390 			cs[type].shrinkTo(j);
391 		}
392 		return true;
393 	}
394 
395 	/**
396 	 * Si un mod?le est trouv?, ce vecteur contient le mod?le.
397 	 * 
398 	 * @return un mod?le de la formule.
399 	 */
400 	public int[] model() {
401 		if (model == null) {
402 			throw new UnsupportedOperationException(
403 					"Call the solve method first!!!"); //$NON-NLS-1$
404 		}
405 		int[] nmodel = new int[model.length];
406 		System.arraycopy(model, 0, nmodel, 0, model.length);
407 		return nmodel;
408 	}
409 
410 	/**
411 	 * Satisfait un litt?ral
412 	 * 
413 	 * @param p
414 	 *            le litt?ral
415 	 * @return true si tout se passe bien, false si un conflit appara?t.
416 	 */
417 	public boolean enqueue(int p) {
418 		return enqueue(p, null);
419 	}
420 
421 	/**
422 	 * Put the literal on the queue of assignments to be done.
423 	 * 
424 	 * @param p
425 	 *            the literal.
426 	 * @param from
427 	 *            the reason to propagate that literal, else null
428 	 * @return true if the asignment can be made, false if a conflict is
429 	 *         detected.
430 	 */
431 	public boolean enqueue(int p, Constr from) {
432 		assert p > 1;
433 		if (voc.isSatisfied(p)) {
434 			// literal is already satisfied. Skipping.
435 			return true;
436 		}
437 		if (voc.isFalsified(p)) {
438 			// conflicting enqueued assignment
439 			return false;
440 		}
441 		// new fact, store it
442 		voc.satisfies(p);
443 		voc.setLevel(p, decisionLevel());
444 		voc.setReason(p, from);
445 		trail.push(p);
446 		if (from != null) {
447 			from.forwardActivity(claInc);
448 		}
449 		return true;
450 	}
451 
452 	private boolean[] mseen = new boolean[0];
453 
454 	private final IVecInt preason = new VecInt();
455 
456 	private final IVecInt outLearnt = new VecInt();
457 
458 	public void analyze(Constr confl, Pair results) {
459 		assert confl != null;
460 		outLearnt.clear();
461 
462 		final boolean[] seen = mseen;
463 
464 		assert outLearnt.size() == 0;
465 		for (int i = 0; i < seen.length; i++) {
466 			seen[i] = false;
467 		}
468 
469 		analyzer.initAnalyze();
470 		int p = ILits.UNDEFINED;
471 
472 		outLearnt.push(ILits.UNDEFINED);
473 		// reserve de la place pour le litteral falsifie
474 		int outBtlevel = 0;
475 
476 		do {
477 			preason.clear();
478 			assert confl != null;
479 			confl.calcReason(p, preason);
480 			learnedConstraintsDeletionStrategy.onConflictAnalysis(confl);
481 			// Trace reason for p
482 			for (int j = 0; j < preason.size(); j++) {
483 				int q = preason.get(j);
484 				order.updateVar(q);
485 				if (!seen[q >> 1]) {
486 					// order.updateVar(q); // MINISAT
487 					seen[q >> 1] = true;
488 					if (voc.getLevel(q) == decisionLevel()) {
489 						analyzer.onCurrentDecisionLevelLiteral(q);
490 					} else if (voc.getLevel(q) > 0) {
491 						// ajoute les variables depuis le niveau de d?cision 0
492 						outLearnt.push(q ^ 1);
493 						outBtlevel = Math.max(outBtlevel, voc.getLevel(q));
494 					}
495 				}
496 			}
497 
498 			// select next reason to look at
499 			do {
500 				p = trail.last();
501 				confl = voc.getReason(p);
502 				undoOne();
503 			} while (!seen[p >> 1]);
504 			// seen[p.var] indique que p se trouve dans outLearnt ou dans
505 			// le dernier niveau de d?cision
506 		} while (analyzer.clauseNonAssertive(confl));
507 
508 		outLearnt.set(0, p ^ 1);
509 		simplifier.simplify(outLearnt);
510 
511 		Constr c = dsfactory.createUnregisteredClause(outLearnt);
512 		slistener.learn(c);
513 		learnedConstraintsDeletionStrategy.onConflict(c);
514 		results.reason = c;
515 
516 		assert outBtlevel > -1;
517 		results.backtrackLevel = outBtlevel;
518 	}
519 
520 	interface ISimplifier extends Serializable {
521 		void simplify(IVecInt outLearnt);
522 	}
523 
524 	public static final ISimplifier NO_SIMPLIFICATION = new ISimplifier() {
525 		/**
526          * 
527          */
528 		private static final long serialVersionUID = 1L;
529 
530 		public void simplify(IVecInt outLearnt) {
531 		}
532 
533 		@Override
534 		public String toString() {
535 			return "No reason simplification"; //$NON-NLS-1$
536 		}
537 	};
538 
539 	public final ISimplifier SIMPLE_SIMPLIFICATION = new ISimplifier() {
540 		/**
541          * 
542          */
543 		private static final long serialVersionUID = 1L;
544 
545 		public void simplify(IVecInt conflictToReduce) {
546 			simpleSimplification(conflictToReduce);
547 		}
548 
549 		@Override
550 		public String toString() {
551 			return "Simple reason simplification"; //$NON-NLS-1$
552 		}
553 	};
554 
555 	public final ISimplifier EXPENSIVE_SIMPLIFICATION = new ISimplifier() {
556 
557 		/**
558          * 
559          */
560 		private static final long serialVersionUID = 1L;
561 
562 		public void simplify(IVecInt conflictToReduce) {
563 			expensiveSimplification(conflictToReduce);
564 		}
565 
566 		@Override
567 		public String toString() {
568 			return "Expensive reason simplification"; //$NON-NLS-1$
569 		}
570 	};
571 
572 	private ISimplifier simplifier = NO_SIMPLIFICATION;
573 
574 	/**
575 	 * Setup the reason simplification strategy. By default, there is no reason
576 	 * simplification. NOTE THAT REASON SIMPLIFICATION DOES NOT WORK WITH
577 	 * SPECIFIC DATA STRUCTURE FOR HANDLING BOTH BINARY AND TERNARY CLAUSES.
578 	 * 
579 	 * @param simp
580 	 *            the name of the simplifier (one of NO_SIMPLIFICATION,
581 	 *            SIMPLE_SIMPLIFICATION, EXPENSIVE_SIMPLIFICATION).
582 	 */
583 	public void setSimplifier(String simp) {
584 		Field f;
585 		try {
586 			f = Solver.class.getDeclaredField(simp);
587 			simplifier = (ISimplifier) f.get(this);
588 		} catch (Exception e) {
589 			e.printStackTrace();
590 			simplifier = NO_SIMPLIFICATION;
591 		}
592 	}
593 
594 	/**
595 	 * Setup the reason simplification strategy. By default, there is no reason
596 	 * simplification. NOTE THAT REASON SIMPLIFICATION IS ONLY ALLOWED FOR WL
597 	 * CLAUSAL data structures. USING REASON SIMPLIFICATION ON CB CLAUSES,
598 	 * CARDINALITY CONSTRAINTS OR PB CONSTRAINTS MIGHT RESULT IN INCORRECT
599 	 * RESULTS.
600 	 * 
601 	 * @param simp
602 	 */
603 	public void setSimplifier(ISimplifier simp) {
604 		simplifier = simp;
605 	}
606 
607 	// MiniSat -- Copyright (c) 2003-2005, Niklas Een, Niklas Sorensson
608 	//
609 	// Permission is hereby granted, free of charge, to any person obtaining a
610 	// copy of this software and associated documentation files (the
611 	// "Software"), to deal in the Software without restriction, including
612 	// without limitation the rights to use, copy, modify, merge, publish,
613 	// distribute, sublicense, and/or sell copies of the Software, and to
614 	// permit persons to whom the Software is furnished to do so, subject to
615 	// the following conditions:
616 	//
617 	// The above copyright notice and this permission notice shall be included
618 	// in all copies or substantial portions of the Software.
619 	//
620 	// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
621 	// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
622 	// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
623 	// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
624 	// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
625 	// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
626 	// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
627 
628 	// Taken from MiniSAT 1.14: Simplify conflict clause (a little):
629 	private void simpleSimplification(IVecInt conflictToReduce) {
630 		int i, j;
631 		final boolean[] seen = mseen;
632 		for (i = j = 1; i < conflictToReduce.size(); i++) {
633 			IConstr r = voc.getReason(conflictToReduce.get(i));
634 			if (r == null) {
635 				conflictToReduce.moveTo(j++, i);
636 			} else {
637 				for (int k = 0; k < r.size(); k++)
638 					if (voc.isFalsified(r.get(k)) && !seen[r.get(k) >> 1]
639 							&& (voc.getLevel(r.get(k)) != 0)) {
640 						conflictToReduce.moveTo(j++, i);
641 						break;
642 					}
643 			}
644 		}
645 		conflictToReduce.shrink(i - j);
646 		stats.reducedliterals += (i - j);
647 	}
648 
649 	private final IVecInt analyzetoclear = new VecInt();
650 
651 	private final IVecInt analyzestack = new VecInt();
652 
653 	// Taken from MiniSAT 1.14
654 	private void expensiveSimplification(IVecInt conflictToReduce) {
655 		// Simplify conflict clause (a lot):
656 		//
657 		int i, j;
658 		// (maintain an abstraction of levels involved in conflict)
659 		analyzetoclear.clear();
660 		conflictToReduce.copyTo(analyzetoclear);
661 		for (i = 1, j = 1; i < conflictToReduce.size(); i++)
662 			if (voc.getReason(conflictToReduce.get(i)) == null
663 					|| !analyzeRemovable(conflictToReduce.get(i)))
664 				conflictToReduce.moveTo(j++, i);
665 		conflictToReduce.shrink(i - j);
666 		stats.reducedliterals += (i - j);
667 	}
668 
669 	// Check if 'p' can be removed.' min_level' is used to abort early if
670 	// visiting literals at a level that cannot be removed.
671 	//
672 	private boolean analyzeRemovable(int p) {
673 		assert voc.getReason(p) != null;
674 		analyzestack.clear();
675 		analyzestack.push(p);
676 		final boolean[] seen = mseen;
677 		int top = analyzetoclear.size();
678 		while (analyzestack.size() > 0) {
679 			int q = analyzestack.last();
680 			assert voc.getReason(q) != null;
681 			Constr c = voc.getReason(q);
682 			analyzestack.pop();
683 			for (int i = 0; i < c.size(); i++) {
684 				int l = c.get(i);
685 				if (voc.isFalsified(l) && !seen[var(l)] && voc.getLevel(l) != 0) {
686 					if (voc.getReason(l) == null) {
687 						for (int j = top; j < analyzetoclear.size(); j++)
688 							seen[analyzetoclear.get(j) >> 1] = false;
689 						analyzetoclear.shrink(analyzetoclear.size() - top);
690 						return false;
691 					}
692 					seen[l >> 1] = true;
693 					analyzestack.push(l);
694 					analyzetoclear.push(l);
695 				}
696 			}
697 		}
698 
699 		return true;
700 	}
701 
702 	// END Minisat 1.14 cut and paste
703 
704 	/**
705      * 
706      */
707 	protected void undoOne() {
708 		// recupere le dernier litteral affecte
709 		int p = trail.last();
710 		assert p > 1;
711 		assert voc.getLevel(p) >= 0;
712 		int x = p >> 1;
713 		// desaffecte la variable
714 		voc.unassign(p);
715 		voc.setReason(p, null);
716 		voc.setLevel(p, -1);
717 		// met a jour l'heuristique
718 		order.undo(x);
719 		// depile le litteral des affectations
720 		trail.pop();
721 		// met a jour les contraintes apres desaffectation du litteral :
722 		// normalement, il n'y a rien a faire ici pour les prouveurs de type
723 		// Chaff??
724 		IVec<Undoable> undos = voc.undos(p);
725 		assert undos != null;
726 		while (undos.size() > 0) {
727 			undos.last().undo(p);
728 			undos.pop();
729 		}
730 	}
731 
732 	/**
733 	 * Propagate activity to a constraint
734 	 * 
735 	 * @param confl
736 	 *            a constraint
737 	 */
738 	public void claBumpActivity(Constr confl) {
739 		confl.incActivity(claInc);
740 		if (confl.getActivity() > CLAUSE_RESCALE_BOUND)
741 			claRescalActivity();
742 		// for (int i = 0; i < confl.size(); i++) {
743 		// varBumpActivity(confl.get(i));
744 		// }
745 	}
746 
747 	public void varBumpActivity(int p) {
748 		order.updateVar(p);
749 	}
750 
751 	private void claRescalActivity() {
752 		for (int i = 0; i < learnts.size(); i++) {
753 			learnts.get(i).rescaleBy(CLAUSE_RESCALE_FACTOR);
754 		}
755 		claInc *= CLAUSE_RESCALE_FACTOR;
756 	}
757 
758 	/**
759 	 * @return null if not conflict is found, else a conflicting constraint.
760 	 */
761 	public Constr propagate() {
762 		while (qhead < trail.size()) {
763 			stats.propagations++;
764 			int p = trail.get(qhead++);
765 			slistener.propagating(toDimacs(p), null);
766 			order.assignLiteral(p);
767 			// p is the literal to propagate
768 			// Moved original MiniSAT code to dsfactory to avoid
769 			// watches manipulation in counter Based clauses for instance.
770 			assert p > 1;
771 			IVec<Propagatable> watched = dsfactory.getWatchesFor(p);
772 
773 			final int size = watched.size();
774 			for (int i = 0; i < size; i++) {
775 				stats.inspects++;
776 				if (!watched.get(i).propagate(this, p)) {
777 					// Constraint is conflicting: copy remaining watches to
778 					// watches[p]
779 					// and return constraint
780 					dsfactory.conflictDetectedInWatchesFor(p, i);
781 					qhead = trail.size(); // propQ.clear();
782 					// FIXME enlever le transtypage
783 					return (Constr) watched.get(i);
784 				}
785 			}
786 		}
787 		return null;
788 	}
789 
790 	void record(Constr constr) {
791 		constr.assertConstraint(this);
792 		slistener.adding(toDimacs(constr.get(0)));
793 		if (constr.size() == 1) {
794 			stats.learnedliterals++;
795 		} else {
796 			learner.learns(constr);
797 		}
798 	}
799 
800 	/**
801 	 * @return false ssi conflit imm?diat.
802 	 */
803 	public boolean assume(int p) {
804 		// Precondition: assume propagation queue is empty
805 		assert trail.size() == qhead;
806 		trailLim.push(trail.size());
807 		return enqueue(p);
808 	}
809 
810 	/**
811 	 * Revert to the state before the last push()
812 	 */
813 	private void cancel() {
814 		// assert trail.size() == qhead || !undertimeout;
815 		int decisionvar = trail.unsafeGet(trailLim.last());
816 		slistener.backtracking(toDimacs(decisionvar));
817 		for (int c = trail.size() - trailLim.last(); c > 0; c--) {
818 			undoOne();
819 		}
820 		trailLim.pop();
821 	}
822 
823 	/**
824 	 * Restore literals
825 	 */
826 	private void cancelLearntLiterals(int learnedLiteralsLimit) {
827 		learnedLiterals.clear();
828 		// assert trail.size() == qhead || !undertimeout;
829 		while (trail.size() > learnedLiteralsLimit) {
830 			learnedLiterals.push(trail.last());
831 			undoOne();
832 		}
833 		qhead = trail.size();
834 		// learnedLiterals = 0;
835 	}
836 
837 	/**
838 	 * Cancel several levels of assumptions
839 	 * 
840 	 * @param level
841 	 */
842 	protected void cancelUntil(int level) {
843 		while (decisionLevel() > level) {
844 			cancel();
845 		}
846 		qhead = trail.size();
847 	}
848 
849 	private final Pair analysisResult = new Pair();
850 
851 	private boolean[] fullmodel;
852 
853 	Lbool search(long nofConflicts) {
854 		assert rootLevel == decisionLevel();
855 		stats.starts++;
856 		int conflictC = 0;
857 
858 		// varDecay = 1 / params.varDecay;
859 		order.setVarDecay(1 / params.getVarDecay());
860 		claDecay = 1 / params.getClaDecay();
861 
862 		do {
863 			slistener.beginLoop();
864 			// propage les clauses unitaires
865 			Constr confl = propagate();
866 			assert trail.size() == qhead;
867 
868 			if (confl == null) {
869 				// No conflict found
870 				// simpliFYDB() prevents a correct use of
871 				// constraints removal.
872 				if (decisionLevel() == 0 && isDBSimplificationAllowed) {
873 					// // Simplify the set of problem clause
874 					// // iff rootLevel==0
875 					stats.rootSimplifications++;
876 					boolean ret = simplifyDB();
877 					assert ret;
878 				}
879 				// was learnts.size() - nAssigns() > nofLearnts
880 				// if (nofLearnts.obj >= 0 && learnts.size() > nofLearnts.obj) {
881 				assert nAssigns() <= voc.realnVars();
882 				if (nAssigns() == voc.realnVars()) {
883 					slistener.solutionFound();
884 					modelFound();
885 					return Lbool.TRUE;
886 				}
887 				if (conflictC >= nofConflicts) {
888 					// Reached bound on number of conflicts
889 					// Force a restart
890 					cancelUntil(rootLevel);
891 					return Lbool.UNDEFINED;
892 				}
893 				if (needToReduceDB) {
894 					reduceDB();
895 					needToReduceDB = false;
896 					// Runtime.getRuntime().gc();
897 				}
898 				// New variable decision
899 				stats.decisions++;
900 				int p = order.select();
901 				assert p > 1;
902 				slistener.assuming(toDimacs(p));
903 				boolean ret = assume(p);
904 				assert ret;
905 			} else {
906 				// un conflit apparait
907 				stats.conflicts++;
908 				conflictC++;
909 				slistener.conflictFound(confl);
910 				conflictCount.newConflict();
911 				if (decisionLevel() == rootLevel) {
912 					// on est a la racine, la formule est inconsistante
913 					return Lbool.FALSE;
914 				}
915 				// analyze conflict
916 				analyze(confl, analysisResult);
917 				assert analysisResult.backtrackLevel < decisionLevel();
918 				cancelUntil(Math.max(analysisResult.backtrackLevel, rootLevel));
919 				assert (decisionLevel() >= rootLevel)
920 						&& (decisionLevel() >= analysisResult.backtrackLevel);
921 				if (analysisResult.reason == null) {
922 					return Lbool.FALSE;
923 				}
924 				record(analysisResult.reason);
925 				analysisResult.reason = null;
926 				decayActivities();
927 			}
928 		} while (undertimeout);
929 		return Lbool.UNDEFINED; // timeout occured
930 	}
931 
932 	protected void analyzeAtRootLevel(Constr conflict) {
933 	}
934 
935 	/**
936      * 
937      */
938 	void modelFound() {
939 		model = new int[trail.size()];
940 		fullmodel = new boolean[nVars()];
941 		int index = 0;
942 		for (int i = 1; i <= voc.nVars(); i++) {
943 			if (voc.belongsToPool(i)) {
944 				int p = voc.getFromPool(i);
945 				if (!voc.isUnassigned(p)) {
946 					model[index++] = voc.isSatisfied(p) ? i : -i;
947 					fullmodel[i - 1] = voc.isSatisfied(p);
948 				}
949 			}
950 		}
951 		assert index == model.length;
952 		cancelUntil(rootLevel);
953 	}
954 
955 	public boolean model(int var) {
956 		if (var <= 0 || var > nVars()) {
957 			throw new IllegalArgumentException(
958 					"Use a valid Dimacs var id as argument!"); //$NON-NLS-1$
959 		}
960 		if (fullmodel == null) {
961 			throw new UnsupportedOperationException(
962 					"Call the solve method first!!!"); //$NON-NLS-1$
963 		}
964 		return fullmodel[var - 1];
965 	}
966 
967 	public void clearLearntClauses() {
968 		for (Iterator<Constr> iterator = learnts.iterator(); iterator.hasNext();)
969 			iterator.next().remove(this);
970 		learnts.clear();
971 		learnedLiterals.clear();
972 	}
973 
974 	protected void reduceDB() {
975 		sortOnActivity();
976 		stats.reduceddb++;
977 		learnedConstraintsDeletionStrategy.reduce(learnts);
978 		System.gc();
979 	}
980 
981 	/**
982 	 * @param learnts
983 	 */
984 	private void sortOnActivity() {
985 		learnts.sort(comparator);
986 	}
987 
988 	/**
989      * 
990      */
991 	protected void decayActivities() {
992 		order.varDecayActivity();
993 		claDecayActivity();
994 	}
995 
996 	/**
997      * 
998      */
999 	private void claDecayActivity() {
1000 		claInc *= claDecay;
1001 	}
1002 
1003 	/**
1004 	 * @return true iff the set of constraints is satisfiable, else false.
1005 	 */
1006 	public boolean isSatisfiable() throws TimeoutException {
1007 		return isSatisfiable(VecInt.EMPTY);
1008 	}
1009 
1010 	/**
1011 	 * @return true iff the set of constraints is satisfiable, else false.
1012 	 */
1013 	public boolean isSatisfiable(boolean global) throws TimeoutException {
1014 		return isSatisfiable(VecInt.EMPTY, global);
1015 	}
1016 
1017 	private double timebegin = 0;
1018 
1019 	private boolean needToReduceDB;
1020 
1021 	private ConflictTimer conflictCount;
1022 
1023 	private transient Timer timer;
1024 
1025 	public boolean isSatisfiable(IVecInt assumps) throws TimeoutException {
1026 		return isSatisfiable(assumps, false);
1027 	}
1028 
1029 	interface LearnedConstraintsDeletionStrategy extends Serializable {
1030 
1031 		void init();
1032 
1033 		ConflictTimer getTimer();
1034 
1035 		void reduce(IVec<Constr> learnedConstrs);
1036 
1037 		void onConflict(Constr outLearnt);
1038 
1039 		void onConflictAnalysis(Constr reason);
1040 	}
1041 
1042 	/**
1043 	 * @since 2.1
1044 	 */
1045 	public LearnedConstraintsDeletionStrategy MEMORY_BASED = new LearnedConstraintsDeletionStrategy() {
1046 
1047 		/**
1048 		 * 
1049 		 */
1050 		private static final long serialVersionUID = 1L;
1051 
1052 		final long memorybound = Runtime.getRuntime().freeMemory() / 10;
1053 
1054 		private final ConflictTimer freeMem = new ConflictTimerAdapter(500) {
1055 			private static final long serialVersionUID = 1L;
1056 
1057 			@Override
1058 			void run() {
1059 				long freemem = Runtime.getRuntime().freeMemory();
1060 				// System.out.println("c Free memory "+freemem);
1061 				if (freemem < memorybound) {
1062 					// Reduce the set of learnt clauses
1063 					needToReduceDB = true;
1064 				}
1065 			}
1066 		};
1067 
1068 		public void reduce(IVec<Constr> learnedConstrs) {
1069 			int i, j;
1070 			for (i = j = 0; i < learnts.size() / 2; i++) {
1071 				Constr c = learnts.get(i);
1072 				if (c.locked() || c.size() == 2) {
1073 					learnts.set(j++, learnts.get(i));
1074 				} else {
1075 					c.remove(Solver.this);
1076 				}
1077 			}
1078 			for (; i < learnts.size(); i++) {
1079 				learnts.set(j++, learnts.get(i));
1080 			}
1081 			System.out.println("c cleaning " + (learnts.size() - j) //$NON-NLS-1$
1082 					+ " clauses out of " + learnts.size()); //$NON-NLS-1$ //$NON-NLS-2$
1083 			learnts.shrinkTo(j);
1084 		}
1085 
1086 		public ConflictTimer getTimer() {
1087 			return freeMem;
1088 		}
1089 
1090 		@Override
1091 		public String toString() {
1092 			return "Memory based learned constraints deletion strategy";
1093 		}
1094 
1095 		public void init() {
1096 			// do nothing
1097 		}
1098 
1099 		public void onConflict(Constr outLearnt) {
1100 			// do nothing
1101 
1102 		}
1103 
1104 		public void onConflictAnalysis(Constr reason) {
1105 			if (reason.learnt())
1106 				claBumpActivity(reason);
1107 		}
1108 	};
1109 
1110 	/**
1111 	 * @since 2.1
1112 	 */
1113 	public LearnedConstraintsDeletionStrategy GLUCOSE = new LearnedConstraintsDeletionStrategy() {
1114 
1115 		/**
1116 		 * 
1117 		 */
1118 		private static final long serialVersionUID = 1L;
1119 		private int[] flags = new int[0];
1120 		private int flag = 0;
1121 
1122 		private final ConflictTimer clauseManagement = new ConflictTimerAdapter(
1123 				500) {
1124 			private static final long serialVersionUID = 1L;
1125 			private int nbconflict = 0;
1126 			private static final int MAX_CLAUSE = 20000;
1127 			private static final int INC_CLAUSE = 500;
1128 			private int nextbound = MAX_CLAUSE;
1129 
1130 			@Override
1131 			void run() {
1132 				nbconflict += INC_CLAUSE;
1133 
1134 				if (nbconflict >= nextbound) {
1135 					nextbound += INC_CLAUSE;
1136 					nbconflict = 0;
1137 					needToReduceDB = true;
1138 				}
1139 			}
1140 		};
1141 
1142 		public void reduce(IVec<Constr> learnedConstrs) {
1143 			int i, j;
1144 			for (i = j = learnedConstrs.size() / 2; i < learnedConstrs.size(); i++) {
1145 				Constr c = learnedConstrs.get(i);
1146 				if (c.locked() || c.getActivity() <= 2.0) {
1147 					learnedConstrs.set(j++, learnts.get(i));
1148 				} else {
1149 					c.remove(Solver.this);
1150 				}
1151 			}
1152 			System.out
1153 					.println("c cleaning " + (learnedConstrs.size() - j) //$NON-NLS-1$
1154 							+ " clauses out of " + learnedConstrs.size() + " with flag " + flag); //$NON-NLS-1$ //$NON-NLS-2$
1155 			learnts.shrinkTo(j);
1156 
1157 		}
1158 
1159 		public ConflictTimer getTimer() {
1160 			return clauseManagement;
1161 		}
1162 
1163 		@Override
1164 		public String toString() {
1165 			return "Glucose learned constraints deletion strategy";
1166 		}
1167 
1168 		public void init() {
1169 			final int howmany = voc.nVars();
1170 			if (flags.length <= howmany) {
1171 				flags = new int[howmany + 1];
1172 			}
1173 
1174 		}
1175 
1176 		public void onConflict(Constr outLearnt) {
1177 			// TODO Auto-generated method stub
1178 			int nblevel = 1;
1179 			flag++;
1180 			int currentLevel;
1181 			for (int i = 1; i < outLearnt.size(); i++) {
1182 				currentLevel = voc.getLevel(outLearnt.get(i));
1183 				if (flags[currentLevel] != flag) {
1184 					flags[currentLevel] = flag;
1185 					nblevel++;
1186 				}
1187 			}
1188 			outLearnt.incActivity(nblevel);
1189 		}
1190 
1191 		public void onConflictAnalysis(Constr reason) {
1192 			// do nothing
1193 		}
1194 	};
1195 
1196 	private LearnedConstraintsDeletionStrategy learnedConstraintsDeletionStrategy = MEMORY_BASED;
1197 
1198 	/**
1199 	 * @param lcds
1200 	 * @since 2.1
1201 	 */
1202 	public void setLearnedConstraintsDeletionStrategy(
1203 			LearnedConstraintsDeletionStrategy lcds) {
1204 		learnedConstraintsDeletionStrategy = lcds;
1205 	}
1206 
1207 	public boolean isSatisfiable(IVecInt assumps, boolean global)
1208 			throws TimeoutException {
1209 		Lbool status = Lbool.UNDEFINED;
1210 
1211 		final int howmany = voc.nVars();
1212 		if (mseen.length <= howmany) {
1213 			mseen = new boolean[howmany + 1];
1214 		}
1215 		trail.ensure(howmany);
1216 		trailLim.ensure(howmany);
1217 		learnedLiterals.ensure(howmany);
1218 		timebegin = System.currentTimeMillis();
1219 		slistener.start();
1220 		model = null; // forget about previous model
1221 		fullmodel = null;
1222 		order.init();
1223 		learnedConstraintsDeletionStrategy.init();
1224 
1225 		int learnedLiteralsLimit = trail.size();
1226 
1227 		// push previously learned literals
1228 		for (IteratorInt iterator = learnedLiterals.iterator(); iterator
1229 				.hasNext();) {
1230 			enqueue(iterator.next());
1231 		}
1232 
1233 		// propagate constraints
1234 		Constr confl = propagate();
1235 		if (confl != null) {
1236 			analyzeAtRootLevel(confl);
1237 			slistener.conflictFound(confl);
1238 			slistener.end(Lbool.FALSE);
1239 			cancelUntil(0);
1240 			cancelLearntLiterals(learnedLiteralsLimit);
1241 			return false;
1242 		}
1243 
1244 		// push incremental assumptions
1245 		for (IteratorInt iterator = assumps.iterator(); iterator.hasNext();) {
1246 			int p = voc.getFromPool(iterator.next());
1247 			if (!assume(p) || ((confl = propagate()) != null)) {
1248 				if (confl == null) {
1249 					slistener.conflictFound(p);
1250 				} else {
1251 					slistener.conflictFound(confl);
1252 				}
1253 				slistener.end(Lbool.FALSE);
1254 				cancelUntil(0);
1255 				cancelLearntLiterals(learnedLiteralsLimit);
1256 				return false;
1257 			}
1258 		}
1259 		rootLevel = decisionLevel();
1260 		// moved initialization here if new literals are added in the
1261 		// assumptions.
1262 		order.init(); // duplicated on purpose
1263 		learner.init();
1264 		restarter.init(params);
1265 
1266 		if (timeBasedTimeout) {
1267 			if (!global || timer == null) {
1268 				TimerTask stopMe = new TimerTask() {
1269 					@Override
1270 					public void run() {
1271 						undertimeout = false;
1272 					}
1273 				};
1274 				timer = new Timer(true);
1275 				timer.schedule(stopMe, timeout);
1276 				conflictCount = learnedConstraintsDeletionStrategy.getTimer();
1277 				undertimeout = true;
1278 			}
1279 		} else {
1280 			if (!global || conflictCount == null) {
1281 				ConflictTimer conflictTimeout = new ConflictTimerAdapter(
1282 						(int) timeout) {
1283 					private static final long serialVersionUID = 1L;
1284 
1285 					@Override
1286 					public void run() {
1287 						undertimeout = false;
1288 					}
1289 				};
1290 				undertimeout = true;
1291 				conflictCount = new ConflictTimerContainer().add(
1292 						conflictTimeout).add(
1293 						learnedConstraintsDeletionStrategy.getTimer());
1294 			}
1295 		}
1296 		needToReduceDB = false;
1297 		// Solve
1298 		while ((status == Lbool.UNDEFINED) && undertimeout) {
1299 			status = search(restarter.nextRestartNumberOfConflict());
1300 			// System.out.println("c speed
1301 			// "+(stats.decisions/((System.currentTimeMillis()-timebegin)/1000))+"
1302 			// dec/s, "+stats.starts+"/"+stats.conflicts);
1303 			restarter.onRestart();
1304 		}
1305 
1306 		cancelUntil(0);
1307 		cancelLearntLiterals(learnedLiteralsLimit);
1308 		if (!global && timeBasedTimeout) {
1309 			timer.cancel();
1310 			timer = null;
1311 		}
1312 		slistener.end(status);
1313 		if (!undertimeout) {
1314 			String message = " Timeout (" + timeout
1315 					+ (timeBasedTimeout ? "s" : " conflicts") + ") exceeded";
1316 			throw new TimeoutException(message); //$NON-NLS-1$//$NON-NLS-2$
1317 		}
1318 		return status == Lbool.TRUE;
1319 	}
1320 
1321 	public void printInfos(PrintWriter out, String prefix) {
1322 		out.print(prefix);
1323 		out.println("constraints type ");
1324 		for (Map.Entry<String, Counter> entry : constrTypes.entrySet()) {
1325 			out.println(prefix + entry.getKey() + " => " + entry.getValue());
1326 		}
1327 	}
1328 
1329 	/**
1330 	 * @since 2.1
1331 	 */
1332 	public void printLearntClausesInfos(PrintWriter out, String prefix) {
1333 		Map<String, Counter> learntTypes = new HashMap<String, Counter>();
1334 		for (Iterator<Constr> it = learnts.iterator(); it.hasNext();) {
1335 			String type = it.next().getClass().getName();
1336 			Counter count = learntTypes.get(type);
1337 			if (count == null) {
1338 				learntTypes.put(type, new Counter());
1339 			} else {
1340 				count.inc();
1341 			}
1342 		}
1343 		out.print(prefix);
1344 		out.println("learnt constraints type ");
1345 		for (Map.Entry<String, Counter> entry : learntTypes.entrySet()) {
1346 			out.println(prefix + entry.getKey() + " => " + entry.getValue());
1347 		}
1348 	}
1349 
1350 	public SolverStats getStats() {
1351 		return stats;
1352 	}
1353 
1354 	public IOrder getOrder() {
1355 		return order;
1356 	}
1357 
1358 	public void setOrder(IOrder h) {
1359 		order = h;
1360 		order.setLits(voc);
1361 	}
1362 
1363 	public ILits getVocabulary() {
1364 		return voc;
1365 	}
1366 
1367 	public void reset() {
1368 		// FIXME verify that cleanup is OK
1369 		voc.resetPool();
1370 		dsfactory.reset();
1371 		constrs.clear();
1372 		learnts.clear();
1373 		stats.reset();
1374 		constrTypes.clear();
1375 	}
1376 
1377 	public int nVars() {
1378 		return voc.nVars();
1379 	}
1380 
1381 	/**
1382 	 * @param constr
1383 	 *            a constraint implementing the Constr interface.
1384 	 * @return a reference to the constraint for external use.
1385 	 */
1386 	protected IConstr addConstr(Constr constr) {
1387 		if (constr != null) {
1388 			constrs.push(constr);
1389 			String type = constr.getClass().getName();
1390 			Counter count = constrTypes.get(type);
1391 			if (count == null) {
1392 				constrTypes.put(type, new Counter());
1393 			} else {
1394 				count.inc();
1395 			}
1396 		}
1397 		return constr;
1398 	}
1399 
1400 	public DataStructureFactory getDSFactory() {
1401 		return dsfactory;
1402 	}
1403 
1404 	public IVecInt getOutLearnt() {
1405 		return outLearnt;
1406 	}
1407 
1408 	/**
1409 	 * returns the ith constraint in the solver.
1410 	 * 
1411 	 * @param i
1412 	 *            the constraint number (begins at 0)
1413 	 * @return the ith constraint
1414 	 */
1415 	public IConstr getIthConstr(int i) {
1416 		return constrs.get(i);
1417 	}
1418 
1419 	/*
1420 	 * (non-Javadoc)
1421 	 * 
1422 	 * @see org.sat4j.specs.ISolver#printStat(java.io.PrintStream,
1423 	 * java.lang.String)
1424 	 */
1425 	public void printStat(PrintStream out, String prefix) {
1426 		printStat(new PrintWriter(out), prefix);
1427 	}
1428 
1429 	public void printStat(PrintWriter out, String prefix) {
1430 		stats.printStat(out, prefix);
1431 		double cputime = (System.currentTimeMillis() - timebegin) / 1000;
1432 		out.println(prefix
1433 				+ "speed (assignments/second)\t: " + stats.propagations //$NON-NLS-1$
1434 				/ cputime);
1435 		order.printStat(out, prefix);
1436 		printLearntClausesInfos(out, prefix);
1437 	}
1438 
1439 	/*
1440 	 * (non-Javadoc)
1441 	 * 
1442 	 * @see java.lang.Object#toString()
1443 	 */
1444 	public String toString(String prefix) {
1445 		StringBuffer stb = new StringBuffer();
1446 		Object[] objs = { analyzer, dsfactory, learner, params, order,
1447 				simplifier, restarter, learnedConstraintsDeletionStrategy };
1448 		stb.append(prefix);
1449 		stb.append("--- Begin Solver configuration ---"); //$NON-NLS-1$
1450 		stb.append("\n"); //$NON-NLS-1$
1451 		for (Object o : objs) {
1452 			stb.append(prefix);
1453 			stb.append(o.toString());
1454 			stb.append("\n"); //$NON-NLS-1$
1455 		}
1456 		stb.append(prefix);
1457 		stb.append("timeout=");
1458 		if (timeBasedTimeout) {
1459 			stb.append(timeout / 1000);
1460 			stb.append("s\n");
1461 		} else {
1462 			stb.append(timeout);
1463 			stb.append(" conflicts\n");
1464 		}
1465 		stb.append(prefix);
1466 		stb.append("DB Simplification allowed=");
1467 		stb.append(isDBSimplificationAllowed);
1468 		stb.append("\n");
1469 		stb.append(prefix);
1470 		stb.append("--- End Solver configuration ---"); //$NON-NLS-1$
1471 		return stb.toString();
1472 	}
1473 
1474 	/*
1475 	 * (non-Javadoc)
1476 	 * 
1477 	 * @see java.lang.Object#toString()
1478 	 */
1479 	@Override
1480 	public String toString() {
1481 		return toString(""); //$NON-NLS-1$
1482 	}
1483 
1484 	public int getTimeout() {
1485 		return (int) (timeBasedTimeout ? timeout / 1000 : timeout);
1486 	}
1487 
1488 	/**
1489 	 * @since 2.1
1490 	 */
1491 	public long getTimeoutMs() {
1492 		if (!timeBasedTimeout) {
1493 			throw new UnsupportedOperationException(
1494 					"The timeout is given in number of conflicts!");
1495 		}
1496 		return timeout;
1497 	}
1498 
1499 	public void setExpectedNumberOfClauses(int nb) {
1500 		constrs.ensure(nb);
1501 	}
1502 
1503 	public Map<String, Number> getStat() {
1504 		return stats.toMap();
1505 	}
1506 
1507 	public int[] findModel() throws TimeoutException {
1508 		if (isSatisfiable()) {
1509 			return model();
1510 		}
1511 		// DLB findbugs ok
1512 		// A zero length array would mean that the formula is a tautology.
1513 		return null;
1514 	}
1515 
1516 	public int[] findModel(IVecInt assumps) throws TimeoutException {
1517 		if (isSatisfiable(assumps)) {
1518 			return model();
1519 		}
1520 		// DLB findbugs ok
1521 		// A zero length array would mean that the formula is a tautology.
1522 		return null;
1523 	}
1524 
1525 	public boolean isDBSimplificationAllowed() {
1526 		return isDBSimplificationAllowed;
1527 	}
1528 
1529 	public void setDBSimplificationAllowed(boolean status) {
1530 		isDBSimplificationAllowed = status;
1531 	}
1532 
1533 	/**
1534 	 * @since 2.1
1535 	 */
1536 	public int nextFreeVarId(boolean reserve) {
1537 		return voc.nextFreeVarId(reserve);
1538 	}
1539 
1540 	/**
1541 	 * @since 2.1
1542 	 */
1543 	public IConstr addBlockingClause(IVecInt literals)
1544 			throws ContradictionException {
1545 		return addClause(literals);
1546 	}
1547 
1548 	/**
1549 	 * @since 2.1
1550 	 */
1551 	public void unset(int p) {
1552 		int current = trail.last();
1553 		while (current != p) {
1554 			undoOne();
1555 			current = trail.last();
1556 		}
1557 		undoOne();
1558 	}
1559 
1560 }
1561 
1562 class ActivityComparator implements Comparator<Constr>, Serializable {
1563 
1564 	private static final long serialVersionUID = 1L;
1565 
1566 	/*
1567 	 * (non-Javadoc)
1568 	 * 
1569 	 * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
1570 	 */
1571 	public int compare(Constr c1, Constr c2) {
1572 		long delta = Math.round(c1.getActivity() - c2.getActivity());
1573 		if (delta == 0) {
1574 			return c1.size() - c2.size();
1575 		}
1576 		return (int) delta;
1577 	}
1578 }
1579 
1580 interface ConflictTimer {
1581 
1582 	void reset();
1583 
1584 	void newConflict();
1585 }
1586 
1587 abstract class ConflictTimerAdapter implements Serializable, ConflictTimer {
1588 
1589 	/**
1590 	 * 
1591 	 */
1592 	private static final long serialVersionUID = 1L;
1593 
1594 	private int counter;
1595 
1596 	private final int bound;
1597 
1598 	ConflictTimerAdapter(final int bound) {
1599 		this.bound = bound;
1600 		counter = 0;
1601 	}
1602 
1603 	public void reset() {
1604 		counter = 0;
1605 	}
1606 
1607 	public void newConflict() {
1608 		counter++;
1609 		if (counter == bound) {
1610 			run();
1611 			counter = 0;
1612 		}
1613 	}
1614 
1615 	abstract void run();
1616 }
1617 
1618 class ConflictTimerContainer implements Serializable, ConflictTimer {
1619 
1620 	/**
1621 	 * 
1622 	 */
1623 	private static final long serialVersionUID = 1L;
1624 
1625 	private final IVec<ConflictTimer> timers = new Vec<ConflictTimer>();
1626 
1627 	ConflictTimerContainer add(ConflictTimer timer) {
1628 		timers.push(timer);
1629 		return this;
1630 	}
1631 
1632 	public void reset() {
1633 		Iterator<ConflictTimer> it = timers.iterator();
1634 		while (it.hasNext()) {
1635 			it.next().reset();
1636 		}
1637 	}
1638 
1639 	public void newConflict() {
1640 		Iterator<ConflictTimer> it = timers.iterator();
1641 		while (it.hasNext()) {
1642 			it.next().newConflict();
1643 		}
1644 	}
1645 }