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.minisat.core.ILits;
33  import org.sat4j.minisat.core.UnitPropagationListener;
34  import org.sat4j.specs.ContradictionException;
35  
36  /**
37   * Data structure for pseudo-boolean constraint with watched literals.
38   * 
39   * All literals are watched. The sum of the literals satisfied or unvalued is
40   * always memorized, to detect conflict.
41   * 
42   * 
43   */
44  
45  public class MinWatchPbLongLimit extends WatchPbLong {
46  	private static final long serialVersionUID = 1L;
47  
48  	/**
49  	 * sum of the coefficients of the literals satisfied or unvalued
50  	 */
51  	protected long watchCumul = 0;
52  
53  	/**
54  	 * if watchCumul is at Long.MAX_VALUE, contains the complement to the sum of
55  	 * the coefficients of the literals satisfied or unvalued
56  	 */
57  	protected long compWatchCumul = 0;
58  
59  	/**
60  	 * is the literal of index i watching the constraint ?
61  	 */
62  	protected boolean[] watched;
63  
64  	/**
65  	 * indexes of literals watching the constraint
66  	 */
67  	protected int[] watching;
68  
69  	/**
70  	 * number of literals watching the constraint.
71  	 * 
72  	 * This is the real size of the array watching
73  	 */
74  	protected int watchingCount = 0;
75  
76  	/**
77  	 * Basic constructor for pb constraint a0.x0 + a1.x1 + ... + an.xn >= k
78  	 * 
79  	 * This constructor is called for learnt pseudo boolean constraints.
80  	 * 
81  	 * @param voc
82  	 *            all the possible variables (vocabulary)
83  	 * @param mpb
84  	 *            a mutable PB constraint
85  	 */
86  	protected MinWatchPbLongLimit(ILits voc, IDataStructurePB mpb) {
87  
88  		super(mpb);
89  		this.voc = voc;
90  
91  		watching = new int[this.coefs.length];
92  		watched = new boolean[this.coefs.length];
93  		activity = 0;
94  		watchCumul = 0;
95  		watchingCount = 0;
96  
97  	}
98  
99  	/**
100 	 * Basic constructor for PB constraint a0.x0 + a1.x1 + ... + an.xn >= k
101 	 * 
102 	 * @param voc
103 	 *            all the possible variables (vocabulary)
104 	 * @param lits
105 	 *            literals of the constraint (x0,x1, ... xn)
106 	 * @param coefs
107 	 *            coefficients of the left side of the constraint (a0, a1, ...
108 	 *            an)
109 	 * @param degree
110 	 *            degree of the constraint (k)
111 	 */
112 	protected MinWatchPbLongLimit(ILits voc, int[] lits, BigInteger[] coefs, // NOPMD
113 			BigInteger degree) {
114 
115 		super(lits, coefs, degree);
116 		this.voc = voc;
117 
118 		watching = new int[this.coefs.length];
119 		watched = new boolean[this.coefs.length];
120 		activity = 0;
121 		watchCumul = 0;
122 		watchingCount = 0;
123 
124 	}
125 
126 	/*
127 	 * This method initialize the watched literals.
128 	 * 
129 	 * This method is only called in the factory methods.
130 	 * 
131 	 * @see org.sat4j.minisat.constraints.WatchPb#computeWatches()
132 	 */
133 	@Override
134 	protected void computeWatches() throws ContradictionException {
135 		assert watchCumul == 0;
136 		assert watchingCount == 0;
137 		for (int i = 0; i < lits.length
138 				&& watchCumulMinusValueIsLessThanDegree(coefs[0]); i++) {
139 			if (!voc.isFalsified(lits[i])) {
140 				voc.watch(lits[i] ^ 1, this);
141 				watching[watchingCount++] = i;
142 				watched[i] = true;
143 				// update the initial value for watchCumul (poss)
144 				addToWC(coefs[i]);
145 			}
146 		}
147 
148 		if (learnt)
149 			watchMoreForLearntConstraint();
150 
151 		if (watchCumul < degree) {
152 			throw new ContradictionException("non satisfiable constraint");
153 		}
154 		assert nbOfWatched() == watchingCount;
155 	}
156 
157 	private void watchMoreForLearntConstraint() {
158 		// looking for literals to be watched,
159 		// ordered by decreasing level
160 		int free = 1;
161 		int maxlevel, maxi, level;
162 
163 		while (watchCumulMinusValueIsLessThanDegree(coefs[0]) && (free > 0)) {
164 			free = 0;
165 			// looking for the literal falsified
166 			// at the least (lowest ?) level
167 			maxlevel = -1;
168 			maxi = -1;
169 			for (int i = 0; i < lits.length; i++) {
170 				if (voc.isFalsified(lits[i]) && !watched[i]) {
171 					free++;
172 					level = voc.getLevel(lits[i]);
173 					if (level > maxlevel) {
174 						maxi = i;
175 						maxlevel = level;
176 					}
177 				}
178 			}
179 
180 			if (free > 0) {
181 				assert maxi >= 0;
182 				voc.watch(lits[maxi] ^ 1, this);
183 				watching[watchingCount++] = maxi;
184 				watched[maxi] = true;
185 				// update of the watchCumul value
186 				addToWC(coefs[maxi]);
187 				free--;
188 				assert free >= 0;
189 			}
190 		}
191 		assert lits.length == 1 || watchingCount > 1;
192 	}
193 
194 	/*
195 	 * This method propagates any possible value.
196 	 * 
197 	 * This method is only called in the factory methods.
198 	 * 
199 	 * @see
200 	 * org.sat4j.minisat.constraints.WatchPb#computePropagation(org.sat4j.minisat
201 	 * .UnitPropagationListener)
202 	 */
203 	@Override
204 	protected void computePropagation(UnitPropagationListener s)
205 			throws ContradictionException {
206 		// propagate any possible value
207 		int ind = 0;
208 		while (ind < lits.length
209 				&& watchCumulMinusValueIsLessThanDegree(coefs[watching[ind]])) {
210 			// (watchCumul - coefs[watching[ind]]) < degree) {
211 			if (voc.isUnassigned(lits[ind]) && !s.enqueue(lits[ind], this)) {
212 				throw new ContradictionException("non satisfiable constraint");
213 			}
214 			ind++;
215 		}
216 	}
217 
218 	/**
219 	 * build a pseudo boolean constraint. Coefficients are positive integers
220 	 * less than or equal to the degree (this is called a normalized
221 	 * constraint).
222 	 * 
223 	 * @param s
224 	 *            a unit propagation listener
225 	 * @param voc
226 	 *            the vocabulary
227 	 * @param lits
228 	 *            the literals
229 	 * @param coefs
230 	 *            the coefficients
231 	 * @param degree
232 	 *            the degree of the constraint to normalize.
233 	 * @return a new PB constraint or null if a trivial inconsistency is
234 	 *         detected.
235 	 */
236 	public static MinWatchPbLongLimit normalizedMinWatchPbNew(
237 			UnitPropagationListener s, ILits voc, int[] lits,
238 			BigInteger[] coefs, BigInteger degree)
239 			throws ContradictionException {
240 		// Parameters must not be modified
241 		MinWatchPbLongLimit outclause = new MinWatchPbLongLimit(voc, lits,
242 				coefs, degree);
243 
244 		if (outclause.degree <= 0) {
245 			return null;
246 		}
247 
248 		outclause.computeWatches();
249 
250 		outclause.computePropagation(s);
251 
252 		return outclause;
253 
254 	}
255 
256 	/**
257 	 * Number of really watched literals. It should return the same value as
258 	 * watchingCount.
259 	 * 
260 	 * This method must only be called for assertions.
261 	 * 
262 	 * @return number of watched literals.
263 	 */
264 	protected int nbOfWatched() {
265 		int retour = 0;
266 		for (int ind = 0; ind < this.watched.length; ind++) {
267 			for (int i = 0; i < watchingCount; i++)
268 				if (watching[i] == ind)
269 					assert watched[ind];
270 			retour += (this.watched[ind]) ? 1 : 0;
271 		}
272 		return retour;
273 	}
274 
275 	/**
276 	 * Propagation of a falsified literal
277 	 * 
278 	 * @param s
279 	 *            the solver
280 	 * @param p
281 	 *            the propagated literal (it must be falsified)
282 	 * @return false iff there is a conflict
283 	 */
284 	public boolean propagate(UnitPropagationListener s, int p) {
285 		assert nbOfWatched() == watchingCount;
286 		assert watchingCount > 1;
287 
288 		// finding the index for p in the array of literals (pIndice)
289 		// and in the array of watching (pIndiceWatching)
290 		int pIndiceWatching = 0;
291 		while (pIndiceWatching < watchingCount
292 				&& (lits[watching[pIndiceWatching]] ^ 1) != p)
293 			pIndiceWatching++;
294 		int pIndice = watching[pIndiceWatching];
295 
296 		assert p == (lits[pIndice] ^ 1);
297 		assert watched[pIndice];
298 
299 		// the greatest coefficient of the watched literals is necessary
300 		// (pIndice excluded)
301 		long maxCoef = maximalCoefficient(pIndice);
302 
303 		// update watching and watched w.r.t. to the propagation of p
304 		// new literals will be watched, maxCoef could be changed
305 		maxCoef = updateWatched(maxCoef, pIndice);
306 
307 		// long upWatchCumul = watchCumul - coefs[pIndice];
308 		assert nbOfWatched() == watchingCount;
309 
310 		// if a conflict has been detected, return false
311 		if (watchCumulMinusValueIsLessThanDegree(coefs[pIndice])) {
312 			// if (watchCumul - coefs[pIndice] < degree) {
313 			// conflit
314 			voc.watch(p, this);
315 			assert watched[pIndice];
316 			assert !isSatisfiable();
317 			return false;
318 		} else {
319 			assert Long.MAX_VALUE - coefs[pIndice] > maxCoef;
320 			if (watchCumulMinusValueIsLessThanDegree(coefs[pIndice] + maxCoef)) {
321 				// some literals must be assigned to true and then propagated
322 				assert watchingCount != 0;
323 				// long limit = upWatchCumul - degree;
324 				// A REVOIR A PARTIR D'ICI
325 				for (int i = 0; i < watchingCount; i++) {
326 					assert Long.MAX_VALUE - coefs[pIndice] > coefs[watching[i]];
327 					// if (watchCumul - coefs[pIndice] - degree <
328 					// coefs[watching[i]]
329 					if (watchCumulMinusValueIsLessThanDegree(coefs[pIndice]
330 							+ coefs[watching[i]])
331 							&& i != pIndiceWatching
332 							&& !voc.isSatisfied(lits[watching[i]])
333 							&& !s.enqueue(lits[watching[i]], this)) {
334 						voc.watch(p, this);
335 						assert !isSatisfiable();
336 						return false;
337 					}
338 				}
339 			}
340 			// if the constraint is added to the undos of p (by propagation),
341 			// then p should be preserved.
342 			voc.undos(p).push(this);
343 		}
344 
345 		// else p is no more watched
346 		watched[pIndice] = false;
347 		substractToWC(coefs[pIndice]);
348 		watching[pIndiceWatching] = watching[--watchingCount];
349 
350 		assert watchingCount != 0;
351 		assert nbOfWatched() == watchingCount;
352 
353 		return true;
354 	}
355 
356 	/**
357 	 * Remove the constraint from the solver
358 	 */
359 	public void remove(UnitPropagationListener upl) {
360 		for (int i = 0; i < watchingCount; i++) {
361 			voc.watches(lits[watching[i]] ^ 1).remove(this);
362 			this.watched[this.watching[i]] = false;
363 		}
364 		watchingCount = 0;
365 		assert nbOfWatched() == watchingCount;
366 		int ind = 0;
367 		while (ind < coefs.length
368 				&& watchCumulMinusValueIsLessThanDegree(coefs[ind])) {
369 			// (watchCumul - coefs[ind]) < degree) {
370 			upl.unset(lits[ind]);
371 			ind++;
372 		}
373 	}
374 
375 	/**
376 	 * this method is called during backtrack
377 	 * 
378 	 * @param p
379 	 *            un unassigned literal
380 	 */
381 	public void undo(int p) {
382 		voc.watch(p, this);
383 		int pIndice = 0;
384 		while ((lits[pIndice] ^ 1) != p)
385 			pIndice++;
386 
387 		assert pIndice < lits.length;
388 
389 		// watchCumul = watchCumul + coefs[pIndice];
390 		addToWC(coefs[pIndice]);
391 
392 		assert watchingCount == nbOfWatched();
393 
394 		watched[pIndice] = true;
395 		watching[watchingCount++] = pIndice;
396 
397 		assert watchingCount == nbOfWatched();
398 	}
399 
400 	/**
401 	 * build a pseudo boolean constraint from a specific data structure. For
402 	 * learnt constraints.
403 	 * 
404 	 * @param s
405 	 *            a unit propagation listener (usually the solver)
406 	 * @param mpb
407 	 *            data structure which contains literals of the constraint,
408 	 *            coefficients (a0, a1, ... an), and the degree of the
409 	 *            constraint (k). The constraint is a "more than" constraint.
410 	 * @return a new PB constraint or null if a trivial inconsistency is
411 	 *         detected.
412 	 */
413 	public static WatchPbLong normalizedWatchPbNew(ILits voc,
414 			IDataStructurePB mpb) {
415 		return new MinWatchPbLong(voc, mpb);
416 	}
417 
418 	/**
419 	 * the maximal coefficient for the watched literals
420 	 * 
421 	 * @param pIndice
422 	 *            propagated literal : its coefficient is excluded from the
423 	 *            search of the maximal coefficient
424 	 * @return the maximal coefficient for the watched literals
425 	 */
426 	protected long maximalCoefficient(int pIndice) {
427 		long maxCoef = 0;
428 		for (int i = 0; i < watchingCount; i++)
429 			if (coefs[watching[i]] > maxCoef && watching[i] != pIndice) {
430 				maxCoef = coefs[watching[i]];
431 			}
432 
433 		assert learnt || maxCoef != 0;
434 		// DLB assert maxCoef!=0;
435 		return maxCoef;
436 	}
437 
438 	/**
439 	 * update arrays watched and watching w.r.t. the propagation of a literal.
440 	 * 
441 	 * return the maximal coefficient of the watched literals (could have been
442 	 * changed).
443 	 * 
444 	 * @param mc
445 	 *            the current maximal coefficient of the watched literals
446 	 * @param pIndice
447 	 *            the literal propagated (falsified)
448 	 * @return the new maximal coefficient of the watched literals
449 	 */
450 	protected long updateWatched(long mc, int pIndice) {
451 		long maxCoef = mc;
452 		// if not all the literals are watched
453 		if (watchingCount < size()) {
454 			// the watchCumul sum will have to be updated
455 			// long upWatchCumul = watchCumul - coefs[pIndice];
456 			long upWatchCumul = 0;
457 			long compUpWatchCumul = 0;
458 			if (compWatchCumul > 0) {
459 				assert watchCumul == Long.MAX_VALUE;
460 				compUpWatchCumul = compWatchCumul - coefs[pIndice];
461 				if (compUpWatchCumul < 0) {
462 					upWatchCumul = Long.MAX_VALUE - compUpWatchCumul;
463 					compUpWatchCumul = 0;
464 				}
465 			} else {
466 				upWatchCumul = watchCumul - coefs[pIndice];
467 			}
468 			// we must obtain upWatchCumul such that
469 			// upWatchCumul = degree + maxCoef
470 			// long degreePlusMaxCoef = degree + maxCoef; // dvh
471 			long degreePlusMaxCoef = 0;
472 			long compDegreePlusMaxCoef = 0;
473 			if (Long.MAX_VALUE - degree < maxCoef) {
474 				degreePlusMaxCoef = Long.MAX_VALUE;
475 				compDegreePlusMaxCoef = maxCoef - (Long.MAX_VALUE - degree);
476 			} else
477 				degreePlusMaxCoef = degree + maxCoef;
478 			for (int ind = 0; ind < lits.length; ind++) {
479 				// if (upWatchCumul >= degreePlusMaxCoef) {
480 				if ((compUpWatchCumul == 0 && compDegreePlusMaxCoef == 0 && upWatchCumul >= degreePlusMaxCoef)
481 						|| (compUpWatchCumul > compDegreePlusMaxCoef)
482 						|| (compUpWatchCumul == compDegreePlusMaxCoef && upWatchCumul == degreePlusMaxCoef)) {
483 					// nothing more to watch
484 					// note: logic negated to old version // dvh
485 					break;
486 				}
487 				// while upWatchCumul does not contain enough
488 				if (!voc.isFalsified(lits[ind]) && !watched[ind]) {
489 					// watch one more
490 					// upWatchCumul = upWatchCumul + coefs[ind];
491 					if (Long.MAX_VALUE - coefs[ind] >= upWatchCumul)
492 						upWatchCumul = upWatchCumul + coefs[ind];
493 					else {
494 						compUpWatchCumul = coefs[ind]
495 								- (Long.MAX_VALUE - upWatchCumul);
496 						upWatchCumul = Long.MAX_VALUE;
497 					}
498 
499 					// update arrays watched and watching
500 					watched[ind] = true;
501 					assert watchingCount < size();
502 					watching[watchingCount++] = ind;
503 					voc.watch(lits[ind] ^ 1, this);
504 					// this new watched literal could change the maximal
505 					// coefficient
506 					if (coefs[ind] > maxCoef) {
507 						maxCoef = coefs[ind];
508 						// degreePlusMaxCoef = degree + maxCoef; // update
509 						compDegreePlusMaxCoef = 0;
510 						if (Long.MAX_VALUE - degree < maxCoef) {
511 							degreePlusMaxCoef = Long.MAX_VALUE;
512 							compDegreePlusMaxCoef = maxCoef
513 									- (Long.MAX_VALUE - degree);
514 						} else
515 							degreePlusMaxCoef = degree + maxCoef;
516 						// that one
517 						// too
518 					}
519 				}
520 			}
521 			// update watchCumul
522 			// watchCumul = upWatchCumul + coefs[pIndice];
523 			watchCumul = upWatchCumul;
524 			compWatchCumul = compUpWatchCumul;
525 			addToWC(coefs[pIndice]);
526 		}
527 		return maxCoef;
528 	}
529 
530 	private boolean watchCumulMinusValueIsLessThanDegree(long coef) {
531 		return ((watchCumul - coef) < degree && watchCumul != Long.MAX_VALUE)
532 				|| (compWatchCumul - coef) > 0
533 				|| ((watchCumul - coef) + compWatchCumul) < degree;
534 	}
535 
536 	private void addToWC(long coef) {
537 		if (Long.MAX_VALUE - coef >= watchCumul)
538 			watchCumul = watchCumul + coef;
539 		else {
540 			compWatchCumul = coef - (Long.MAX_VALUE - watchCumul);
541 			watchCumul = Long.MAX_VALUE;
542 		}
543 	}
544 
545 	private void substractToWC(long coef) {
546 		if (compWatchCumul == 0)
547 			watchCumul = watchCumul - coef;
548 		else {
549 			compWatchCumul = compWatchCumul - coef;
550 			if (compWatchCumul < 0) {
551 				watchCumul = watchCumul - compWatchCumul;
552 				compWatchCumul = 0;
553 			}
554 		}
555 	}
556 
557 }