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.minisat.core.UnitPropagationListener;
42  import org.sat4j.specs.ContradictionException;
43  import org.sat4j.specs.IVecInt;
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      /**
54       * constraint activity
55       */
56      protected double activity;
57      /** Constructor used for original constraints. */
58  
59      /**
60       * coefficients of the literals of the constraint
61       */
62      protected BigInteger[] bigCoefs;
63  
64      /**
65       * degree of the pseudo-boolean constraint
66       */
67      protected BigInteger bigDegree;
68  
69      /**
70       * coefficients of the literals of the constraint
71       */
72      protected long[] coefs;
73  
74      protected long sumcoefs;
75  
76      /**
77       * degree of the pseudo-boolean constraint
78       */
79      protected long degree;
80  
81      /**
82       * literals of the constraint
83       */
84      protected int[] lits;
85  
86      /**
87       * true if the constraint is a learned constraint
88       */
89      protected boolean learnt = false;
90  
91      /**
92       * constraint's vocabulary
93       */
94      protected ILits voc;
95  
96      /**
97       * This constructor is only available for the serialization.
98       */
99      WatchPbLongCP() {
100     }
101 
102     /** Constructor used for learnt constraints. */
103     WatchPbLongCP(IDataStructurePB mpb) {
104         int size = mpb.size();
105         this.lits = new int[size];
106         this.bigCoefs = new BigInteger[size];
107         mpb.buildConstraintFromMapPb(this.lits, this.bigCoefs);
108         assert mpb.isLongSufficient();
109         // assert MaxLongWatchPBConstructor.isLongSufficient(bigCoefs,
110         // mpb.getDegree());
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     abstract protected void computeWatches() throws ContradictionException;
203 
204     abstract protected 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, best_i;
380         long tmp;
381         BigInteger bigTmp;
382         int tmp2;
383 
384         for (i = from; i < to - 1; i++) {
385             best_i = i;
386             for (j = i + 1; j < to; j++) {
387                 if (this.coefs[j] > this.coefs[best_i]
388                         || this.coefs[j] == this.coefs[best_i]
389                         && this.lits[j] > this.lits[best_i]) {
390                     best_i = j;
391                 }
392             }
393             tmp = this.coefs[i];
394             this.coefs[i] = this.coefs[best_i];
395             this.coefs[best_i] = tmp;
396             bigTmp = this.bigCoefs[i];
397             this.bigCoefs[i] = this.bigCoefs[best_i];
398             this.bigCoefs[best_i] = bigTmp;
399             tmp2 = this.lits[i];
400             this.lits[i] = this.lits[best_i];
401             this.lits[best_i] = tmp2;
402             assert this.coefs[i] >= 0;
403             assert this.coefs[best_i] >= 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     final protected void sort() {
442         assert this.lits != null;
443         if (this.coefs.length > 0) {
444             this.sort(0, size());
445             // long buffInt = coefs[0];
446             // for (int i = 1; i < coefs.length; i++) {
447             // assert buffInt >= coefs[i];
448             // buffInt = coefs[i];
449             // }
450 
451         }
452     }
453 
454     /**
455      * sort partially coefficient and literal arrays
456      * 
457      * @param from
458      *            index for the beginning of the sort
459      * @param to
460      *            index for the end of the sort
461      */
462     final protected void sort(int from, int to) {
463         int width = to - from;
464         if (width <= 15) {
465             selectionSort(from, to);
466         } else {
467             assert this.coefs.length == this.bigCoefs.length;
468             int indPivot = width / 2 + from;
469             long pivot = this.coefs[indPivot];
470             int litPivot = this.lits[indPivot];
471             long tmp;
472             BigInteger bigTmp;
473             int i = from - 1;
474             int j = to;
475             int tmp2;
476 
477             for (;;) {
478                 do {
479                     i++;
480                 } while (this.coefs[i] > pivot || this.coefs[i] == pivot
481                         && this.lits[i] > litPivot);
482                 do {
483                     j--;
484                 } while (pivot > this.coefs[j] || this.coefs[j] == pivot
485                         && this.lits[j] < litPivot);
486 
487                 if (i >= j) {
488                     break;
489                 }
490 
491                 tmp = this.coefs[i];
492                 this.coefs[i] = this.coefs[j];
493                 this.coefs[j] = tmp;
494                 bigTmp = this.bigCoefs[i];
495                 this.bigCoefs[i] = this.bigCoefs[j];
496                 this.bigCoefs[j] = bigTmp;
497                 tmp2 = this.lits[i];
498                 this.lits[i] = this.lits[j];
499                 this.lits[j] = tmp2;
500                 assert this.coefs[i] >= 0;
501                 assert this.coefs[j] >= 0;
502             }
503 
504             sort(from, i);
505             sort(i, to);
506         }
507 
508     }
509 
510     @Override
511     public String toString() {
512         StringBuffer stb = new StringBuffer();
513 
514         if (this.lits.length > 0) {
515             for (int i = 0; i < this.lits.length; i++) {
516                 // if (voc.isUnassigned(lits[i])) {
517                 stb.append(" + ");
518                 stb.append(this.coefs[i]);
519                 stb.append(".");
520                 stb.append(Lits.toString(this.lits[i]));
521                 stb.append("[");
522                 stb.append(this.voc.valueToString(this.lits[i]));
523                 stb.append("@");
524                 stb.append(this.voc.getLevel(this.lits[i]));
525                 stb.append("]");
526                 stb.append(" ");
527                 // }
528             }
529             stb.append(">= ");
530             stb.append(this.degree);
531         }
532         return stb.toString();
533     }
534 
535     public void assertConstraint(UnitPropagationListener s) {
536         long tmp = slackConstraint();
537         for (int i = 0; i < this.lits.length; i++) {
538             if (this.voc.isUnassigned(this.lits[i]) && tmp < this.coefs[i]) {
539                 boolean ret = s.enqueue(this.lits[i], this);
540                 assert ret;
541             }
542         }
543     }
544 
545     public void register() {
546         assert this.learnt;
547         try {
548             computeWatches();
549         } catch (ContradictionException e) {
550             System.out.println(this);
551             assert false;
552         }
553     }
554 
555     /**
556      * to obtain the literals of the constraint.
557      * 
558      * @return a copy of the array of the literals
559      */
560     public int[] getLits() {
561         int[] litsBis = new int[this.lits.length];
562         System.arraycopy(this.lits, 0, litsBis, 0, this.lits.length);
563         return litsBis;
564     }
565 
566     public ILits getVocabulary() {
567         return this.voc;
568     }
569 
570     /**
571      * compute an implied clause on the literals with the greater coefficients.
572      * 
573      * @return a vector containing the literals for this clause.
574      */
575     public IVecInt computeAnImpliedClause() {
576         long cptCoefs = 0;
577         int index = this.coefs.length;
578         while (cptCoefs > this.degree && index > 0) {
579             cptCoefs = cptCoefs + this.coefs[--index];
580         }
581         if (index > 0 && index < size() / 2) {
582             IVecInt literals = new VecInt(index);
583             for (int j = 0; j <= index; j++) {
584                 literals.push(this.lits[j]);
585             }
586             return literals;
587         }
588         return null;
589     }
590 
591     public boolean coefficientsEqualToOne() {
592         return false;
593     }
594 
595     @Override
596     public boolean equals(Object pb) {
597         if (pb == null) {
598             return false;
599         }
600         // this method should be simplified since now two constraints should
601         // have
602         // always
603         // their literals in the same order
604         try {
605 
606             WatchPbLongCP wpb = (WatchPbLongCP) pb;
607             if (this.degree != wpb.degree
608                     || this.coefs.length != wpb.coefs.length
609                     || this.lits.length != wpb.lits.length) {
610                 return false;
611             }
612             int lit;
613             boolean ok;
614             for (int ilit = 0; ilit < this.coefs.length; ilit++) {
615                 lit = this.lits[ilit];
616                 ok = false;
617                 for (int ilit2 = 0; ilit2 < this.coefs.length; ilit2++) {
618                     if (wpb.lits[ilit2] == lit) {
619                         if (wpb.coefs[ilit2] != this.coefs[ilit]) {
620                             return false;
621                         }
622 
623                         ok = true;
624                         break;
625 
626                     }
627                 }
628                 if (!ok) {
629                     return false;
630                 }
631             }
632             return true;
633         } catch (ClassCastException e) {
634             return false;
635         }
636     }
637 
638     @Override
639     public int hashCode() {
640         long sum = 0;
641         for (int p : this.lits) {
642             sum += p;
643         }
644         return (int) sum / this.lits.length;
645     }
646 
647     public void forwardActivity(double claInc) {
648         if (!this.learnt) {
649             this.activity += claInc;
650         }
651     }
652 
653     public long[] getLongCoefs() {
654         long[] coefsBis = new long[this.coefs.length];
655         System.arraycopy(this.coefs, 0, coefsBis, 0, this.coefs.length);
656         return coefsBis;
657     }
658 
659     public BigInteger slackConstraint(BigInteger[] theCoefs,
660             BigInteger theDegree) {
661         return computeLeftSide(theCoefs).subtract(theDegree);
662     }
663 
664     /**
665      * to obtain the coefficient of the i-th literal of the constraint
666      * 
667      * @param i
668      *            index of the literal
669      * @return coefficient of the literal
670      */
671     public BigInteger getCoef(int i) {
672         return this.bigCoefs[i];
673     }
674 
675     /**
676      * to obtain the coefficients of the constraint.
677      * 
678      * @return a copy of the array of the coefficients
679      */
680     public BigInteger[] getCoefs() {
681         BigInteger[] coefsBis = new BigInteger[this.coefs.length];
682         System.arraycopy(this.bigCoefs, 0, coefsBis, 0, this.coefs.length);
683         return coefsBis;
684     }
685 
686     /**
687      * @return Returns the degree.
688      */
689     public BigInteger getDegree() {
690         return this.bigDegree;
691     }
692 
693     public boolean canBePropagatedMultipleTimes() {
694         return true;
695     }
696 
697     public Constr toConstraint() {
698         return this;
699     }
700 }