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