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.ConstrGroup;
67  import org.sat4j.core.Vec;
68  import org.sat4j.core.VecInt;
69  import org.sat4j.specs.ContradictionException;
70  import org.sat4j.specs.IConstr;
71  import org.sat4j.specs.ISolver;
72  import org.sat4j.specs.IVec;
73  import org.sat4j.specs.IVecInt;
74  import org.sat4j.specs.IteratorInt;
75  import org.sat4j.specs.Lbool;
76  import org.sat4j.specs.SearchListener;
77  import org.sat4j.specs.TimeoutException;
78  
79  /**
80   * The backbone of the library providing the modular implementation of a MiniSAT
81   * (Chaff) like solver.
82   * 
83   * @author leberre
84   */
85  public class Solver<D extends DataStructureFactory> implements ISolver,
86  		UnitPropagationListener, ActivityListener, Learner {
87  
88  	private static final long serialVersionUID = 1L;
89  
90  	private static final double CLAUSE_RESCALE_FACTOR = 1e-20;
91  
92  	private static final double CLAUSE_RESCALE_BOUND = 1 / CLAUSE_RESCALE_FACTOR;
93  
94  	/**
95  	 * Set of original constraints.
96  	 */
97  	private final IVec<Constr> constrs = new Vec<Constr>(); // Constr
98  
99  	/**
100 	 * Set of learned constraints.
101 	 */
102 	private final IVec<Constr> learnts = new Vec<Constr>(); // Clause
103 
104 	/**
105 	 * incr?ment pour l'activit? des clauses.
106 	 */
107 	private double claInc = 1.0;
108 
109 	/**
110 	 * decay factor pour l'activit? des clauses.
111 	 */
112 	private double claDecay = 1.0;
113 
114 	/**
115 	 * Queue de propagation
116 	 */
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 SolverStats stats = new SolverStats();
150 
151 	private LearningStrategy<D> learner;
152 
153 	protected volatile boolean undertimeout;
154 
155 	private long timeout = Integer.MAX_VALUE;
156 
157 	private boolean timeBasedTimeout = true;
158 
159 	protected D dsfactory;
160 
161 	private SearchParams params;
162 
163 	private final IVecInt __dimacs_out = new VecInt();
164 
165 	private SearchListener slistener = new VoidTracing();
166 
167 	private RestartStrategy restarter;
168 
169 	private final Map<String, Counter> constrTypes = new HashMap<String, Counter>();
170 
171 	private boolean isDBSimplificationAllowed = false;
172 
173 	private final IVecInt learnedLiterals = new VecInt();
174 
175 	private boolean verbose = false;
176 
177 	private String prefix = "c ";
178 	private int declaredMaxVarId = 0;
179 
180 	protected IVecInt dimacs2internal(IVecInt in) {
181 		__dimacs_out.clear();
182 		__dimacs_out.ensure(in.size());
183 		int p;
184 		for (int i = 0; i < in.size(); i++) {
185 			p = in.get(i);
186 			if (p == 0) {
187 				throw new IllegalArgumentException(
188 						"0 is not a valid variable identifier");
189 			}
190 			__dimacs_out.unsafePush(voc.getFromPool(p));
191 		}
192 		return __dimacs_out;
193 	}
194 
195 	/*
196 	 * @since 2.3.1
197 	 */
198 	public void registerLiteral(int p) {
199 		voc.getFromPool(p);
200 	}
201 
202 	/**
203 	 * creates a Solver without LearningListener. A learningListener must be
204 	 * added to the solver, else it won't backtrack!!! A data structure factory
205 	 * must be provided, else it won't work either.
206 	 */
207 
208 	public Solver(LearningStrategy<D> learner, D dsf, IOrder order,
209 			RestartStrategy restarter) {
210 		this(learner, dsf, new SearchParams(), order, restarter);
211 	}
212 
213 	public Solver(LearningStrategy<D> learner, D dsf, SearchParams params,
214 			IOrder order, RestartStrategy restarter) {
215 		this.learner = learner;
216 		this.order = order;
217 		this.params = params;
218 		setDataStructureFactory(dsf);
219 		this.restarter = restarter;
220 	}
221 
222 	/**
223 	 * Change the internal representation of the constraints. Note that the
224 	 * heuristics must be changed prior to calling that method.
225 	 * 
226 	 * @param dsf
227 	 *            the internal factory
228 	 */
229 	public final void setDataStructureFactory(D dsf) {
230 		dsfactory = dsf;
231 		dsfactory.setUnitPropagationListener(this);
232 		dsfactory.setLearner(this);
233 		voc = dsf.getVocabulary();
234 		order.setLits(voc);
235 	}
236 
237 	/**
238 	 * @since 2.2
239 	 */
240 	public boolean isVerbose() {
241 		return verbose;
242 	}
243 
244 	/**
245 	 * @param value
246 	 * @since 2.2
247 	 */
248 	public void setVerbose(boolean value) {
249 		verbose = value;
250 	}
251 
252 	/**
253 	 * @since 2.1
254 	 */
255 	public void setSearchListener(SearchListener sl) {
256 		slistener = sl;
257 	}
258 
259 	/**
260 	 * @since 2.2
261 	 */
262 	public SearchListener getSearchListener() {
263 		return slistener;
264 	}
265 
266 	/**
267 	 * @since 2.2
268 	 */
269 	public void setLearner(LearningStrategy<D> learner) {
270 		this.learner = learner;
271 	}
272 
273 	public void setTimeout(int t) {
274 		timeout = t * 1000L;
275 		timeBasedTimeout = true;
276 	}
277 
278 	public void setTimeoutMs(long t) {
279 		timeout = t;
280 		timeBasedTimeout = true;
281 	}
282 
283 	public void setTimeoutOnConflicts(int count) {
284 		timeout = count;
285 		timeBasedTimeout = false;
286 	}
287 
288 	public void setSearchParams(SearchParams sp) {
289 		params = sp;
290 	}
291 
292 	public void setRestartStrategy(RestartStrategy restarter) {
293 		this.restarter = restarter;
294 	}
295 
296 	public void expireTimeout() {
297 		undertimeout = false;
298 		if (timeBasedTimeout) {
299 			if (timer != null) {
300 				timer.cancel();
301 				timer = null;
302 			}
303 		} else {
304 			if (conflictCount != null) {
305 				conflictCount = null;
306 			}
307 		}
308 	}
309 
310 	protected int nAssigns() {
311 		return trail.size();
312 	}
313 
314 	public int nConstraints() {
315 		return constrs.size();
316 	}
317 
318 	public void learn(Constr c) {
319 		learnts.push(c);
320 		c.setLearnt();
321 		c.register();
322 		stats.learnedclauses++;
323 		switch (c.size()) {
324 		case 2:
325 			stats.learnedbinaryclauses++;
326 			break;
327 		case 3:
328 			stats.learnedternaryclauses++;
329 			break;
330 		default:
331 			// do nothing
332 		}
333 	}
334 
335 	public final int decisionLevel() {
336 		return trailLim.size();
337 	}
338 
339 	@Deprecated
340 	public int newVar() {
341 		int index = voc.nVars() + 1;
342 		voc.ensurePool(index);
343 		return index;
344 	}
345 
346 	public int newVar(int howmany) {
347 		voc.ensurePool(howmany);
348 		declaredMaxVarId = howmany;
349 		return howmany;
350 	}
351 
352 	public IConstr addClause(IVecInt literals) throws ContradictionException {
353 		IVecInt vlits = dimacs2internal(literals);
354 		return addConstr(dsfactory.createClause(vlits));
355 	}
356 
357 	public boolean removeConstr(IConstr co) {
358 		if (co == null) {
359 			throw new IllegalArgumentException(
360 					"Reference to the constraint to remove needed!"); //$NON-NLS-1$
361 		}
362 		Constr c = (Constr) co;
363 		c.remove(this);
364 		constrs.remove(c);
365 		clearLearntClauses();
366 		String type = c.getClass().getName();
367 		constrTypes.get(type).dec();
368 		return true;
369 	}
370 
371 	/**
372 	 * @since 2.1
373 	 */
374 	public boolean removeSubsumedConstr(IConstr co) {
375 		if (co == null) {
376 			throw new IllegalArgumentException(
377 					"Reference to the constraint to remove needed!"); //$NON-NLS-1$
378 		}
379 		if (constrs.last() != co) {
380 			throw new IllegalArgumentException(
381 					"Can only remove latest added constraint!!!"); //$NON-NLS-1$
382 		}
383 		Constr c = (Constr) co;
384 		c.remove(this);
385 		constrs.pop();
386 		String type = c.getClass().getName();
387 		constrTypes.get(type).dec();
388 		return true;
389 	}
390 
391 	public void addAllClauses(IVec<IVecInt> clauses)
392 			throws ContradictionException {
393 		for (Iterator<IVecInt> iterator = clauses.iterator(); iterator
394 				.hasNext();) {
395 			addClause(iterator.next());
396 		}
397 	}
398 
399 	public IConstr addAtMost(IVecInt literals, int degree)
400 			throws ContradictionException {
401 		int n = literals.size();
402 		IVecInt opliterals = new VecInt(n);
403 		for (IteratorInt iterator = literals.iterator(); iterator.hasNext();) {
404 			opliterals.push(-iterator.next());
405 		}
406 		return addAtLeast(opliterals, n - degree);
407 	}
408 
409 	public IConstr addAtLeast(IVecInt literals, int degree)
410 			throws ContradictionException {
411 		IVecInt vlits = dimacs2internal(literals);
412 		return addConstr(dsfactory.createCardinalityConstraint(vlits, degree));
413 	}
414 
415 	public IConstr addExactly(IVecInt literals, int n)
416 			throws ContradictionException {
417 		ConstrGroup group = new ConstrGroup(false);
418 		group.add(addAtMost(literals, n));
419 		group.add(addAtLeast(literals, n));
420 		return group;
421 	}
422 
423 	@SuppressWarnings("unchecked")
424 	public boolean simplifyDB() {
425 		// Simplifie la base de clauses apres la premiere propagation des
426 		// clauses unitaires
427 		IVec<Constr>[] cs = new IVec[] { constrs, learnts };
428 		for (int type = 0; type < 2; type++) {
429 			int j = 0;
430 			for (int i = 0; i < cs[type].size(); i++) {
431 				if (cs[type].get(i).simplify()) {
432 					// enleve les contraintes satisfaites de la base
433 					cs[type].get(i).remove(this);
434 				} else {
435 					cs[type].moveTo(j++, i);
436 				}
437 			}
438 			cs[type].shrinkTo(j);
439 		}
440 		return true;
441 	}
442 
443 	/**
444 	 * Si un mod?le est trouv?, ce vecteur contient le mod?le.
445 	 * 
446 	 * @return un mod?le de la formule.
447 	 */
448 	public int[] model() {
449 		if (model == null) {
450 			throw new UnsupportedOperationException(
451 					"Call the solve method first!!!"); //$NON-NLS-1$
452 		}
453 		int[] nmodel = new int[model.length];
454 		System.arraycopy(model, 0, nmodel, 0, model.length);
455 		return nmodel;
456 	}
457 
458 	/**
459 	 * Satisfait un litt?ral
460 	 * 
461 	 * @param p
462 	 *            le litt?ral
463 	 * @return true si tout se passe bien, false si un conflit appara?t.
464 	 */
465 	public boolean enqueue(int p) {
466 		return enqueue(p, null);
467 	}
468 
469 	/**
470 	 * Put the literal on the queue of assignments to be done.
471 	 * 
472 	 * @param p
473 	 *            the literal.
474 	 * @param from
475 	 *            the reason to propagate that literal, else null
476 	 * @return true if the assignment can be made, false if a conflict is
477 	 *         detected.
478 	 */
479 	public boolean enqueue(int p, Constr from) {
480 		assert p > 1;
481 		if (voc.isSatisfied(p)) {
482 			// literal is already satisfied. Skipping.
483 			return true;
484 		}
485 		if (voc.isFalsified(p)) {
486 			// conflicting enqueued assignment
487 			return false;
488 		}
489 		// new fact, store it
490 		voc.satisfies(p);
491 		voc.setLevel(p, decisionLevel());
492 		voc.setReason(p, from);
493 		trail.push(p);
494 		return true;
495 	}
496 
497 	private boolean[] mseen = new boolean[0];
498 
499 	private final IVecInt mpreason = new VecInt();
500 
501 	private final IVecInt moutLearnt = new VecInt();
502 
503 	/**
504 	 * @throws TimeoutException
505 	 *             if the timeout is reached during conflict analysis.
506 	 */
507 	public void analyze(Constr confl, Pair results) throws TimeoutException {
508 		assert confl != null;
509 
510 		final boolean[] seen = mseen;
511 		final IVecInt outLearnt = moutLearnt;
512 		final IVecInt preason = mpreason;
513 
514 		outLearnt.clear();
515 		assert outLearnt.size() == 0;
516 		for (int i = 0; i < seen.length; i++) {
517 			seen[i] = false;
518 		}
519 
520 		int counter = 0;
521 		int p = ILits.UNDEFINED;
522 
523 		outLearnt.push(ILits.UNDEFINED);
524 		// reserve de la place pour le litteral falsifie
525 		int outBtlevel = 0;
526 		IConstr prevConfl = null;
527 
528 		do {
529 			preason.clear();
530 			assert confl != null;
531 			if (prevConfl != confl) {
532 				confl.calcReason(p, preason);
533 				learnedConstraintsDeletionStrategy.onConflictAnalysis(confl);
534 				// Trace reason for p
535 				for (int j = 0; j < preason.size(); j++) {
536 					int q = preason.get(j);
537 					order.updateVar(q);
538 					if (!seen[q >> 1]) {
539 						seen[q >> 1] = true;
540 						if (voc.getLevel(q) == decisionLevel()) {
541 							counter++;
542 							order.updateVarAtDecisionLevel(q);
543 						} else if (voc.getLevel(q) > 0) {
544 							// only literals assigned after decision level 0
545 							// part of
546 							// the explanation
547 							outLearnt.push(q ^ 1);
548 							outBtlevel = Math.max(outBtlevel, voc.getLevel(q));
549 						}
550 					}
551 				}
552 			}
553 			prevConfl = confl;
554 			// select next reason to look at
555 			do {
556 				p = trail.last();
557 				confl = voc.getReason(p);
558 				undoOne();
559 			} while (!seen[p >> 1]);
560 			// seen[p.var] indique que p se trouve dans outLearnt ou dans
561 			// le dernier niveau de d?cision
562 		} while (--counter > 0);
563 
564 		outLearnt.set(0, p ^ 1);
565 		simplifier.simplify(outLearnt);
566 
567 		Constr c = dsfactory.createUnregisteredClause(outLearnt);
568 		slistener.learn(c);
569 		learnedConstraintsDeletionStrategy.onConflict(c);
570 		results.reason = c;
571 
572 		assert outBtlevel > -1;
573 		results.backtrackLevel = outBtlevel;
574 	}
575 
576 	/**
577 	 * Derive a subset of the assumptions causing the inconistency.
578 	 * 
579 	 * @param confl
580 	 *            the last conflict of the search, occuring at root level.
581 	 * @param assumps
582 	 *            the set of assumption literals
583 	 * @param conflictingLiteral
584 	 *            the literal detected conflicting while propagating
585 	 *            assumptions.
586 	 * @return a subset of assumps causing the inconsistency.
587 	 * @since 2.2
588 	 */
589 	public IVecInt analyzeFinalConflictInTermsOfAssumptions(Constr confl,
590 			IVecInt assumps, int conflictingLiteral) {
591 		if (assumps.size() == 0) {
592 			return null;
593 		}
594 		while (!trailLim.isEmpty() && trailLim.last() == trail.size()) {
595 			// conflict detected when assuming a value
596 			trailLim.pop();
597 		}
598 		final boolean[] seen = mseen;
599 		final IVecInt outLearnt = moutLearnt;
600 		final IVecInt preason = mpreason;
601 
602 		outLearnt.clear();
603 		if (trailLim.size() == 0) {
604 			// conflict detected on unit clauses
605 			return outLearnt;
606 		}
607 
608 		assert outLearnt.size() == 0;
609 		for (int i = 0; i < seen.length; i++) {
610 			seen[i] = false;
611 		}
612 
613 		if (confl == null) {
614 			seen[conflictingLiteral >> 1] = true;
615 		}
616 
617 		int p = ILits.UNDEFINED;
618 		while (confl == null && trail.size() > 0 && trailLim.size() > 0) {
619 			p = trail.last();
620 			confl = voc.getReason(p);
621 			undoOne();
622 			if (confl == null && p == (conflictingLiteral ^ 1)) {
623 				outLearnt.push(toDimacs(p));
624 			}
625 			if (trail.size() <= trailLim.last()) {
626 				trailLim.pop();
627 			}
628 		}
629 		if (confl == null) {
630 			return outLearnt;
631 		}
632 		do {
633 
634 			preason.clear();
635 			confl.calcReason(p, preason);
636 			// Trace reason for p
637 			for (int j = 0; j < preason.size(); j++) {
638 				int q = preason.get(j);
639 				if (!seen[q >> 1]) {
640 					seen[q >> 1] = true;
641 					if (voc.getReason(q) == null && voc.getLevel(q) > 0) {
642 						assert assumps.contains(toDimacs(q));
643 						outLearnt.push(toDimacs(q));
644 					}
645 				}
646 			}
647 
648 			// select next reason to look at
649 			do {
650 				p = trail.last();
651 				confl = voc.getReason(p);
652 				undoOne();
653 				if (decisionLevel() > 0 && trail.size() <= trailLim.last()) {
654 					trailLim.pop();
655 				}
656 			} while (trail.size() > 0 && decisionLevel() > 0
657 					&& (!seen[p >> 1] || confl == null));
658 		} while (decisionLevel() > 0);
659 		return outLearnt;
660 	}
661 
662 	interface ISimplifier extends Serializable {
663 		void simplify(IVecInt outLearnt);
664 	}
665 
666 	public static final ISimplifier NO_SIMPLIFICATION = new ISimplifier() {
667 		/**
668          * 
669          */
670 		private static final long serialVersionUID = 1L;
671 
672 		public void simplify(IVecInt outLearnt) {
673 		}
674 
675 		@Override
676 		public String toString() {
677 			return "No reason simplification"; //$NON-NLS-1$
678 		}
679 	};
680 
681 	public final ISimplifier SIMPLE_SIMPLIFICATION = new ISimplifier() {
682 		/**
683          * 
684          */
685 		private static final long serialVersionUID = 1L;
686 
687 		public void simplify(IVecInt conflictToReduce) {
688 			simpleSimplification(conflictToReduce);
689 		}
690 
691 		@Override
692 		public String toString() {
693 			return "Simple reason simplification"; //$NON-NLS-1$
694 		}
695 	};
696 
697 	public final ISimplifier EXPENSIVE_SIMPLIFICATION = new ISimplifier() {
698 
699 		/**
700          * 
701          */
702 		private static final long serialVersionUID = 1L;
703 
704 		public void simplify(IVecInt conflictToReduce) {
705 			expensiveSimplification(conflictToReduce);
706 		}
707 
708 		@Override
709 		public String toString() {
710 			return "Expensive reason simplification"; //$NON-NLS-1$
711 		}
712 	};
713 
714 	public final ISimplifier EXPENSIVE_SIMPLIFICATION_WLONLY = new ISimplifier() {
715 
716 		/**
717          * 
718          */
719 		private static final long serialVersionUID = 1L;
720 
721 		public void simplify(IVecInt conflictToReduce) {
722 			expensiveSimplificationWLOnly(conflictToReduce);
723 		}
724 
725 		@Override
726 		public String toString() {
727 			return "Expensive reason simplification specific for WL data structure"; //$NON-NLS-1$
728 		}
729 	};
730 
731 	private ISimplifier simplifier = NO_SIMPLIFICATION;
732 
733 	/**
734 	 * Setup the reason simplification strategy. By default, there is no reason
735 	 * simplification. NOTE THAT REASON SIMPLIFICATION DOES NOT WORK WITH
736 	 * SPECIFIC DATA STRUCTURE FOR HANDLING BOTH BINARY AND TERNARY CLAUSES.
737 	 * 
738 	 * @param simp
739 	 *            the name of the simplifier (one of NO_SIMPLIFICATION,
740 	 *            SIMPLE_SIMPLIFICATION, EXPENSIVE_SIMPLIFICATION).
741 	 */
742 	public void setSimplifier(String simp) {
743 		Field f;
744 		try {
745 			f = Solver.class.getDeclaredField(simp);
746 			simplifier = (ISimplifier) f.get(this);
747 		} catch (Exception e) {
748 			e.printStackTrace();
749 			simplifier = NO_SIMPLIFICATION;
750 		}
751 	}
752 
753 	/**
754 	 * Setup the reason simplification strategy. By default, there is no reason
755 	 * simplification. NOTE THAT REASON SIMPLIFICATION IS ONLY ALLOWED FOR WL
756 	 * CLAUSAL data structures. USING REASON SIMPLIFICATION ON CB CLAUSES,
757 	 * CARDINALITY CONSTRAINTS OR PB CONSTRAINTS MIGHT RESULT IN INCORRECT
758 	 * RESULTS.
759 	 * 
760 	 * @param simp
761 	 */
762 	public void setSimplifier(ISimplifier simp) {
763 		simplifier = simp;
764 	}
765 
766 	// MiniSat -- Copyright (c) 2003-2005, Niklas Een, Niklas Sorensson
767 	//
768 	// Permission is hereby granted, free of charge, to any person obtaining a
769 	// copy of this software and associated documentation files (the
770 	// "Software"), to deal in the Software without restriction, including
771 	// without limitation the rights to use, copy, modify, merge, publish,
772 	// distribute, sublicense, and/or sell copies of the Software, and to
773 	// permit persons to whom the Software is furnished to do so, subject to
774 	// the following conditions:
775 	//
776 	// The above copyright notice and this permission notice shall be included
777 	// in all copies or substantial portions of the Software.
778 	//
779 	// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
780 	// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
781 	// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
782 	// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
783 	// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
784 	// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
785 	// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
786 
787 	// Taken from MiniSAT 1.14: Simplify conflict clause (a little):
788 	private void simpleSimplification(IVecInt conflictToReduce) {
789 		int i, j, p;
790 		final boolean[] seen = mseen;
791 		IConstr r;
792 		for (i = j = 1; i < conflictToReduce.size(); i++) {
793 			r = voc.getReason(conflictToReduce.get(i));
794 			if (r == null || r.canBePropagatedMultipleTimes()) {
795 				conflictToReduce.moveTo(j++, i);
796 			} else {
797 				for (int k = 0; k < r.size(); k++) {
798 					p = r.get(k);
799 					if (!seen[p >> 1] && voc.isFalsified(p)
800 							&& (voc.getLevel(p) != 0)) {
801 						conflictToReduce.moveTo(j++, i);
802 						break;
803 					}
804 				}
805 			}
806 		}
807 		conflictToReduce.shrink(i - j);
808 		stats.reducedliterals += (i - j);
809 	}
810 
811 	private final IVecInt analyzetoclear = new VecInt();
812 
813 	private final IVecInt analyzestack = new VecInt();
814 
815 	// Taken from MiniSAT 1.14
816 	private void expensiveSimplification(IVecInt conflictToReduce) {
817 		// Simplify conflict clause (a lot):
818 		//
819 		int i, j;
820 		// (maintain an abstraction of levels involved in conflict)
821 		analyzetoclear.clear();
822 		conflictToReduce.copyTo(analyzetoclear);
823 		for (i = 1, j = 1; i < conflictToReduce.size(); i++)
824 			if (voc.getReason(conflictToReduce.get(i)) == null
825 					|| !analyzeRemovable(conflictToReduce.get(i)))
826 				conflictToReduce.moveTo(j++, i);
827 		conflictToReduce.shrink(i - j);
828 		stats.reducedliterals += (i - j);
829 	}
830 
831 	// Check if 'p' can be removed.' min_level' is used to abort early if
832 	// visiting literals at a level that cannot be removed.
833 	//
834 	private boolean analyzeRemovable(int p) {
835 		assert voc.getReason(p) != null;
836 		ILits lvoc = voc;
837 		IVecInt lanalyzestack = analyzestack;
838 		IVecInt lanalyzetoclear = analyzetoclear;
839 		lanalyzestack.clear();
840 		lanalyzestack.push(p);
841 		final boolean[] seen = mseen;
842 		int top = lanalyzetoclear.size();
843 		while (lanalyzestack.size() > 0) {
844 			int q = lanalyzestack.last();
845 			assert lvoc.getReason(q) != null;
846 			Constr c = lvoc.getReason(q);
847 			lanalyzestack.pop();
848 			if (c.canBePropagatedMultipleTimes()) {
849 				for (int j = top; j < lanalyzetoclear.size(); j++)
850 					seen[lanalyzetoclear.get(j) >> 1] = false;
851 				lanalyzetoclear.shrink(lanalyzetoclear.size() - top);
852 				return false;
853 			}
854 			for (int i = 0; i < c.size(); i++) {
855 				int l = c.get(i);
856 				if (!seen[var(l)] && lvoc.isFalsified(l)
857 						&& lvoc.getLevel(l) != 0) {
858 					if (lvoc.getReason(l) == null) {
859 						for (int j = top; j < lanalyzetoclear.size(); j++)
860 							seen[lanalyzetoclear.get(j) >> 1] = false;
861 						lanalyzetoclear.shrink(lanalyzetoclear.size() - top);
862 						return false;
863 					}
864 					seen[l >> 1] = true;
865 					lanalyzestack.push(l);
866 					lanalyzetoclear.push(l);
867 				}
868 			}
869 
870 		}
871 
872 		return true;
873 	}
874 
875 	// Taken from MiniSAT 1.14
876 	private void expensiveSimplificationWLOnly(IVecInt conflictToReduce) {
877 		// Simplify conflict clause (a lot):
878 		//
879 		int i, j;
880 		// (maintain an abstraction of levels involved in conflict)
881 		analyzetoclear.clear();
882 		conflictToReduce.copyTo(analyzetoclear);
883 		for (i = 1, j = 1; i < conflictToReduce.size(); i++)
884 			if (voc.getReason(conflictToReduce.get(i)) == null
885 					|| !analyzeRemovableWLOnly(conflictToReduce.get(i)))
886 				conflictToReduce.moveTo(j++, i);
887 		conflictToReduce.shrink(i - j);
888 		stats.reducedliterals += (i - j);
889 	}
890 
891 	// Check if 'p' can be removed.' min_level' is used to abort early if
892 	// visiting literals at a level that cannot be removed.
893 	//
894 	private boolean analyzeRemovableWLOnly(int p) {
895 		assert voc.getReason(p) != null;
896 		analyzestack.clear();
897 		analyzestack.push(p);
898 		final boolean[] seen = mseen;
899 		int top = analyzetoclear.size();
900 		while (analyzestack.size() > 0) {
901 			int q = analyzestack.last();
902 			assert voc.getReason(q) != null;
903 			Constr c = voc.getReason(q);
904 			analyzestack.pop();
905 			for (int i = 1; i < c.size(); i++) {
906 				int l = c.get(i);
907 				if (!seen[var(l)] && voc.getLevel(l) != 0) {
908 					if (voc.getReason(l) == null) {
909 						for (int j = top; j < analyzetoclear.size(); j++)
910 							seen[analyzetoclear.get(j) >> 1] = false;
911 						analyzetoclear.shrink(analyzetoclear.size() - top);
912 						return false;
913 					}
914 					seen[l >> 1] = true;
915 					analyzestack.push(l);
916 					analyzetoclear.push(l);
917 				}
918 			}
919 		}
920 
921 		return true;
922 	}
923 
924 	// END Minisat 1.14 cut and paste
925 
926 	/**
927      * 
928      */
929 	protected void undoOne() {
930 		// gather last assigned literal
931 		int p = trail.last();
932 		assert p > 1;
933 		assert voc.getLevel(p) >= 0;
934 		int x = p >> 1;
935 		// unassign variable
936 		voc.unassign(p);
937 		voc.setReason(p, null);
938 		voc.setLevel(p, -1);
939 		// update heuristics value
940 		order.undo(x);
941 		// remove literal from the trail
942 		trail.pop();
943 		// update constraints on backtrack.
944 		// not used if the solver uses watched literals.
945 		IVec<Undoable> undos = voc.undos(p);
946 		assert undos != null;
947 		for (int size = undos.size(); size > 0; size--) {
948 			undos.last().undo(p);
949 			undos.pop();
950 		}
951 	}
952 
953 	/**
954 	 * Propagate activity to a constraint
955 	 * 
956 	 * @param confl
957 	 *            a constraint
958 	 */
959 	public void claBumpActivity(Constr confl) {
960 		confl.incActivity(claInc);
961 		if (confl.getActivity() > CLAUSE_RESCALE_BOUND)
962 			claRescalActivity();
963 		// for (int i = 0; i < confl.size(); i++) {
964 		// varBumpActivity(confl.get(i));
965 		// }
966 	}
967 
968 	public void varBumpActivity(int p) {
969 		order.updateVar(p);
970 	}
971 
972 	private void claRescalActivity() {
973 		for (int i = 0; i < learnts.size(); i++) {
974 			learnts.get(i).rescaleBy(CLAUSE_RESCALE_FACTOR);
975 		}
976 		claInc *= CLAUSE_RESCALE_FACTOR;
977 	}
978 
979 	private final IVec<Propagatable> watched = new Vec<Propagatable>();
980 
981 	/**
982 	 * @return null if not conflict is found, else a conflicting constraint.
983 	 */
984 	public Constr propagate() {
985 		IVec<Propagatable> lwatched = watched;
986 		IVecInt ltrail = trail;
987 		ILits lvoc = voc;
988 		SolverStats lstats = stats;
989 		IOrder lorder = order;
990 		SearchListener lslistener = slistener;
991 		// ltrail.size() changes due to propagation
992 		// cannot cache that value.
993 		while (qhead < ltrail.size()) {
994 			lstats.propagations++;
995 			int p = ltrail.get(qhead++);
996 			lslistener.propagating(toDimacs(p), null);
997 			lorder.assignLiteral(p);
998 			// p is the literal to propagate
999 			// Moved original MiniSAT code to dsfactory to avoid
1000 			// watches manipulation in counter Based clauses for instance.
1001 			assert p > 1;
1002 			lwatched.clear();
1003 			lvoc.watches(p).moveTo(lwatched);
1004 			final int size = lwatched.size();
1005 			for (int i = 0; i < size; i++) {
1006 				lstats.inspects++;
1007 				// try shortcut
1008 				// shortcut = shortcuts.get(i);
1009 				// if (shortcut != ILits.UNDEFINED && voc.isSatisfied(shortcut))
1010 				// {
1011 				// voc.watch(p, watched.get(i), shortcut);
1012 				// stats.shortcuts++;
1013 				// continue;
1014 				// }
1015 				if (!lwatched.get(i).propagate(this, p)) {
1016 					// Constraint is conflicting: copy remaining watches to
1017 					// watches[p]
1018 					// and return constraint
1019 					final int sizew = lwatched.size();
1020 					for (int j = i + 1; j < sizew; j++) {
1021 						lvoc.watch(p, lwatched.get(j));
1022 					}
1023 					qhead = ltrail.size(); // propQ.clear();
1024 					// FIXME enlever le transtypage
1025 					return (Constr) lwatched.get(i);
1026 				}
1027 			}
1028 		}
1029 		return null;
1030 	}
1031 
1032 	void record(Constr constr) {
1033 		constr.assertConstraint(this);
1034 		slistener.adding(toDimacs(constr.get(0)));
1035 		if (constr.size() == 1) {
1036 			stats.learnedliterals++;
1037 		} else {
1038 			learner.learns(constr);
1039 		}
1040 	}
1041 
1042 	/**
1043 	 * @return false ssi conflit imm?diat.
1044 	 */
1045 	public boolean assume(int p) {
1046 		// Precondition: assume propagation queue is empty
1047 		assert trail.size() == qhead;
1048 		assert !trailLim.contains(trail.size());
1049 		trailLim.push(trail.size());
1050 		return enqueue(p);
1051 	}
1052 
1053 	/**
1054 	 * Revert to the state before the last push()
1055 	 */
1056 	private void cancel() {
1057 		// assert trail.size() == qhead || !undertimeout;
1058 		int decisionvar = trail.unsafeGet(trailLim.last());
1059 		slistener.backtracking(toDimacs(decisionvar));
1060 		for (int c = trail.size() - trailLim.last(); c > 0; c--) {
1061 			undoOne();
1062 		}
1063 		trailLim.pop();
1064 	}
1065 
1066 	/**
1067 	 * Restore literals
1068 	 */
1069 	private void cancelLearntLiterals(int learnedLiteralsLimit) {
1070 		learnedLiterals.clear();
1071 		// assert trail.size() == qhead || !undertimeout;
1072 		while (trail.size() > learnedLiteralsLimit) {
1073 			learnedLiterals.push(trail.last());
1074 			undoOne();
1075 		}
1076 		// qhead = 0;
1077 		// learnedLiterals = 0;
1078 	}
1079 
1080 	/**
1081 	 * Cancel several levels of assumptions
1082 	 * 
1083 	 * @param level
1084 	 */
1085 	protected void cancelUntil(int level) {
1086 		while (decisionLevel() > level) {
1087 			cancel();
1088 		}
1089 		qhead = trail.size();
1090 	}
1091 
1092 	private final Pair analysisResult = new Pair();
1093 
1094 	private boolean[] userbooleanmodel;
1095 
1096 	private IVecInt unsatExplanationInTermsOfAssumptions;
1097 
1098 	Lbool search(long nofConflicts, IVecInt assumps) {
1099 		assert rootLevel == decisionLevel();
1100 		stats.starts++;
1101 		int conflictC = 0;
1102 		int backjumpLevel;
1103 
1104 		// varDecay = 1 / params.varDecay;
1105 		order.setVarDecay(1 / params.getVarDecay());
1106 		claDecay = 1 / params.getClaDecay();
1107 
1108 		do {
1109 			slistener.beginLoop();
1110 			// propage les clauses unitaires
1111 			Constr confl = propagate();
1112 			assert trail.size() == qhead;
1113 
1114 			if (confl == null) {
1115 				// No conflict found
1116 				// simpliFYDB() prevents a correct use of
1117 				// constraints removal.
1118 				if (decisionLevel() == 0 && isDBSimplificationAllowed) {
1119 					// // Simplify the set of problem clause
1120 					// // iff rootLevel==0
1121 					stats.rootSimplifications++;
1122 					boolean ret = simplifyDB();
1123 					assert ret;
1124 				}
1125 				// was learnts.size() - nAssigns() > nofLearnts
1126 				// if (nofLearnts.obj >= 0 && learnts.size() > nofLearnts.obj) {
1127 				assert nAssigns() <= voc.realnVars();
1128 				if (nAssigns() == voc.realnVars()) {
1129 					slistener.solutionFound();
1130 					modelFound();
1131 					return Lbool.TRUE;
1132 				}
1133 				if (conflictC >= nofConflicts) {
1134 					// Reached bound on number of conflicts
1135 					// Force a restart
1136 					cancelUntil(rootLevel);
1137 					return Lbool.UNDEFINED;
1138 				}
1139 				if (needToReduceDB) {
1140 					reduceDB();
1141 					needToReduceDB = false;
1142 					// Runtime.getRuntime().gc();
1143 				}
1144 				// New variable decision
1145 				stats.decisions++;
1146 				int p = order.select();
1147 				assert p > 1;
1148 				slistener.assuming(toDimacs(p));
1149 				boolean ret = assume(p);
1150 				assert ret;
1151 			} else {
1152 				// un conflit apparait
1153 				stats.conflicts++;
1154 				conflictC++;
1155 				slistener.conflictFound(confl, decisionLevel(), trail.size());
1156 				conflictCount.newConflict();
1157 
1158 				if (decisionLevel() == rootLevel) {
1159 					// conflict at root level, the formula is inconsistent
1160 					unsatExplanationInTermsOfAssumptions = analyzeFinalConflictInTermsOfAssumptions(
1161 							confl, assumps, ILits.UNDEFINED);
1162 					return Lbool.FALSE;
1163 				}
1164 				// analyze conflict
1165 				try {
1166 					analyze(confl, analysisResult);
1167 				} catch (TimeoutException e) {
1168 					return Lbool.UNDEFINED;
1169 				}
1170 				assert analysisResult.backtrackLevel < decisionLevel();
1171 				backjumpLevel = Math.max(analysisResult.backtrackLevel,
1172 						rootLevel);
1173 				slistener.backjump(backjumpLevel);
1174 				cancelUntil(backjumpLevel);
1175 				if (backjumpLevel == rootLevel) {
1176 					conflictC = 0;
1177 				}
1178 				assert (decisionLevel() >= rootLevel)
1179 						&& (decisionLevel() >= analysisResult.backtrackLevel);
1180 				if (analysisResult.reason == null) {
1181 					return Lbool.FALSE;
1182 				}
1183 				record(analysisResult.reason);
1184 				analysisResult.reason = null;
1185 				decayActivities();
1186 			}
1187 		} while (undertimeout);
1188 		return Lbool.UNDEFINED; // timeout occured
1189 	}
1190 
1191 	protected void analyzeAtRootLevel(Constr conflict) {
1192 	}
1193 
1194 	private final IVecInt implied = new VecInt();
1195 	private final IVecInt decisions = new VecInt();
1196 
1197 	private int[] fullmodel;
1198 
1199 	/**
1200      * 
1201      */
1202 	void modelFound() {
1203 		IVecInt tempmodel = new VecInt(nVars());
1204 		userbooleanmodel = new boolean[realNumberOfVariables()];
1205 		fullmodel = null;
1206 		for (int i = 1; i <= nVars(); i++) {
1207 			if (voc.belongsToPool(i)) {
1208 				int p = voc.getFromPool(i);
1209 				if (!voc.isUnassigned(p)) {
1210 					tempmodel.push(voc.isSatisfied(p) ? i : -i);
1211 					userbooleanmodel[i - 1] = voc.isSatisfied(p);
1212 					if (voc.getReason(p) == null) {
1213 						decisions.push(tempmodel.last());
1214 					} else {
1215 						implied.push(tempmodel.last());
1216 					}
1217 				}
1218 			}
1219 		}
1220 		model = new int[tempmodel.size()];
1221 		tempmodel.copyTo(model);
1222 		if (realNumberOfVariables() > nVars()) {
1223 			for (int i = nVars() + 1; i <= realNumberOfVariables(); i++) {
1224 				if (voc.belongsToPool(i)) {
1225 					int p = voc.getFromPool(i);
1226 					if (!voc.isUnassigned(p)) {
1227 						tempmodel.push(voc.isSatisfied(p) ? i : -i);
1228 						userbooleanmodel[i - 1] = voc.isSatisfied(p);
1229 					}
1230 				}
1231 			}
1232 			fullmodel = new int[tempmodel.size()];
1233 			tempmodel.moveTo(fullmodel);
1234 		}
1235 		cancelUntil(rootLevel);
1236 	}
1237 
1238 	public int[] primeImplicant() {
1239 		IVecInt currentD = new VecInt(decisions.size());
1240 		decisions.copyTo(currentD);
1241 		IVecInt assumptions = new VecInt(implied.size() + decisions.size());
1242 		implied.copyTo(assumptions);
1243 		decisions.copyTo(assumptions);
1244 		IVecInt prime = new VecInt(assumptions.size());
1245 		implied.copyTo(prime);
1246 		for (int i = 0; i < currentD.size(); i++) {
1247 			int p = currentD.get(i);
1248 			assumptions.remove(p);
1249 			assumptions.push(-p);
1250 			try {
1251 				if (isSatisfiable(assumptions)) {
1252 					assumptions.pop();
1253 					assumptions.push(-p);
1254 				} else {
1255 					prime.push(p);
1256 					assumptions.pop();
1257 					assumptions.push(p);
1258 				}
1259 			} catch (TimeoutException e) {
1260 				throw new IllegalStateException("Should not timeout here", e);
1261 			}
1262 		}
1263 		int[] implicant = new int[prime.size()];
1264 		prime.copyTo(implicant);
1265 		return implicant;
1266 	}
1267 
1268 	public boolean model(int var) {
1269 		if (var <= 0 || var > realNumberOfVariables()) {
1270 			throw new IllegalArgumentException(
1271 					"Use a valid Dimacs var id as argument!"); //$NON-NLS-1$
1272 		}
1273 		if (userbooleanmodel == null) {
1274 			throw new UnsupportedOperationException(
1275 					"Call the solve method first!!!"); //$NON-NLS-1$
1276 		}
1277 		return userbooleanmodel[var - 1];
1278 	}
1279 
1280 	public void clearLearntClauses() {
1281 		for (Iterator<Constr> iterator = learnts.iterator(); iterator.hasNext();)
1282 			iterator.next().remove(this);
1283 		learnts.clear();
1284 		learnedLiterals.clear();
1285 	}
1286 
1287 	protected void reduceDB() {
1288 		stats.reduceddb++;
1289 		learnedConstraintsDeletionStrategy.reduce(learnts);
1290 		System.gc();
1291 	}
1292 
1293 	/**
1294 	 * @param learnts
1295 	 */
1296 	private void sortOnActivity() {
1297 		learnts.sort(comparator);
1298 	}
1299 
1300 	/**
1301      * 
1302      */
1303 	protected void decayActivities() {
1304 		order.varDecayActivity();
1305 		claDecayActivity();
1306 	}
1307 
1308 	/**
1309      * 
1310      */
1311 	private void claDecayActivity() {
1312 		claInc *= claDecay;
1313 	}
1314 
1315 	/**
1316 	 * @return true iff the set of constraints is satisfiable, else false.
1317 	 */
1318 	public boolean isSatisfiable() throws TimeoutException {
1319 		return isSatisfiable(VecInt.EMPTY);
1320 	}
1321 
1322 	/**
1323 	 * @return true iff the set of constraints is satisfiable, else false.
1324 	 */
1325 	public boolean isSatisfiable(boolean global) throws TimeoutException {
1326 		return isSatisfiable(VecInt.EMPTY, global);
1327 	}
1328 
1329 	private double timebegin = 0;
1330 
1331 	private boolean needToReduceDB;
1332 
1333 	private ConflictTimer conflictCount;
1334 
1335 	private transient Timer timer;
1336 
1337 	public boolean isSatisfiable(IVecInt assumps) throws TimeoutException {
1338 		return isSatisfiable(assumps, false);
1339 	}
1340 
1341 	interface LearnedConstraintsDeletionStrategy extends Serializable {
1342 
1343 		void init();
1344 
1345 		ConflictTimer getTimer();
1346 
1347 		void reduce(IVec<Constr> learnedConstrs);
1348 
1349 		void onConflict(Constr outLearnt);
1350 
1351 		void onConflictAnalysis(Constr reason);
1352 	}
1353 
1354 	public final LearnedConstraintsDeletionStrategy fixedSize(final int maxsize) {
1355 		return new LearnedConstraintsDeletionStrategy() {
1356 
1357 			private static final long serialVersionUID = 1L;
1358 			private final ConflictTimer aTimer = new ConflictTimerAdapter(
1359 					maxsize) {
1360 
1361 				private static final long serialVersionUID = 1L;
1362 
1363 				@Override
1364 				void run() {
1365 					needToReduceDB = true;
1366 				}
1367 			};
1368 
1369 			public void reduce(IVec<Constr> learnedConstrs) {
1370 				int i, j, k;
1371 				for (i = j = k = 0; i < learnts.size()
1372 						&& learnts.size() - k > maxsize; i++) {
1373 					Constr c = learnts.get(i);
1374 					if (c.locked() || c.size() == 2) {
1375 						learnts.set(j++, learnts.get(i));
1376 					} else {
1377 						c.remove(Solver.this);
1378 						k++;
1379 					}
1380 				}
1381 				for (; i < learnts.size(); i++) {
1382 					learnts.set(j++, learnts.get(i));
1383 				}
1384 				if (verbose) {
1385 					System.out.println(getLogPrefix()
1386 							+ "cleaning " + (learnts.size() - j) //$NON-NLS-1$
1387 							+ " clauses out of " + learnts.size()); //$NON-NLS-1$ //$NON-NLS-2$
1388 					System.out.flush();
1389 				}
1390 				learnts.shrinkTo(j);
1391 			}
1392 
1393 			public void onConflictAnalysis(Constr reason) {
1394 				// TODO Auto-generated method stub
1395 
1396 			}
1397 
1398 			public void onConflict(Constr outLearnt) {
1399 				// TODO Auto-generated method stub
1400 
1401 			}
1402 
1403 			@Override
1404 			public String toString() {
1405 				return "Fixed size (" + maxsize
1406 						+ ") learned constraints deletion strategy";
1407 			}
1408 
1409 			public void init() {
1410 			}
1411 
1412 			public ConflictTimer getTimer() {
1413 				return aTimer;
1414 			}
1415 		};
1416 	}
1417 
1418 	/**
1419 	 * @since 2.1
1420 	 */
1421 	public final LearnedConstraintsDeletionStrategy memory_based = new LearnedConstraintsDeletionStrategy() {
1422 
1423 		private static final long serialVersionUID = 1L;
1424 
1425 		final long memorybound = Runtime.getRuntime().freeMemory() / 10;
1426 
1427 		private final ConflictTimer freeMem = new ConflictTimerAdapter(500) {
1428 			private static final long serialVersionUID = 1L;
1429 
1430 			@Override
1431 			void run() {
1432 				long freemem = Runtime.getRuntime().freeMemory();
1433 				// System.out.println("c Free memory "+freemem);
1434 				if (freemem < memorybound) {
1435 					// Reduce the set of learnt clauses
1436 					needToReduceDB = true;
1437 				}
1438 			}
1439 		};
1440 
1441 		public void reduce(IVec<Constr> learnedConstrs) {
1442 			sortOnActivity();
1443 			int i, j;
1444 			for (i = j = 0; i < learnts.size() / 2; i++) {
1445 				Constr c = learnts.get(i);
1446 				if (c.locked() || c.size() == 2) {
1447 					learnts.set(j++, learnts.get(i));
1448 				} else {
1449 					c.remove(Solver.this);
1450 				}
1451 			}
1452 			for (; i < learnts.size(); i++) {
1453 				learnts.set(j++, learnts.get(i));
1454 			}
1455 			if (verbose) {
1456 				System.out.println(getLogPrefix()
1457 						+ "cleaning " + (learnts.size() - j) //$NON-NLS-1$
1458 						+ " clauses out of " + learnts.size()); //$NON-NLS-1$ //$NON-NLS-2$
1459 				System.out.flush();
1460 			}
1461 			learnts.shrinkTo(j);
1462 		}
1463 
1464 		public ConflictTimer getTimer() {
1465 			return freeMem;
1466 		}
1467 
1468 		@Override
1469 		public String toString() {
1470 			return "Memory based learned constraints deletion strategy";
1471 		}
1472 
1473 		public void init() {
1474 			// do nothing
1475 		}
1476 
1477 		public void onConflict(Constr constr) {
1478 			// do nothing
1479 
1480 		}
1481 
1482 		public void onConflictAnalysis(Constr reason) {
1483 			if (reason.learnt())
1484 				claBumpActivity(reason);
1485 		}
1486 	};
1487 
1488 	/**
1489 	 * @since 2.1
1490 	 */
1491 	public final LearnedConstraintsDeletionStrategy glucose = new LearnedConstraintsDeletionStrategy() {
1492 
1493 		private static final long serialVersionUID = 1L;
1494 		private int[] flags = new int[0];
1495 		private int flag = 0;
1496 		private int wall = 0;
1497 
1498 		private final ConflictTimer clauseManagement = new ConflictTimerAdapter(
1499 				1000) {
1500 			private static final long serialVersionUID = 1L;
1501 			private int nbconflict = 0;
1502 			private static final int MAX_CLAUSE = 5000;
1503 			private static final int INC_CLAUSE = 1000;
1504 			private int nextbound = MAX_CLAUSE;
1505 
1506 			@Override
1507 			void run() {
1508 				nbconflict += bound();
1509 				if (nbconflict >= nextbound) {
1510 					nextbound += INC_CLAUSE;
1511 					if (nextbound > wall) {
1512 						nextbound = wall;
1513 					}
1514 					nbconflict = 0;
1515 					needToReduceDB = true;
1516 				}
1517 			}
1518 
1519 			@Override
1520 			public void reset() {
1521 				super.reset();
1522 				nextbound = MAX_CLAUSE;
1523 				if (nbconflict >= nextbound) {
1524 					nbconflict = 0;
1525 					needToReduceDB = true;
1526 				}
1527 			}
1528 		};
1529 
1530 		public void reduce(IVec<Constr> learnedConstrs) {
1531 			sortOnActivity();
1532 			int i, j;
1533 			for (i = j = learnedConstrs.size() / 2; i < learnedConstrs.size(); i++) {
1534 				Constr c = learnedConstrs.get(i);
1535 				if (c.locked() || c.getActivity() <= 2.0) {
1536 					learnedConstrs.set(j++, learnts.get(i));
1537 				} else {
1538 					c.remove(Solver.this);
1539 				}
1540 			}
1541 			if (verbose) {
1542 				System.out
1543 						.println(getLogPrefix()
1544 								+ "cleaning " + (learnedConstrs.size() - j) //$NON-NLS-1$
1545 								+ " clauses out of " + learnedConstrs.size() + " with flag " + flag + "/" + stats.conflicts); //$NON-NLS-1$ //$NON-NLS-2$
1546 				System.out.flush();
1547 			}
1548 			learnts.shrinkTo(j);
1549 
1550 		}
1551 
1552 		public ConflictTimer getTimer() {
1553 			return clauseManagement;
1554 		}
1555 
1556 		@Override
1557 		public String toString() {
1558 			return "Glucose learned constraints deletion strategy";
1559 		}
1560 
1561 		public void init() {
1562 			final int howmany = voc.nVars();
1563 			wall = constrs.size() > 10000 ? constrs.size() : 10000;
1564 			if (flags.length <= howmany) {
1565 				flags = new int[howmany + 1];
1566 			}
1567 			flag = 0;
1568 			clauseManagement.reset();
1569 		}
1570 
1571 		public void onConflict(Constr constr) {
1572 			int nblevel = 1;
1573 			flag++;
1574 			int currentLevel;
1575 			for (int i = 1; i < constr.size(); i++) {
1576 				currentLevel = voc.getLevel(constr.get(i));
1577 				if (flags[currentLevel] != flag) {
1578 					flags[currentLevel] = flag;
1579 					nblevel++;
1580 				}
1581 			}
1582 			constr.incActivity(nblevel);
1583 		}
1584 
1585 		public void onConflictAnalysis(Constr reason) {
1586 			// do nothing
1587 		}
1588 	};
1589 
1590 	private LearnedConstraintsDeletionStrategy learnedConstraintsDeletionStrategy = glucose;
1591 
1592 	/**
1593 	 * @param lcds
1594 	 * @since 2.1
1595 	 */
1596 	public void setLearnedConstraintsDeletionStrategy(
1597 			LearnedConstraintsDeletionStrategy lcds) {
1598 		learnedConstraintsDeletionStrategy = lcds;
1599 	}
1600 
1601 	public boolean isSatisfiable(IVecInt assumps, boolean global)
1602 			throws TimeoutException {
1603 		Lbool status = Lbool.UNDEFINED;
1604 		final int howmany = voc.nVars();
1605 		if (mseen.length <= howmany) {
1606 			mseen = new boolean[howmany + 1];
1607 		}
1608 		trail.ensure(howmany);
1609 		trailLim.ensure(howmany);
1610 		learnedLiterals.ensure(howmany);
1611 		decisions.clear();
1612 		implied.clear();
1613 		slistener.start();
1614 		model = null; // forget about previous model
1615 		userbooleanmodel = null;
1616 		unsatExplanationInTermsOfAssumptions = null;
1617 		order.init();
1618 		learnedConstraintsDeletionStrategy.init();
1619 		int learnedLiteralsLimit = trail.size();
1620 
1621 		// Fix for Bug SAT37
1622 		qhead = 0;
1623 		// Apply undos on unit literals because they are getting propagated
1624 		// again now that qhead is 0.
1625 		for (int i = learnedLiteralsLimit - 1; i >= 0; i--) {
1626 			int p = trail.get(i);
1627 			IVec<Undoable> undos = voc.undos(p);
1628 			assert undos != null;
1629 			for (int size = undos.size(); size > 0; size--) {
1630 				undos.last().undo(p);
1631 				undos.pop();
1632 			}
1633 		}
1634 
1635 		// push previously learned literals
1636 		for (IteratorInt iterator = learnedLiterals.iterator(); iterator
1637 				.hasNext();) {
1638 			enqueue(iterator.next());
1639 		}
1640 
1641 		// propagate constraints
1642 		Constr confl = propagate();
1643 		if (confl != null) {
1644 			analyzeAtRootLevel(confl);
1645 			slistener.conflictFound(confl, 0, 0);
1646 			slistener.end(Lbool.FALSE);
1647 			cancelUntil(0);
1648 			cancelLearntLiterals(learnedLiteralsLimit);
1649 			return false;
1650 		}
1651 
1652 		// push incremental assumptions
1653 		for (IteratorInt iterator = assumps.iterator(); iterator.hasNext();) {
1654 			int assump = iterator.next();
1655 			int p = voc.getFromPool(assump);
1656 			if ((!voc.isSatisfied(p) && !assume(p))
1657 					|| ((confl = propagate()) != null)) {
1658 				if (confl == null) {
1659 					slistener.conflictFound(p);
1660 					unsatExplanationInTermsOfAssumptions = analyzeFinalConflictInTermsOfAssumptions(
1661 							null, assumps, p);
1662 					unsatExplanationInTermsOfAssumptions.push(assump);
1663 				} else {
1664 					slistener.conflictFound(confl, decisionLevel(),
1665 							trail.size());
1666 					unsatExplanationInTermsOfAssumptions = analyzeFinalConflictInTermsOfAssumptions(
1667 							confl, assumps, ILits.UNDEFINED);
1668 				}
1669 
1670 				slistener.end(Lbool.FALSE);
1671 				cancelUntil(0);
1672 				cancelLearntLiterals(learnedLiteralsLimit);
1673 				return false;
1674 			}
1675 		}
1676 		rootLevel = decisionLevel();
1677 		// moved initialization here if new literals are added in the
1678 		// assumptions.
1679 		order.init(); // duplicated on purpose
1680 		learner.init();
1681 
1682 		boolean firstTimeGlobal = false;
1683 		if (timeBasedTimeout) {
1684 			if (!global || timer == null) {
1685 				firstTimeGlobal = true;
1686 				undertimeout = true;
1687 				TimerTask stopMe = new TimerTask() {
1688 					@Override
1689 					public void run() {
1690 						undertimeout = false;
1691 					}
1692 				};
1693 				timer = new Timer(true);
1694 				timer.schedule(stopMe, timeout);
1695 				conflictCount = learnedConstraintsDeletionStrategy.getTimer();
1696 			}
1697 		} else {
1698 			if (!global || conflictCount == null) {
1699 				firstTimeGlobal = true;
1700 				undertimeout = true;
1701 				ConflictTimer conflictTimeout = new ConflictTimerAdapter(
1702 						(int) timeout) {
1703 					private static final long serialVersionUID = 1L;
1704 
1705 					@Override
1706 					public void run() {
1707 						undertimeout = false;
1708 					}
1709 				};
1710 				conflictCount = new ConflictTimerContainer().add(
1711 						conflictTimeout).add(
1712 						learnedConstraintsDeletionStrategy.getTimer());
1713 			}
1714 		}
1715 		if (!global || firstTimeGlobal) {
1716 			restarter.init(params);
1717 			timebegin = System.currentTimeMillis();
1718 		}
1719 		needToReduceDB = false;
1720 		// Solve
1721 		while ((status == Lbool.UNDEFINED) && undertimeout) {
1722 			status = search(restarter.nextRestartNumberOfConflict(), assumps);
1723 			if (status == Lbool.UNDEFINED) {
1724 				restarter.onRestart();
1725 				slistener.restarting();
1726 			}
1727 		}
1728 
1729 		cancelUntil(0);
1730 		cancelLearntLiterals(learnedLiteralsLimit);
1731 		if (!global && timeBasedTimeout) {
1732 			timer.cancel();
1733 			timer = null;
1734 		}
1735 		slistener.end(status);
1736 		if (!undertimeout) {
1737 			String message = " Timeout (" + timeout
1738 					+ (timeBasedTimeout ? "s" : " conflicts") + ") exceeded";
1739 			throw new TimeoutException(message); //$NON-NLS-1$//$NON-NLS-2$
1740 		}
1741 		return status == Lbool.TRUE;
1742 	}
1743 
1744 	public void printInfos(PrintWriter out, String prefix) {
1745 		out.print(prefix);
1746 		out.println("constraints type ");
1747 		long total = 0;
1748 		for (Map.Entry<String, Counter> entry : constrTypes.entrySet()) {
1749 			out.println(prefix + entry.getKey() + " => " + entry.getValue());
1750 			total += entry.getValue().getValue();
1751 		}
1752 		out.print(prefix);
1753 		out.print(total);
1754 		out.println(" constraints processed.");
1755 	}
1756 
1757 	/**
1758 	 * @since 2.1
1759 	 */
1760 	public void printLearntClausesInfos(PrintWriter out, String prefix) {
1761 		Map<String, Counter> learntTypes = new HashMap<String, Counter>();
1762 		for (Iterator<Constr> it = learnts.iterator(); it.hasNext();) {
1763 			String type = it.next().getClass().getName();
1764 			Counter count = learntTypes.get(type);
1765 			if (count == null) {
1766 				learntTypes.put(type, new Counter());
1767 			} else {
1768 				count.inc();
1769 			}
1770 		}
1771 		out.print(prefix);
1772 		out.println("learnt constraints type ");
1773 		for (Map.Entry<String, Counter> entry : learntTypes.entrySet()) {
1774 			out.println(prefix + entry.getKey() + " => " + entry.getValue());
1775 		}
1776 	}
1777 
1778 	public SolverStats getStats() {
1779 		return stats;
1780 	}
1781 
1782 	/**
1783 	 * 
1784 	 * @param myStats
1785 	 * @since 2.2
1786 	 */
1787 	protected void initStats(SolverStats myStats) {
1788 		this.stats = myStats;
1789 	}
1790 
1791 	public IOrder getOrder() {
1792 		return order;
1793 	}
1794 
1795 	public void setOrder(IOrder h) {
1796 		order = h;
1797 		order.setLits(voc);
1798 	}
1799 
1800 	public ILits getVocabulary() {
1801 		return voc;
1802 	}
1803 
1804 	public void reset() {
1805 		trail.clear();
1806 		trailLim.clear();
1807 		qhead = 0;
1808 		for (Iterator<Constr> iterator = constrs.iterator(); iterator.hasNext();)
1809 			iterator.next().remove(this);
1810 		constrs.clear();
1811 		clearLearntClauses();
1812 		voc.resetPool();
1813 		dsfactory.reset();
1814 		stats.reset();
1815 		constrTypes.clear();
1816 	}
1817 
1818 	public int nVars() {
1819 		if (declaredMaxVarId == 0) {
1820 			return voc.nVars();
1821 		}
1822 		return declaredMaxVarId;
1823 	}
1824 
1825 	/**
1826 	 * @param constr
1827 	 *            a constraint implementing the Constr interface.
1828 	 * @return a reference to the constraint for external use.
1829 	 */
1830 	protected IConstr addConstr(Constr constr) {
1831 		if (constr == null) {
1832 			Counter count = constrTypes.get("ignored satisfied constraints");
1833 			if (count == null) {
1834 				constrTypes.put("ignored satisfied constraints", new Counter());
1835 			} else {
1836 				count.inc();
1837 			}
1838 		} else {
1839 			constrs.push(constr);
1840 			String type = constr.getClass().getName();
1841 			Counter count = constrTypes.get(type);
1842 			if (count == null) {
1843 				constrTypes.put(type, new Counter());
1844 			} else {
1845 				count.inc();
1846 			}
1847 		}
1848 		return constr;
1849 	}
1850 
1851 	public DataStructureFactory getDSFactory() {
1852 		return dsfactory;
1853 	}
1854 
1855 	public IVecInt getOutLearnt() {
1856 		return moutLearnt;
1857 	}
1858 
1859 	/**
1860 	 * returns the ith constraint in the solver.
1861 	 * 
1862 	 * @param i
1863 	 *            the constraint number (begins at 0)
1864 	 * @return the ith constraint
1865 	 */
1866 	public IConstr getIthConstr(int i) {
1867 		return constrs.get(i);
1868 	}
1869 
1870 	/*
1871 	 * (non-Javadoc)
1872 	 * 
1873 	 * @see org.sat4j.specs.ISolver#printStat(java.io.PrintStream,
1874 	 * java.lang.String)
1875 	 */
1876 	public void printStat(PrintStream out, String prefix) {
1877 		printStat(new PrintWriter(out, true), prefix);
1878 	}
1879 
1880 	public void printStat(PrintWriter out, String prefix) {
1881 		stats.printStat(out, prefix);
1882 		double cputime = (System.currentTimeMillis() - timebegin) / 1000;
1883 		out.println(prefix
1884 				+ "speed (assignments/second)\t: " + stats.propagations //$NON-NLS-1$
1885 				/ cputime);
1886 		order.printStat(out, prefix);
1887 		printLearntClausesInfos(out, prefix);
1888 	}
1889 
1890 	/*
1891 	 * (non-Javadoc)
1892 	 * 
1893 	 * @see java.lang.Object#toString()
1894 	 */
1895 	public String toString(String prefix) {
1896 		StringBuffer stb = new StringBuffer();
1897 		Object[] objs = { dsfactory, learner, params, order, simplifier,
1898 				restarter, learnedConstraintsDeletionStrategy };
1899 		stb.append(prefix);
1900 		stb.append("--- Begin Solver configuration ---"); //$NON-NLS-1$
1901 		stb.append("\n"); //$NON-NLS-1$
1902 		for (Object o : objs) {
1903 			stb.append(prefix);
1904 			stb.append(o.toString());
1905 			stb.append("\n"); //$NON-NLS-1$
1906 		}
1907 		stb.append(prefix);
1908 		stb.append("timeout=");
1909 		if (timeBasedTimeout) {
1910 			stb.append(timeout / 1000);
1911 			stb.append("s\n");
1912 		} else {
1913 			stb.append(timeout);
1914 			stb.append(" conflicts\n");
1915 		}
1916 		stb.append(prefix);
1917 		stb.append("DB Simplification allowed=");
1918 		stb.append(isDBSimplificationAllowed);
1919 		stb.append("\n");
1920 		stb.append(prefix);
1921 		stb.append("--- End Solver configuration ---"); //$NON-NLS-1$
1922 		return stb.toString();
1923 	}
1924 
1925 	/*
1926 	 * (non-Javadoc)
1927 	 * 
1928 	 * @see java.lang.Object#toString()
1929 	 */
1930 	@Override
1931 	public String toString() {
1932 		return toString(""); //$NON-NLS-1$
1933 	}
1934 
1935 	public int getTimeout() {
1936 		return (int) (timeBasedTimeout ? timeout / 1000 : timeout);
1937 	}
1938 
1939 	/**
1940 	 * @since 2.1
1941 	 */
1942 	public long getTimeoutMs() {
1943 		if (!timeBasedTimeout) {
1944 			throw new UnsupportedOperationException(
1945 					"The timeout is given in number of conflicts!");
1946 		}
1947 		return timeout;
1948 	}
1949 
1950 	public void setExpectedNumberOfClauses(int nb) {
1951 		constrs.ensure(nb);
1952 	}
1953 
1954 	public Map<String, Number> getStat() {
1955 		return stats.toMap();
1956 	}
1957 
1958 	public int[] findModel() throws TimeoutException {
1959 		if (isSatisfiable()) {
1960 			return model();
1961 		}
1962 		// DLB findbugs ok
1963 		// A zero length array would mean that the formula is a tautology.
1964 		return null;
1965 	}
1966 
1967 	public int[] findModel(IVecInt assumps) throws TimeoutException {
1968 		if (isSatisfiable(assumps)) {
1969 			return model();
1970 		}
1971 		// DLB findbugs ok
1972 		// A zero length array would mean that the formula is a tautology.
1973 		return null;
1974 	}
1975 
1976 	public boolean isDBSimplificationAllowed() {
1977 		return isDBSimplificationAllowed;
1978 	}
1979 
1980 	public void setDBSimplificationAllowed(boolean status) {
1981 		isDBSimplificationAllowed = status;
1982 	}
1983 
1984 	/**
1985 	 * @since 2.1
1986 	 */
1987 	public int nextFreeVarId(boolean reserve) {
1988 		return voc.nextFreeVarId(reserve);
1989 	}
1990 
1991 	/**
1992 	 * @since 2.1
1993 	 */
1994 	public IConstr addBlockingClause(IVecInt literals)
1995 			throws ContradictionException {
1996 		return addClause(literals);
1997 	}
1998 
1999 	/**
2000 	 * @since 2.1
2001 	 */
2002 	public void unset(int p) {
2003 		// the literal might already have been
2004 		// removed from the trail.
2005 		if (voc.isUnassigned(p) || trail.isEmpty()) {
2006 			return;
2007 		}
2008 		int current = trail.last();
2009 		while (current != p) {
2010 			undoOne();
2011 			if (trail.isEmpty()) {
2012 				return;
2013 			}
2014 			current = trail.last();
2015 		}
2016 		undoOne();
2017 		qhead = trail.size();
2018 	}
2019 
2020 	/**
2021 	 * @since 2.2
2022 	 */
2023 	public void setLogPrefix(String prefix) {
2024 		this.prefix = prefix;
2025 	}
2026 
2027 	/**
2028 	 * @since 2.2
2029 	 */
2030 	public String getLogPrefix() {
2031 		return prefix;
2032 	}
2033 
2034 	/**
2035 	 * @since 2.2
2036 	 */
2037 	public IVecInt unsatExplanation() {
2038 		IVecInt copy = new VecInt(unsatExplanationInTermsOfAssumptions.size());
2039 		unsatExplanationInTermsOfAssumptions.copyTo(copy);
2040 		return copy;
2041 	}
2042 
2043 	/**
2044 	 * @since 2.3.1
2045 	 */
2046 	public int[] modelWithInternalVariables() {
2047 		if (model == null) {
2048 			throw new UnsupportedOperationException(
2049 					"Call the solve method first!!!"); //$NON-NLS-1$
2050 		}
2051 		int[] nmodel;
2052 		if (nVars() == realNumberOfVariables()) {
2053 			nmodel = new int[model.length];
2054 			System.arraycopy(model, 0, nmodel, 0, nmodel.length);
2055 		} else {
2056 			nmodel = new int[fullmodel.length];
2057 			System.arraycopy(fullmodel, 0, nmodel, 0, nmodel.length);
2058 		}
2059 
2060 		return nmodel;
2061 	}
2062 
2063 	/**
2064 	 * @since 2.3.1
2065 	 */
2066 	public int realNumberOfVariables() {
2067 		return voc.nVars();
2068 	}
2069 
2070 }
2071 
2072 class ActivityComparator implements Comparator<Constr>, Serializable {
2073 
2074 	private static final long serialVersionUID = 1L;
2075 
2076 	/*
2077 	 * (non-Javadoc)
2078 	 * 
2079 	 * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
2080 	 */
2081 	public int compare(Constr c1, Constr c2) {
2082 		long delta = Math.round(c1.getActivity() - c2.getActivity());
2083 		if (delta == 0) {
2084 			return c1.size() - c2.size();
2085 		}
2086 		return (int) delta;
2087 	}
2088 }
2089 
2090 interface ConflictTimer {
2091 
2092 	void reset();
2093 
2094 	void newConflict();
2095 }
2096 
2097 abstract class ConflictTimerAdapter implements Serializable, ConflictTimer {
2098 
2099 	/**
2100 	 * 
2101 	 */
2102 	private static final long serialVersionUID = 1L;
2103 
2104 	private int counter;
2105 
2106 	private final int bound;
2107 
2108 	ConflictTimerAdapter(final int bound) {
2109 		this.bound = bound;
2110 		counter = 0;
2111 	}
2112 
2113 	public void reset() {
2114 		counter = 0;
2115 	}
2116 
2117 	public void newConflict() {
2118 		counter++;
2119 		if (counter == bound) {
2120 			run();
2121 			counter = 0;
2122 		}
2123 	}
2124 
2125 	abstract void run();
2126 
2127 	public int bound() {
2128 		return bound;
2129 	}
2130 }
2131 
2132 class ConflictTimerContainer implements Serializable, ConflictTimer {
2133 
2134 	/**
2135 	 * 
2136 	 */
2137 	private static final long serialVersionUID = 1L;
2138 
2139 	private final IVec<ConflictTimer> timers = new Vec<ConflictTimer>();
2140 
2141 	ConflictTimerContainer add(ConflictTimer timer) {
2142 		timers.push(timer);
2143 		return this;
2144 	}
2145 
2146 	public void reset() {
2147 		Iterator<ConflictTimer> it = timers.iterator();
2148 		while (it.hasNext()) {
2149 			it.next().reset();
2150 		}
2151 	}
2152 
2153 	public void newConflict() {
2154 		Iterator<ConflictTimer> it = timers.iterator();
2155 		while (it.hasNext()) {
2156 			it.next().newConflict();
2157 		}
2158 	}
2159 }