View Javadoc

1   /*
2    * SAT4J: a SATisfiability library for Java Copyright (C) 2004-2006 Daniel Le Berre
3    * 
4    * Based on the original minisat specification from:
5    * 
6    * An extensible SAT solver. Niklas E?n and Niklas S?rensson. Proceedings of the
7    * Sixth International Conference on Theory and Applications of Satisfiability
8    * Testing, LNCS 2919, pp 502-518, 2003.
9    * 
10   * This library is free software; you can redistribute it and/or modify it under
11   * the terms of the GNU Lesser General Public License as published by the Free
12   * Software Foundation; either version 2.1 of the License, or (at your option)
13   * any later version.
14   * 
15   * This library is distributed in the hope that it will be useful, but WITHOUT
16   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17   * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
18   * details.
19   * 
20   * You should have received a copy of the GNU Lesser General Public License
21   * along with this library; if not, write to the Free Software Foundation, Inc.,
22   * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23   * 
24   */
25  package org.sat4j.minisat.constraints.pb;
26  
27  import java.math.BigInteger;
28  import java.util.HashMap;
29  import java.util.Map;
30  
31  import org.sat4j.core.VecInt;
32  import org.sat4j.minisat.constraints.cnf.Lits;
33  import org.sat4j.minisat.core.ILits;
34  import org.sat4j.minisat.core.VarActivityListener;
35  
36  /**
37   * @author parrain TODO To change the template for this generated type comment
38   *         go to Window - Preferences - Java - Code Style - Code Templates
39   */
40  public class ConflictMap extends MapPb implements IConflict {
41  
42  	private final ILits voc;
43  
44  	/**
45  	 * to store the slack of the current resolvant
46  	 */
47  	protected BigInteger currentSlack;
48  
49  	protected int currentLevel;
50  
51  	/**
52  	 * allows to access directly to all variables belonging to a particular
53  	 * level At index 0, unassigned literals are stored (usually level -1); so
54  	 * there is always a step between index and levels.
55  	 */
56  	protected VecInt[] byLevel;
57  
58  	/**
59  	 * constructs the data structure needed to perform cutting planes
60  	 * 
61  	 * @param cpb
62  	 *            pseudo-boolean constraint which rosed the conflict
63  	 * @param level
64  	 *            current decision level
65  	 * @return a conflict on which cutting plane can be performed.
66  	 */
67  	public static IConflict createConflict(PBConstr cpb, int level) {
68  		Map<Integer, BigInteger> m = new HashMap<Integer, BigInteger>();
69  		int lit;
70  		BigInteger coefLit;
71  		for (int i = 0; i < cpb.size(); i++) {
72  			lit = cpb.get(i);
73  			coefLit = cpb.getCoef(i);
74  			assert cpb.get(i) != 0;
75  			assert cpb.getCoef(i).signum() > 0;
76  			m.put(lit, coefLit);
77  		}
78  		return new ConflictMap(m, cpb.getDegree(), cpb.getVocabulary(), level);
79  	}
80  
81  	ConflictMap(Map<Integer, BigInteger> m, BigInteger d, ILits voc, int level) {
82  		super(m, d);
83  		this.voc = voc;
84  		this.currentLevel = level;
85  		initStructures();
86  	}
87  
88  	private void initStructures() {
89  		currentSlack = BigInteger.ZERO;
90  		byLevel = new VecInt[levelToIndex(currentLevel) + 1];
91  		int ilit, litLevel, index;
92  		BigInteger tmp;
93  		for (Integer lit : coefs.keySet()) {
94  			ilit = lit.intValue();
95  			litLevel = voc.getLevel(ilit);
96  			// eventually add to slack
97  			tmp = coefs.get(lit);
98  			if ((tmp.signum() > 0)
99  					&& (((!voc.isFalsified(ilit)) || litLevel == currentLevel)))
100 				currentSlack = currentSlack.add(tmp);
101 			// add to byLevel structure
102 			index = levelToIndex(litLevel);
103 			if (byLevel[index] == null) {
104 				byLevel[index] = new VecInt();
105 			}
106 			byLevel[index].push(ilit);
107 		}
108 	}
109 
110 	/**
111 	 * convert level into an index in the byLevel structure
112 	 * 
113 	 * @param level
114 	 * @return
115 	 */
116 	private static final int levelToIndex(int level) {
117 		return level + 1;
118 	}
119 
120 	/**
121 	 * convert index in the byLevel structure into a level
122 	 * 
123 	 * @param indLevel
124 	 * @return
125 	 */
126 	private static final int indexToLevel(int indLevel) {
127 		return indLevel - 1;
128 	}
129 
130 	/*
131 	 * coefficient to be computed.
132 	 * 
133 	 */
134 	protected BigInteger coefMult = BigInteger.ZERO;
135 
136 	protected BigInteger coefMultCons = BigInteger.ZERO;
137 
138 	/**
139 	 * computes a cutting plane with a pseudo-boolean constraint. this method
140 	 * updates the current instance (of ConflictMap).
141 	 * 
142 	 * @param cpb
143 	 *            constraint to compute with the cutting plane
144 	 * @param litImplied
145 	 *            literal that must be resolved by the cutting plane
146 	 * @return an update of the degree of the current instance
147 	 */
148 	public BigInteger resolve(PBConstr cpb, int litImplied,
149 			VarActivityListener val) {
150 		assert litImplied > 1;
151 		int nLitImplied = litImplied ^ 1;
152 		if (cpb == null || !coefs.containsKey(nLitImplied)) {
153 			// no resolution
154 			// undo operation should be anticipated
155 			int litLevel = levelToIndex(voc.getLevel(litImplied));
156 			int lit = 0;
157 			if (byLevel[litLevel] != null) {
158 				if (byLevel[litLevel].contains(litImplied)) {
159 					lit = litImplied;
160 					assert coefs.containsKey(litImplied);
161 				} else if (byLevel[litLevel].contains(nLitImplied)) {
162 					lit = nLitImplied;
163 					assert coefs.containsKey(nLitImplied);
164 				}
165 			}
166 
167 			if (lit > 0) {
168 				byLevel[litLevel].remove(lit);
169 				if (byLevel[0] == null)
170 					byLevel[0] = new VecInt();
171 				byLevel[0].push(lit);
172 			}
173 			return degree;
174 		}
175 
176 		assert slackConflict().signum() <= 0;
177 		assert degree.signum() >= 0;
178 
179 		// coefficients of the constraint must be copied in an other structure
180 		// in order to make reduction operations.
181 		BigInteger[] coefsCons = null;
182 		BigInteger degreeCons = cpb.getDegree();
183 
184 		// search of the index of the implied literal
185 		int ind = 0;
186 		while (cpb.get(ind) != litImplied)
187 			ind++;
188 
189 		assert cpb.get(ind) == litImplied;
190 		assert cpb.getCoef(ind) != BigInteger.ZERO;
191 
192 		if (cpb.getCoef(ind).equals(BigInteger.ONE)) {
193 			// then we know that the resolvant will still be a conflict (cf.
194 			// Dixon's property)
195 			coefMultCons = coefs.get(nLitImplied);
196 			coefMult = BigInteger.ONE;
197 			// updating of the degree of the conflict
198 			degreeCons = degreeCons.multiply(coefMultCons);
199 		} else {
200 			if (coefs.get(nLitImplied).equals(BigInteger.ONE)) {
201 				// then we know that the resolvant will still be a conflict (cf.
202 				// Dixon's property)
203 				coefMult = cpb.getCoef(ind);
204 				coefMultCons = BigInteger.ONE;
205 				// updating of the degree of the conflict
206 				degree = degree.multiply(coefMult);
207 			} else {
208 				// pb-constraint has to be reduced
209 				// to obtain a conflictual result from the cutting plane
210 				WatchPb wpb = (WatchPb) cpb; // DLB Findbugs warning ok
211 				coefsCons = wpb.getCoefs();
212 				assert positiveCoefs(coefsCons);
213 				degreeCons = reduceUntilConflict(litImplied, ind, coefsCons,
214 						wpb);
215 				// updating of the degree of the conflict
216 				degreeCons = degreeCons.multiply(coefMultCons);
217 				degree = degree.multiply(coefMult);
218 			}
219 			
220 			// coefficients of the conflict must be multiplied by coefMult
221 			if (!coefMult.equals(BigInteger.ONE))
222 				for (Integer i : coefs.keySet()) {
223 					setCoef(i, coefs.get(i).multiply(coefMult));
224 				}
225 		}
226 
227 		assert slackConflict().signum() <= 0;
228 
229 		// cutting plane
230 		degree = cuttingPlane(cpb, degreeCons, coefsCons, coefMultCons, val);
231 
232 		// neither litImplied nor nLitImplied is present in coefs structure
233 		assert !coefs.containsKey(litImplied);
234 		assert !coefs.containsKey(nLitImplied);
235 		// neither litImplied nor nLitImplied is present in byLevel structure
236 		assert getLevelByLevel(litImplied) == -1;
237 		assert getLevelByLevel(nLitImplied) == -1;
238 		assert degree.signum() > 0;
239 		assert slackConflict().signum() <= 0;
240 
241 		// saturation
242 		degree = saturation();
243 		assert slackConflict().signum() <= 0;
244 
245 		return degree;
246 	}
247 
248 	protected BigInteger reduceUntilConflict(int litImplied, int ind,
249 			BigInteger[] reducedCoefs, WatchPb wpb) {
250 		BigInteger slackResolve = BigInteger.ONE.negate();
251 		BigInteger slackThis = BigInteger.ZERO;
252 		BigInteger slackIndex;
253 		BigInteger slackConflict = slackConflict();
254 		BigInteger ppcm;
255 		BigInteger reducedDegree = wpb.getDegree();
256 		BigInteger previousCoefLitImplied = BigInteger.ZERO;
257 		BigInteger tmp;
258 		BigInteger coefLitImplied = coefs.get(litImplied ^ 1);
259 
260 		do {
261 			if (slackResolve.signum() >= 0) {
262 				assert slackThis.signum() > 0;
263 				tmp = reduceInConstraint(wpb, reducedCoefs, ind,
264 						reducedDegree);
265 				assert ((tmp.compareTo(reducedDegree) < 0) && (tmp.compareTo(BigInteger.ONE) >= 0));
266 				reducedDegree = tmp;
267 			}
268 			// search of the multiplying coefficients
269 			assert coefs.get(litImplied ^ 1).signum() > 0;
270 			assert reducedCoefs[ind].signum() > 0;
271 
272 			if (!reducedCoefs[ind].equals(previousCoefLitImplied)) {
273 				assert coefLitImplied.equals(coefs.get(litImplied ^ 1));
274 				ppcm = ppcm(reducedCoefs[ind], coefLitImplied);
275 				assert ppcm.signum() > 0;
276 				coefMult = ppcm.divide(coefLitImplied);
277 				coefMultCons = ppcm.divide(reducedCoefs[ind]);
278 
279 				assert coefMultCons.signum() > 0;
280 				assert coefMult.signum() > 0;
281 				assert coefMult.multiply(coefLitImplied).equals(
282 						coefMultCons.multiply(reducedCoefs[ind]));
283 				previousCoefLitImplied = reducedCoefs[ind];
284 			}
285 
286 			// slacks computed for each constraint
287 			slackThis = wpb.slackConstraint(reducedCoefs, reducedDegree)
288 					.multiply(coefMultCons);
289 			assert slackConflict.equals(slackConflict());
290 			slackIndex = slackConflict.multiply(coefMult);
291 			assert slackIndex.signum() <= 0;
292 			// estimate of the slack after the cutting plane
293 			slackResolve = slackThis.add(slackIndex);
294 		} while (slackResolve.signum() >= 0);
295 		assert coefMult.multiply(coefs.get(litImplied ^ 1)).equals(
296 				coefMultCons.multiply(reducedCoefs[ind]));
297 		return reducedDegree;
298 
299 	}
300 
301 	/**
302 	 * computes the slack of the current instance
303 	 */
304 	public BigInteger slackConflict() {
305 		BigInteger poss = BigInteger.ZERO;
306 		BigInteger tmp;
307 		// for each literal
308 		for (Integer i : coefs.keySet()) {
309 			tmp = coefs.get(i);
310 			if (tmp.signum() != 0 && !voc.isFalsified(i))
311 				poss = poss.add(tmp);
312 		}
313 		return poss.subtract(degree);
314 	}
315 
316 	public boolean oldIsAssertive(int dl) {
317 		BigInteger tmp;
318 		BigInteger slack = computeSlack(dl).subtract(degree);
319 		if (slack.signum() < 0)
320 			return false;
321 		for (Integer i : coefs.keySet()) {
322 			tmp = coefs.get(i);
323 			if ((tmp.signum() > 0)
324 					&& (voc.isUnassigned(i) || voc.getLevel(i) >= dl)
325 					&& (slack.compareTo(tmp) < 0))
326 				return true;
327 		}
328 		return false;
329 	}
330 
331 	// computes a slack with respect to a particular decision level
332 	private BigInteger computeSlack(int dl) {
333 		BigInteger slack = BigInteger.ZERO;
334 		BigInteger tmp;
335 		for (Integer i : coefs.keySet()) {
336 			tmp = coefs.get(i);
337 			if ((tmp.signum() > 0)
338 					&& (((!voc.isFalsified(i)) || voc.getLevel(i) >= dl)))
339 				slack = slack.add(tmp);
340 		}
341 		return slack;
342 	}
343 
344 	/**
345 	 * tests if the conflict is assertive (allows to imply a literal) at a
346 	 * particular decision level
347 	 * 
348 	 * @param dl
349 	 *            the decision level
350 	 * @return true if the conflict is assertive at the decision level
351 	 */
352 	public boolean isAssertive(int dl) {
353 		assert dl <= currentLevel;
354 		assert dl <= currentLevel;
355 
356 		currentLevel = dl;
357 		// assert currentSlack.equals(computeSlack(dl));
358 		BigInteger slack = currentSlack.subtract(degree);
359 		if (slack.signum() < 0)
360 			return false;
361 		return isImplyingLiteral(slack);
362 	}
363 
364 	// given the slack already computed, tests if a literal could be implied at
365 	// a particular level
366 	// uses the byLevel data structure to parse each literal by decision level
367 	private boolean isImplyingLiteral(BigInteger slack) {
368 		// unassigned literals are tried first
369 		int unassigned = levelToIndex(-1);
370 		if (byLevel[unassigned] != null) {
371 			for (Integer lit : byLevel[unassigned])
372 				if (slack.compareTo(coefs.get(lit)) < 0)
373 					return true;
374 		}
375 		// then we have to look at every literal at a decision level >=dl
376 		BigInteger tmp;
377 		int level = levelToIndex(currentLevel);
378 		if (byLevel[level] != null)
379 			for (Integer lit : byLevel[level]) {
380 				tmp = coefs.get(lit);
381 				if (tmp != null && slack.compareTo(tmp) < 0)
382 					return true;
383 			}
384 		return false;
385 	}
386 
387 	// given the slack already computed, tests if a literal could be implied at
388 	// a particular level
389 	// uses the coefs data structure (where coefficients are decreasing ordered) to parse each literal
390 	private boolean isImplyingLiteralOrdered(int dl, BigInteger slack) {
391 		int ilit, litLevel;
392 		for (Integer lit : coefs.keySet()) {
393 			ilit = lit.intValue();
394 			litLevel = voc.getLevel(ilit);
395 //			if (slack.compareTo(coefs.get(lit)) >= 0)
396 //				return false;
397 //			else if (litLevel >= dl || voc.isUnassigned(ilit))
398 //				return true;
399 			if ((litLevel >= dl || voc.isUnassigned(ilit)) && (slack.compareTo(coefs.get(lit)) < 0))
400 				return true;
401 		}
402 		return false;
403 	}
404 
405 	/**
406 	 * computes the least common factor of two integers (Plus Petit Commun
407 	 * Multiple in french)
408 	 * 
409 	 * @param a
410 	 *            first integer
411 	 * @param b
412 	 *            second integer
413 	 * @return the least common factor
414 	 */
415 	protected static BigInteger ppcm(BigInteger a, BigInteger b) {
416 		return a.divide(a.gcd(b)).multiply(b);
417 	}
418 
419 	/**
420 	 * constraint reduction : removes a literal of the constraint. The literal
421 	 * should be either unassigned or satisfied. The literal can not be the
422 	 * literal that should be resolved.
423 	 * 
424 	 * @param wpb
425 	 *            the initial constraint to reduce
426 	 * @param coefsBis
427 	 *            the coefficients of the constraint wrt which the reduction
428 	 *            will be proposed
429 	 * @param indLitImplied
430 	 *            index in wpb of the literal that should be resolved
431 	 * @param degreeBis
432 	 *            the degree of the constraint wrt which the reduction will be
433 	 *            proposed
434 	 * @return new degree of the reduced constraint
435 	 */
436 	public BigInteger reduceInConstraint(WatchPb wpb,
437 			final BigInteger[] coefsBis, final int indLitImplied,
438 			final BigInteger degreeBis) {
439 		// logger.entering(this.getClass().getName(),"reduceInConstraint");
440 		assert degreeBis.compareTo(BigInteger.ONE) > 0;
441 		// search of an unassigned literal
442 		int lit = -1;
443 		for (int ind = 0; (ind < wpb.lits.length) && (lit == -1); ind++)
444 			if (coefsBis[ind].signum() != 0 && voc.isUnassigned(wpb.lits[ind])) {
445 				assert coefsBis[ind].compareTo(degreeBis) < 0;
446 				lit = ind;
447 			}
448 
449 		// else, search of a satisfied literal
450 		if (lit == -1)
451 			for (int ind = 0; (ind < wpb.lits.length) && (lit == -1); ind++)
452 				if ((coefsBis[ind].signum() != 0)
453 						&& (voc.isSatisfied(wpb.lits[ind]))
454 						&& (ind != indLitImplied))
455 					lit = ind;
456 
457 		// a literal has been found
458 		assert lit != -1;
459 
460 		assert lit != indLitImplied;
461 		// logger.finer("Found literal "+Lits.toString(lits[lit]));
462 		// reduction can be done
463 		BigInteger degUpdate = degreeBis.subtract(coefsBis[lit]);
464 		coefsBis[lit] = BigInteger.ZERO;
465 
466 		// saturation of the constraint
467 		degUpdate = saturation(coefsBis, degUpdate);
468 
469 		assert coefsBis[indLitImplied].signum() > 0;
470 		assert degreeBis.compareTo(degUpdate) > 0;
471 		return degUpdate;
472 	}
473 
474 	static BigInteger saturation(BigInteger[] coefs, BigInteger degree) {
475 		assert degree.signum() > 0;
476 		BigInteger minimum = degree;
477 		for (int i = 0; i < coefs.length; i++) {
478 			if (coefs[i].signum() > 0)
479 				minimum = minimum.min(coefs[i]);
480 			coefs[i] = degree.min(coefs[i]);
481 		}
482 		if (minimum.equals(degree) && !degree.equals(BigInteger.ONE)) {
483 			// the result is a clause
484 			// there is no more possible reduction
485 			degree = BigInteger.ONE;
486 			for (int i = 0; i < coefs.length; i++)
487 				if (coefs[i].signum() > 0)
488 					coefs[i] = degree;
489 		}
490 		return degree;
491 	}
492 
493 	private boolean positiveCoefs(final BigInteger[] coefsCons) {
494 		for (int i = 0; i < coefsCons.length; i++) {
495 			if (coefsCons[i].signum() <= 0)
496 				return false;
497 		}
498 		return true;
499 	}
500 
501 	/**
502 	 * computes the level for the backtrack : the highest decision level for
503 	 * which the conflict is assertive.
504 	 * 
505 	 * @param maxLevel
506 	 *            the lowest level for which the conflict is assertive
507 	 * @return the highest level (smaller int) for which the constraint is
508 	 *         assertive.
509 	 */
510 	public int getBacktrackLevel(int maxLevel) {
511 		// we are looking for a level higher than maxLevel
512 		// where the constraint is still assertive
513 		VecInt lits;
514 		int level;
515 		int indStop = levelToIndex(maxLevel) - 1;
516 		int indStart = levelToIndex(0);
517 		BigInteger slack = computeSlack(0).subtract(degree);
518 		int previous = 0;
519 		for (int indLevel = indStart; indLevel <= indStop; indLevel++) {
520 			if (byLevel[indLevel] != null) {
521 				level = indexToLevel(indLevel);
522 				assert computeSlack(level).subtract(degree).equals(slack);
523 				if (isImplyingLiteralOrdered(level, slack)) {
524 					//if (isImplyingLiteral(level, slack)) {
525 					break;
526 				}
527 				// updating the new slack
528 				lits = byLevel[indLevel];
529 				for (Integer lit : lits) {
530 					if (voc.isFalsified(lit)
531 							&& voc.getLevel(lit) == indexToLevel(indLevel))
532 						slack = slack.subtract(coefs.get(lit));
533 				}
534 				if (!lits.isEmpty())
535 					previous = level;
536 			}
537 		}
538 		assert previous == oldGetBacktrackLevel(maxLevel);
539 		// assert previous == retour;
540 		return previous;
541 	}
542 
543 	public int oldGetBacktrackLevel(int maxLevel) {
544 		int litLevel;
545 		int borneMax = maxLevel;
546 		assert oldIsAssertive(borneMax);
547 		int borneMin = -1;
548 		// on calcule borneMax,
549 		// le niveau le plus haut dans l'arbre ou la contrainte est assertive
550 		for (int lit : coefs.keySet()) {
551 			litLevel = voc.getLevel(lit);
552 			if (litLevel < borneMax && litLevel > borneMin
553 					&& oldIsAssertive(litLevel))
554 				borneMax = litLevel;
555 		}
556 		// on retourne le niveau immediatement inferieur ? borneMax
557 		// pour lequel la contrainte possede un literal
558 		int retour = 0;
559 		for (int lit : coefs.keySet()) {
560 			litLevel = voc.getLevel(lit);
561 			if (litLevel > retour && litLevel < borneMax) {
562 				retour = litLevel;
563 			}
564 		}
565 		return retour;
566 	}
567 
568 	public void updateSlack(int level) {
569 		int dl = levelToIndex(level);
570 		if (byLevel[dl] != null)
571 			for (int lit : byLevel[dl]) {
572 				if (voc.isFalsified(lit))
573 					currentSlack = currentSlack.add(coefs.get(lit));
574 			}
575 	}
576 
577 	@Override
578 	void increaseCoef(Integer lit, BigInteger incCoef) {
579 		int ilit = lit.intValue();
580 		if ((!voc.isFalsified(ilit)) || voc.getLevel(ilit) == currentLevel) {
581 			currentSlack = currentSlack.add(incCoef);
582 		}
583 		assert byLevel[levelToIndex(voc.getLevel(ilit))].contains(ilit);
584 		super.increaseCoef(lit, incCoef);
585 	}
586 
587 	@Override
588 	void decreaseCoef(Integer lit, BigInteger decCoef) {
589 		int ilit = lit.intValue();
590 		if ((!voc.isFalsified(ilit)) || voc.getLevel(ilit) == currentLevel) {
591 			currentSlack = currentSlack.subtract(decCoef);
592 		}
593 		assert byLevel[levelToIndex(voc.getLevel(ilit))].contains(ilit);
594 		super.decreaseCoef(lit, decCoef);
595 	}
596 
597 	@Override
598 	void setCoef(Integer lit, BigInteger newValue) {
599 		int ilit = lit.intValue();
600 		int litLevel = voc.getLevel(ilit);
601 		if ((!voc.isFalsified(ilit)) || litLevel == currentLevel) {
602 			if (coefs.containsKey(lit))
603 				currentSlack = currentSlack.subtract(coefs.get(lit));
604 			currentSlack = currentSlack.add(newValue);
605 		}
606 		int indLitLevel = levelToIndex(litLevel);
607 		if (!coefs.containsKey(lit)) {
608 			if (byLevel[indLitLevel] == null) {
609 				byLevel[indLitLevel] = new VecInt();
610 			}
611 			byLevel[indLitLevel].push(ilit);
612 
613 		}
614 		assert byLevel[indLitLevel] != null;
615 		assert byLevel[indLitLevel].contains(ilit);
616 		super.setCoef(lit, newValue);
617 	}
618 
619 	@Override
620 	void removeCoef(Integer lit) {
621 		int ilit = lit.intValue();
622 		int litLevel = voc.getLevel(ilit);
623 		if ((!voc.isFalsified(ilit)) || litLevel == currentLevel) {
624 			currentSlack = currentSlack.subtract(coefs.get(lit));
625 		}
626 
627 		int indLitLevel = levelToIndex(litLevel);
628 		assert indLitLevel < byLevel.length;
629 		assert byLevel[indLitLevel] != null;
630 		assert byLevel[indLitLevel].contains(ilit);
631 		byLevel[indLitLevel].remove(lit);
632 		super.removeCoef(lit);
633 	}
634 
635 	private int getLevelByLevel(int lit) {
636 		for (int i = 0; i < byLevel.length; i++)
637 			if (byLevel[i] != null && byLevel[i].contains(lit))
638 				return i;
639 		return -1;
640 	}
641 
642 	public boolean slackIsCorrect(int dl) {
643 		return currentSlack.equals(computeSlack(dl));
644 	}
645 
646 	@Override
647 	public String toString() {
648 		int lit;
649 		StringBuilder stb = new StringBuilder();
650 		for (Map.Entry<Integer, BigInteger> entry : coefs.entrySet()) {
651 			lit = Integer.valueOf(entry.getKey());
652 			stb.append(entry.getValue());
653 			stb.append(".");
654 			stb.append(Lits.toString(lit));
655 			stb.append(" ");
656 			stb.append("[");
657 			stb.append(voc.valueToString(lit));
658 			stb.append("@");
659 			stb.append(voc.getLevel(lit));
660 			stb.append("]");
661 		}
662 		return stb.toString() + " >= " + degree; //$NON-NLS-1$
663 	}
664 
665 }