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