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      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 register() {
538         assert this.learnt;
539         try {
540             computeWatches();
541         } catch (ContradictionException e) {
542             System.out.println(this);
543             assert false;
544         }
545     }
546 
547     /**
548      * to obtain the literals of the constraint.
549      * 
550      * @return a copy of the array of the literals
551      */
552     public int[] getLits() {
553         int[] litsBis = new int[this.lits.length];
554         System.arraycopy(this.lits, 0, litsBis, 0, this.lits.length);
555         return litsBis;
556     }
557 
558     public ILits getVocabulary() {
559         return this.voc;
560     }
561 
562     /**
563      * compute an implied clause on the literals with the greater coefficients.
564      * 
565      * @return a vector containing the literals for this clause.
566      */
567     public IVecInt computeAnImpliedClause() {
568         long cptCoefs = 0;
569         int index = this.coefs.length;
570         while (cptCoefs > this.degree && index > 0) {
571             cptCoefs = cptCoefs + this.coefs[--index];
572         }
573         if (index > 0 && index < size() / 2) {
574             IVecInt literals = new VecInt(index);
575             for (int j = 0; j <= index; j++) {
576                 literals.push(this.lits[j]);
577             }
578             return literals;
579         }
580         return null;
581     }
582 
583     public boolean coefficientsEqualToOne() {
584         return false;
585     }
586 
587     @Override
588     public boolean equals(Object pb) {
589         if (pb == null) {
590             return false;
591         }
592         // this method should be simplified since now two constraints should
593         // have
594         // always
595         // their literals in the same order
596         try {
597 
598             WatchPbLongCP wpb = (WatchPbLongCP) pb;
599             if (this.degree != wpb.degree
600                     || this.coefs.length != wpb.coefs.length
601                     || this.lits.length != wpb.lits.length) {
602                 return false;
603             }
604             int lit;
605             boolean ok;
606             for (int ilit = 0; ilit < this.coefs.length; ilit++) {
607                 lit = this.lits[ilit];
608                 ok = false;
609                 for (int ilit2 = 0; ilit2 < this.coefs.length; ilit2++) {
610                     if (wpb.lits[ilit2] == lit) {
611                         if (wpb.coefs[ilit2] != this.coefs[ilit]) {
612                             return false;
613                         }
614 
615                         ok = true;
616                         break;
617 
618                     }
619                 }
620                 if (!ok) {
621                     return false;
622                 }
623             }
624             return true;
625         } catch (ClassCastException e) {
626             return false;
627         }
628     }
629 
630     @Override
631     public int hashCode() {
632         long sum = 0;
633         for (int p : this.lits) {
634             sum += p;
635         }
636         return (int) sum / this.lits.length;
637     }
638 
639     public void forwardActivity(double claInc) {
640         if (!this.learnt) {
641             this.activity += claInc;
642         }
643     }
644 
645     public long[] getLongCoefs() {
646         long[] coefsBis = new long[this.coefs.length];
647         System.arraycopy(this.coefs, 0, coefsBis, 0, this.coefs.length);
648         return coefsBis;
649     }
650 
651     public BigInteger slackConstraint(BigInteger[] theCoefs,
652             BigInteger theDegree) {
653         return computeLeftSide(theCoefs).subtract(theDegree);
654     }
655 
656     /**
657      * to obtain the coefficient of the i-th literal of the constraint
658      * 
659      * @param i
660      *            index of the literal
661      * @return coefficient of the literal
662      */
663     public BigInteger getCoef(int i) {
664         return this.bigCoefs[i];
665     }
666 
667     /**
668      * to obtain the coefficients of the constraint.
669      * 
670      * @return a copy of the array of the coefficients
671      */
672     public BigInteger[] getCoefs() {
673         BigInteger[] coefsBis = new BigInteger[this.coefs.length];
674         System.arraycopy(this.bigCoefs, 0, coefsBis, 0, this.coefs.length);
675         return coefsBis;
676     }
677 
678     /**
679      * @return Returns the degree.
680      */
681     public BigInteger getDegree() {
682         return this.bigDegree;
683     }
684 
685     public boolean canBePropagatedMultipleTimes() {
686         return true;
687     }
688 
689     public Constr toConstraint() {
690         return this;
691     }
692 
693     public void calcReasonOnTheFly(int p, IVecInt trail, IVecInt outReason) {
694         throw new UnsupportedOperationException("Not implemented yet!");
695     }
696 }