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.io.Serializable;
31  import java.math.BigInteger;
32  
33  import org.sat4j.core.VecInt;
34  import org.sat4j.minisat.constraints.cnf.Lits;
35  import org.sat4j.minisat.core.ILits;
36  import org.sat4j.minisat.core.Undoable;
37  import org.sat4j.minisat.core.UnitPropagationListener;
38  import org.sat4j.specs.ContradictionException;
39  import org.sat4j.specs.IVecInt;
40  
41  /**
42   * Abstract data structure for pseudo-boolean constraint with watched literals.
43   * 
44   * @author anne
45   * 
46   */
47  public abstract class WatchPb implements IWatchPb, Undoable, Serializable {
48  
49  	/**
50  	 * 
51  	 */
52  	private static final long serialVersionUID = 1L;
53  
54  	/**
55  	 * constraint activity
56  	 */
57  	protected double activity;
58  
59  	/**
60  	 * coefficients of the literals of the constraint
61  	 */
62  	protected BigInteger[] coefs;
63  
64  	/**
65  	 * degree of the pseudo-boolean constraint
66  	 */
67  	protected BigInteger degree;
68  
69  	/**
70  	 * literals of the constraint
71  	 */
72  	protected int[] lits;
73  
74  	/**
75  	 * true if the constraint is a learned constraint
76  	 */
77  	protected boolean learnt = false;
78  
79  	/**
80  	 * constraint's vocabulary
81  	 */
82  	protected ILits voc;
83  
84  	/**
85  	 * This constructor is only available for the serialization.
86  	 */
87  	WatchPb() {
88  	}
89  
90  	WatchPb(IDataStructurePB mpb) {
91  		int size = mpb.size();
92  		lits = new int[size];
93  		this.coefs = new BigInteger[size];
94  		mpb.buildConstraintFromMapPb(lits, coefs);
95  
96  		this.degree = mpb.getDegree();
97  
98  		// arrays are sorted by decreasing coefficients
99  		sort();
100 	}
101 
102 	WatchPb(int[] lits, BigInteger[] coefs, BigInteger degree) { // NOPMD
103 		this.lits = lits;
104 		this.coefs = coefs;
105 		this.degree = degree;
106 		// arrays are sorted by decreasing coefficients
107 		sort();
108 	}
109 
110 	/**
111 	 * This predicate tests wether the constraint is assertive at decision level
112 	 * dl
113 	 * 
114 	 * @param dl
115 	 * @return true iff the constraint is assertive at decision level dl.
116 	 */
117 	public boolean isAssertive(int dl) {
118 		BigInteger slack = BigInteger.ZERO;
119 		for (int i = 0; i < lits.length; i++) {
120 			if ((coefs[i].signum() > 0)
121 					&& ((!voc.isFalsified(lits[i]) || voc.getLevel(lits[i]) >= dl)))
122 				slack = slack.add(coefs[i]);
123 		}
124 		slack = slack.subtract(degree);
125 		if (slack.signum() < 0)
126 			return false;
127 		for (int i = 0; i < lits.length; i++) {
128 			if ((coefs[i].signum() > 0)
129 					&& (voc.isUnassigned(lits[i]) || voc.getLevel(lits[i]) >= dl)
130 					&& (slack.compareTo(coefs[i]) < 0)) {
131 				return true;
132 			}
133 		}
134 		return false;
135 	}
136 
137 	/**
138 	 * compute the reason for the assignment of a literal
139 	 * 
140 	 * @param p
141 	 *            a falsified literal (or Lit.UNDEFINED)
142 	 * @param outReason
143 	 *            list of falsified literals for which the negation is the
144 	 *            reason of the assignment
145 	 * @see org.sat4j.minisat.core.Constr#calcReason(int, IVecInt)
146 	 */
147 	public void calcReason(int p, IVecInt outReason) {
148 		final int[] mlits = lits;
149 		for (int q : mlits) {
150 			if (voc.isFalsified(q)) {
151 				outReason.push(q ^ 1);
152 			}
153 		}
154 	}
155 
156 	abstract protected void computeWatches() throws ContradictionException;
157 
158 	abstract protected void computePropagation(UnitPropagationListener s)
159 			throws ContradictionException;
160 
161 	/**
162 	 * to obtain the i-th literal of the constraint
163 	 * 
164 	 * @param i
165 	 *            index of the literal
166 	 * @return the literal
167 	 */
168 	public int get(int i) {
169 		return lits[i];
170 	}
171 
172 	/**
173 	 * to obtain the coefficient of the i-th literal of the constraint
174 	 * 
175 	 * @param i
176 	 *            index of the literal
177 	 * @return coefficient of the literal
178 	 */
179 	public BigInteger getCoef(int i) {
180 		return coefs[i];
181 	}
182 
183 	/**
184 	 * to obtain the activity value of the constraint
185 	 * 
186 	 * @return activity value of the constraint
187 	 * @see org.sat4j.minisat.core.Constr#getActivity()
188 	 */
189 	public double getActivity() {
190 		return activity;
191 	}
192 
193 	/**
194 	 * increase activity value of the constraint
195 	 * 
196 	 * @see org.sat4j.minisat.core.Constr#incActivity(double)
197 	 */
198 	public void incActivity(double claInc) {
199 		if (learnt) {
200 			activity += claInc;
201 		}
202 	}
203 
204 	/**
205 	 * compute the slack of the current constraint slack = poss - degree of the
206 	 * constraint
207 	 * 
208 	 * @return la marge
209 	 */
210 	public BigInteger slackConstraint() {
211 		return computeLeftSide().subtract(this.degree);
212 	}
213 
214 	/**
215 	 * compute the slack of a described constraint slack = poss - degree of the
216 	 * constraint
217 	 * 
218 	 * @param theCoefs
219 	 *            coefficients of the constraint
220 	 * @param theDegree
221 	 *            degree of the constraint
222 	 * @return slack of the constraint
223 	 */
224 	public BigInteger slackConstraint(BigInteger[] theCoefs,
225 			BigInteger theDegree) {
226 		return computeLeftSide(theCoefs).subtract(theDegree);
227 	}
228 
229 	/**
230 	 * compute the sum of the coefficients of the satisfied or non-assigned
231 	 * literals of a described constraint (usually called poss)
232 	 * 
233 	 * @param coefs
234 	 *            coefficients of the constraint
235 	 * @return poss
236 	 */
237 	public BigInteger computeLeftSide(BigInteger[] theCoefs) {
238 		BigInteger poss = BigInteger.ZERO;
239 		// for each literal
240 		for (int i = 0; i < lits.length; i++)
241 			if (!voc.isFalsified(lits[i])) {
242 				assert theCoefs[i].signum() >= 0;
243 				poss = poss.add(theCoefs[i]);
244 			}
245 		return poss;
246 	}
247 
248 	/**
249 	 * compute the sum of the coefficients of the satisfied or non-assigned
250 	 * literals of the current constraint (usually called poss)
251 	 * 
252 	 * @return poss
253 	 */
254 	public BigInteger computeLeftSide() {
255 		return computeLeftSide(this.coefs);
256 	}
257 
258 	/**
259 	 * tests if the constraint is still satisfiable.
260 	 * 
261 	 * this method is only called in assertions.
262 	 * 
263 	 * @return the constraint is satisfiable
264 	 */
265 	protected boolean isSatisfiable() {
266 		return computeLeftSide().compareTo(degree) >= 0;
267 	}
268 
269 	/**
270 	 * is the constraint a learnt constraint ?
271 	 * 
272 	 * @return true if the constraint is learnt, else false
273 	 * @see org.sat4j.specs.IConstr#learnt()
274 	 */
275 	public boolean learnt() {
276 		return learnt;
277 	}
278 
279 	/**
280 	 * The constraint is the reason of a unit propagation.
281 	 * 
282 	 * @return true
283 	 */
284 	public boolean locked() {
285 		for (int p : lits) {
286 			if (voc.getReason(p) == this) {
287 				return true;
288 			}
289 		}
290 		return false;
291 	}
292 
293 	/**
294 	 * ppcm : least common multiple for two integers (plus petit commun
295 	 * multiple)
296 	 * 
297 	 * @param a
298 	 *            one integer
299 	 * @param b
300 	 *            the other integer
301 	 * @return the least common multiple of a and b
302 	 */
303 	protected static BigInteger ppcm(BigInteger a, BigInteger b) {
304 		return a.divide(a.gcd(b)).multiply(b);
305 	}
306 
307 	/**
308 	 * to re-scale the activity of the constraint
309 	 * 
310 	 * @param d
311 	 *            adjusting factor
312 	 */
313 	public void rescaleBy(double d) {
314 		activity *= d;
315 	}
316 
317 	void selectionSort(int from, int to) {
318 		int i, j, best_i;
319 		BigInteger tmp;
320 		int tmp2;
321 
322 		for (i = from; i < to - 1; i++) {
323 			best_i = i;
324 			for (j = i + 1; j < to; j++) {
325 				if ((coefs[j].compareTo(coefs[best_i]) > 0)
326 						|| ((coefs[j].equals(coefs[best_i])) && (lits[j] > lits[best_i])))
327 					best_i = j;
328 			}
329 			tmp = coefs[i];
330 			coefs[i] = coefs[best_i];
331 			coefs[best_i] = tmp;
332 			tmp2 = lits[i];
333 			lits[i] = lits[best_i];
334 			lits[best_i] = tmp2;
335 		}
336 	}
337 
338 	/**
339 	 * the constraint is learnt
340 	 */
341 	public void setLearnt() {
342 		learnt = true;
343 	}
344 
345 	/**
346 	 * simplify the constraint (if it is satisfied)
347 	 * 
348 	 * @return true if the constraint is satisfied, else false
349 	 */
350 	public boolean simplify() {
351 		BigInteger cumul = BigInteger.ZERO;
352 
353 		int i = 0;
354 		while (i < lits.length && cumul.compareTo(degree) < 0) {
355 			if (voc.isSatisfied(lits[i])) {
356 				// strong measure
357 				cumul = cumul.add(coefs[i]);
358 			}
359 			i++;
360 		}
361 
362 		return (cumul.compareTo(degree) >= 0);
363 	}
364 
365 	public final int size() {
366 		return lits.length;
367 	}
368 
369 	/**
370 	 * sort coefficient and literal arrays
371 	 */
372 	final protected void sort() {
373 		assert this.lits != null;
374 		if (coefs.length > 0) {
375 			this.sort(0, size());
376 			BigInteger buffInt = coefs[0];
377 			for (int i = 1; i < coefs.length; i++) {
378 				assert buffInt.compareTo(coefs[i]) >= 0;
379 				buffInt = coefs[i];
380 			}
381 
382 		}
383 	}
384 
385 	/**
386 	 * sort partially coefficient and literal arrays
387 	 * 
388 	 * @param from
389 	 *            index for the beginning of the sort
390 	 * @param to
391 	 *            index for the end of the sort
392 	 */
393 	final protected void sort(int from, int to) {
394 		int width = to - from;
395 		if (width <= 15)
396 			selectionSort(from, to);
397 
398 		else {
399 			int indPivot = width / 2 + from;
400 			BigInteger pivot = coefs[indPivot];
401 			int litPivot = lits[indPivot];
402 			BigInteger tmp;
403 			int i = from - 1;
404 			int j = to;
405 			int tmp2;
406 
407 			for (;;) {
408 				do
409 					i++;
410 				while ((coefs[i].compareTo(pivot) > 0)
411 						|| ((coefs[i].equals(pivot)) && (lits[i] > litPivot)));
412 				do
413 					j--;
414 				while ((pivot.compareTo(coefs[j]) > 0)
415 						|| ((coefs[j].equals(pivot)) && (lits[j] < litPivot)));
416 
417 				if (i >= j)
418 					break;
419 
420 				tmp = coefs[i];
421 				coefs[i] = coefs[j];
422 				coefs[j] = tmp;
423 				tmp2 = lits[i];
424 				lits[i] = lits[j];
425 				lits[j] = tmp2;
426 			}
427 
428 			sort(from, i);
429 			sort(i, to);
430 		}
431 
432 	}
433 
434 	@Override
435 	public String toString() {
436 		StringBuffer stb = new StringBuffer();
437 
438 		if (lits.length > 0) {
439 			for (int i = 0; i < lits.length; i++) {
440 				// if (voc.isUnassigned(lits[i])) {
441 				stb.append(" + ");
442 				stb.append(this.coefs[i]);
443 				stb.append(".");
444 				stb.append(Lits.toString(this.lits[i]));
445 				stb.append("[");
446 				stb.append(voc.valueToString(lits[i]));
447 				stb.append("@");
448 				stb.append(voc.getLevel(lits[i]));
449 				stb.append("]");
450 				stb.append(" ");
451 				// }
452 			}
453 			stb.append(">= ");
454 			stb.append(this.degree);
455 		}
456 		return stb.toString();
457 	}
458 
459 	public void assertConstraint(UnitPropagationListener s) {
460 		BigInteger tmp = slackConstraint();
461 		for (int i = 0; i < lits.length; i++) {
462 			if (voc.isUnassigned(lits[i]) && tmp.compareTo(coefs[i]) < 0) {
463 				boolean ret = s.enqueue(lits[i], this);
464 				assert ret;
465 			}
466 		}
467 	}
468 
469 	/**
470 	 * @return Returns the degree.
471 	 */
472 	public BigInteger getDegree() {
473 		return degree;
474 	}
475 
476 	public void register() {
477 		assert learnt;
478 		try {
479 			computeWatches();
480 		} catch (ContradictionException e) {
481 			System.out.println(this);
482 			assert false;
483 		}
484 	}
485 
486 	/**
487 	 * to obtain the coefficients of the constraint.
488 	 * 
489 	 * @return a copy of the array of the coefficients
490 	 */
491 	public BigInteger[] getCoefs() {
492 		BigInteger[] coefsBis = new BigInteger[coefs.length];
493 		System.arraycopy(coefs, 0, coefsBis, 0, coefs.length);
494 		return coefsBis;
495 	}
496 
497 	/**
498 	 * to obtain the literals of the constraint.
499 	 * 
500 	 * @return a copy of the array of the literals
501 	 */
502 	public int[] getLits() {
503 		int[] litsBis = new int[lits.length];
504 		System.arraycopy(lits, 0, litsBis, 0, lits.length);
505 		return litsBis;
506 	}
507 
508 	public ILits getVocabulary() {
509 		return voc;
510 	}
511 
512 	/**
513 	 * compute an implied clause on the literals with the greater coefficients.
514 	 * 
515 	 * @return a vector containing the literals for this clause.
516 	 */
517 	public IVecInt computeAnImpliedClause() {
518 		BigInteger cptCoefs = BigInteger.ZERO;
519 		int index = coefs.length;
520 		while ((cptCoefs.compareTo(degree) > 0) && (index > 0)) {
521 			cptCoefs = cptCoefs.add(coefs[--index]);
522 		}
523 		if (index > 0 && index < size() / 2) {
524 			IVecInt literals = new VecInt(index);
525 			for (int j = 0; j <= index; j++)
526 				literals.push(lits[j]);
527 			return literals;
528 		}
529 		return null;
530 	}
531 
532 	public boolean coefficientsEqualToOne() {
533 		return false;
534 	}
535 
536 	@Override
537 	public boolean equals(Object pb) {
538 		if (pb == null) {
539 			return false;
540 		}
541 		// this method should be simplified since now two constraints should
542 		// have
543 		// always
544 		// their literals in the same order
545 		try {
546 
547 			WatchPb wpb = (WatchPb) pb;
548 			if (!degree.equals(wpb.degree) || coefs.length != wpb.coefs.length
549 					|| lits.length != wpb.lits.length) {
550 				return false;
551 			}
552 			int lit;
553 			boolean ok;
554 			for (int ilit = 0; ilit < coefs.length; ilit++) {
555 				lit = lits[ilit];
556 				ok = false;
557 				for (int ilit2 = 0; ilit2 < coefs.length; ilit2++)
558 					if (wpb.lits[ilit2] == lit) {
559 						if (!wpb.coefs[ilit2].equals(coefs[ilit])) {
560 							return false;
561 						}
562 
563 						ok = true;
564 						break;
565 
566 					}
567 				if (!ok) {
568 					return false;
569 				}
570 			}
571 			return true;
572 		} catch (ClassCastException e) {
573 			return false;
574 		}
575 	}
576 
577 	@Override
578 	public int hashCode() {
579 		long sum = 0;
580 		for (int p : lits) {
581 			sum += p;
582 		}
583 		return (int) sum / lits.length;
584 	}
585 
586 	public void forwardActivity(double claInc) {
587 		if (!learnt) {
588 			activity += claInc;
589 		}
590 	}
591 
592 	public boolean canBePropagatedMultipleTimes() {
593 		return true;
594 	}
595 }