View Javadoc

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