View Javadoc

1   /*
2    * SAT4J: a SATisfiability library for Java Copyright (C) 2004-2006 Daniel Le Berre
3    * 
4    * Based on the original minisat specification from:
5    * 
6    * An extensible SAT solver. Niklas E?n and Niklas S?rensson. Proceedings of the
7    * Sixth International Conference on Theory and Applications of Satisfiability
8    * Testing, LNCS 2919, pp 502-518, 2003.
9    * 
10   * This library is free software; you can redistribute it and/or modify it under
11   * the terms of the GNU Lesser General Public License as published by the Free
12   * Software Foundation; either version 2.1 of the License, or (at your option)
13   * any later version.
14   * 
15   * This library is distributed in the hope that it will be useful, but WITHOUT
16   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17   * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
18   * details.
19   * 
20   * You should have received a copy of the GNU Lesser General Public License
21   * along with this library; if not, write to the Free Software Foundation, Inc.,
22   * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23   * 
24   */
25  
26  package org.sat4j.minisat.constraints.pb;
27  
28  import java.io.Serializable;
29  import java.math.BigInteger;
30  import java.util.Random;
31  
32  import org.sat4j.core.Vec;
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.IVec;
40  import org.sat4j.specs.IVecInt;
41  
42  public abstract class WatchPb implements PBConstr, Undoable, Serializable {
43  
44      /**
45       * constant for the initial type of inequality less than or equal
46       */
47      public static final boolean ATMOST = false;
48  
49      /**
50       * constant for the initial type of inequality more than or equal
51       */
52      public static final boolean ATLEAST = true;
53  
54      /**
55       * variable needed for the sort method
56       */
57      private static final Random rand = new Random(91648253);
58  
59      /**
60       * constraint activity
61       */
62      protected double activity;
63  
64      /**
65       * coefficients of the literals of the constraint
66       */
67      protected BigInteger[] coefs;
68  
69      /**
70       * degree of the pseudo-boolean constraint
71       */
72      protected BigInteger degree;
73  
74      /**
75       * literals of the constraint
76       */
77      protected int[] lits;
78  
79      /**
80       * true if the constraint is a learned constraint
81       */
82      protected boolean learnt = false;
83  
84      /**
85       * true if the constraint is the origin of unit propagation
86       */
87      protected boolean locked;
88  
89      /**
90       * sum of the coefficients of the literals satisfied or unvalued
91       */
92      protected BigInteger watchCumul = BigInteger.ZERO;
93  
94      /**
95       * constraint's vocabulary
96       */
97      protected ILits voc;
98  
99      /**
100      * This constructor is only available for the serialization.
101      */
102     WatchPb() {
103     }
104 
105     WatchPb(IDataStructurePB mpb) {
106         int size = mpb.size();
107         lits = new int[size];
108         this.coefs = new BigInteger[size];
109         mpb.buildConstraintFromMapPb(lits, coefs);
110 
111         this.degree = mpb.getDegree();
112 
113         // On peut trier suivant les coefficients
114         sort();
115     }
116 
117     WatchPb(int[] lits, BigInteger[] coefs, BigInteger degree) {
118     	this.lits = lits;
119     	this.coefs = coefs;
120     	this.degree = degree;
121         // On peut trier suivant les coefficients
122         sort();
123     }
124 
125     /**
126      * This predicate tests wether the constraint is assertive at decision level dl
127      * 
128      * @param dl
129      * @return true iff the constraint is assertive at decision level dl.
130      */
131     public boolean isAssertive(int dl) {
132         BigInteger slack = BigInteger.ZERO;
133         for (int i = 0; i < lits.length; i++) {
134             if ((coefs[i].signum() > 0)
135                     && ((!voc.isFalsified(lits[i]) || voc.getLevel(lits[i]) >= dl)))
136                 slack = slack.add(coefs[i]);
137         }
138         slack = slack.subtract(degree);
139         if (slack.signum() < 0)
140             return false;
141         for (int i = 0; i < lits.length; i++) {
142             if ((coefs[i].signum() > 0)
143                     && (voc.isUnassigned(lits[i]) || voc.getLevel(lits[i]) >= dl)
144                     && (slack.compareTo(coefs[i]) < 0)) {
145                 return true;
146             }
147         }
148         return false;
149     }
150 
151     /**
152      * compute the reason for the assignment of a literal
153      * 
154      * @param p
155      *            a falsified literal (or Lit.UNDEFINED)
156      * @param outReason
157      * 			  list of falsified literals for which the negation is the reason of the assignment 
158      * @see org.sat4j.minisat.core.Constr#calcReason(int, IVecInt)
159      */
160     public void calcReason(int p, IVecInt outReason) {
161         for (int q : lits) {
162             if (voc.isFalsified(q)) {
163                 outReason.push(q ^ 1);
164             }
165         }
166     }
167 
168     abstract protected void computeWatches() throws ContradictionException;
169 
170     abstract protected void computePropagation(UnitPropagationListener s)
171             throws ContradictionException;
172 
173     /**
174      * to obtain the i-th literal of the constraint 
175      * 
176      * @param i
177      *            index of the literal
178      * @return the literal
179      */
180     public int get(int i) {
181         return lits[i];
182     }
183 
184     /**
185      * to obtain the coefficient of the i-th literal of the constraint
186      * 
187      * @param i
188      *            index of the literal
189      * @return coefficient of the literal
190      */
191     public BigInteger getCoef(int i) {
192         return coefs[i];
193     }
194 
195     /**
196      * to obtain the activity value of the constraint
197      * 
198      * @return activity value of the constraint
199      * @see org.sat4j.minisat.core.Constr#getActivity()
200      */
201     public double getActivity() {
202         return activity;
203     }
204 
205     public static IDataStructurePB niceParameters(IVecInt ps,
206             IVec<BigInteger> bigCoefs, boolean moreThan, BigInteger bigDeg,
207             ILits voc) throws ContradictionException {
208         // Ajouter les simplifications quand la structure sera d?finitive
209         if (ps.size() == 0) {
210             throw new ContradictionException("Creating Empty clause ?");
211         } else if (ps.size() != bigCoefs.size()) {
212             throw new IllegalArgumentException(
213                     "Contradiction dans la taille des tableaux ps=" + ps.size()
214                             + " coefs=" + bigCoefs.size() + ".");
215         }
216         return niceCheckedParameters(ps, bigCoefs, moreThan, bigDeg, voc);
217     }
218 
219     public static IDataStructurePB niceCheckedParameters(IVecInt ps,
220             IVec<BigInteger> bigCoefs, boolean moreThan, BigInteger bigDeg,
221             ILits voc) {
222         assert ps.size() != 0 && ps.size() == bigCoefs.size();
223         int[] lits = new int[ps.size()];
224         ps.copyTo(lits);
225         BigInteger[] bc = new BigInteger[bigCoefs.size()];
226         bigCoefs.copyTo(bc);
227         BigInteger bigDegree = bigDeg;
228         if (!moreThan) {
229             for (int i = 0; i < lits.length; i++) {
230                 bc[i] = bc[i].negate();
231             }
232             bigDegree = bigDegree.negate();
233         }
234 
235         for (int i = 0; i < bc.length; i++)
236             if (bc[i].signum() < 0) {
237                 lits[i] = lits[i] ^ 1;
238                 bc[i] = bc[i].negate();
239                 bigDegree = bigDegree.add(bc[i]);
240             }
241 
242         IDataStructurePB mpb = new MapPb();
243         if (bigDegree.signum() > 0)
244             bigDegree = mpb.cuttingPlane(lits, bc, bigDegree);
245         if (bigDegree.signum() > 0)
246             bigDegree = mpb.saturation();
247         if (bigDegree.signum() <= 0)
248             return null;
249         return mpb;
250     }
251 
252     /**
253      * increase activity value of the constraint
254      * 
255      * @see org.sat4j.minisat.core.Constr#incActivity(double)
256      */
257     public void incActivity(double claInc) {
258         activity += claInc;
259     }
260 
261     /**
262      * compute the slack of the current constraint
263      * slack = poss - degree of the constraint
264      * 
265      * @return la marge
266      */
267     public BigInteger slackConstraint() {
268         return recalcLeftSide().subtract(this.degree);
269     }
270 
271     /**
272      * compute the slack of a described constraint
273      * slack = poss - degree of the constraint
274      * 
275      * @param coefs
276      *            coefficients of the constraint
277      * @param degree
278      *            degree of the constraint
279      * @return slack of the constraint
280      */
281     public BigInteger slackConstraint(BigInteger[] coefs, BigInteger degree) {
282         return recalcLeftSide(coefs).subtract(degree);
283     }
284 
285     /**
286      * compute the sum of the coefficients of the satisfied or non-assigned literals
287      * of a described constraint (usually called poss)
288      * 
289      * @param coefs
290      *            coefficients of the constraint
291      * @return poss
292      */
293     public BigInteger recalcLeftSide(BigInteger[] coefs) {
294         BigInteger poss = BigInteger.ZERO;
295         // Pour chaque litteral
296         for (int i = 0; i < lits.length; i++)
297             if (!voc.isFalsified(lits[i])) {
298                 assert coefs[i].signum() >= 0;
299                 poss = poss.add(coefs[i]);
300             }
301         return poss;
302     }
303 
304     /**
305      * compute the sum of the coefficients of the satisfied or non-assigned literals
306      * of the current constraint (usually called poss)
307      * 
308      * @return poss
309      */
310     public BigInteger recalcLeftSide() {
311         return recalcLeftSide(this.coefs);
312     }
313 
314     /**
315      * D?termine si la contrainte est toujours satisfiable
316      * 
317      * @return la contrainte est encore satisfiable
318      */
319     protected boolean isSatisfiable() {
320         return recalcLeftSide().compareTo(degree) >= 0;
321     }
322 
323     /**
324      * is the constraint a learnt constrainte ?
325      * 
326      * @return true si la contrainte est apprise, false sinon
327      * @see org.sat4j.specs.IConstr#learnt()
328      */
329     public boolean learnt() {
330         return learnt;
331     }
332 
333     /**
334      * The constraint is the reason of a unit propagation.
335      * 
336      * @return true
337      */
338     public boolean locked() {
339         return true;
340     }
341 
342     /**
343      * Calcule le ppcm de deux nombres
344      * 
345      * @param a
346      *            premier nombre de l'op?ration
347      * @param b
348      *            second nombre de l'op?ration
349      * @return le ppcm en question
350      */
351     protected static BigInteger ppcm(BigInteger a, BigInteger b) {
352         return a.divide(a.gcd(b)).multiply(b);
353     }
354 
355     /**
356      * Permet le r??????chantillonage de l'activit??? de la contrainte
357      * 
358      * @param d
359      *            facteur d'ajustement
360      */
361     public void rescaleBy(double d) {
362         activity *= d;
363     }
364 
365     void selectionSort(int from, int to) {
366         int i, j, best_i;
367         BigInteger tmp;
368         int tmp2;
369 
370         for (i = from; i < to - 1; i++) {
371             best_i = i;
372             for (j = i + 1; j < to; j++) {
373                 if (coefs[j].compareTo(coefs[best_i]) > 0)
374                     best_i = j;
375             }
376             tmp = coefs[i];
377             coefs[i] = coefs[best_i];
378             coefs[best_i] = tmp;
379             tmp2 = lits[i];
380             lits[i] = lits[best_i];
381             lits[best_i] = tmp2;
382         }
383     }
384 
385     /**
386      * La contrainte est apprise
387      */
388     public void setLearnt() {
389         learnt = true;
390     }
391 
392     /**
393      * Simplifie la contrainte(l'all???ge)
394      * 
395      * @return true si la contrainte est satisfaite, false sinon
396      */
397     public boolean simplify() {
398         BigInteger cumul = BigInteger.ZERO;
399 
400         int i = 0;
401         while (i < lits.length && cumul.compareTo(degree) < 0) {
402             if (voc.isSatisfied(lits[i])) {
403                 // Mesure pessimiste
404                 cumul = cumul.add(coefs[i]);
405             }
406             i++;
407         }
408 
409         return (cumul.compareTo(degree) >= 0);
410     }
411 
412     public int size() {
413         return lits.length;
414     }
415 
416     /**
417      * sort coefficient and literal arrays
418      */
419     final protected void sort() {
420         assert this.lits != null;
421         if (coefs.length > 0) {
422             this.sort(0, size());
423             BigInteger buffInt = coefs[0];
424             for (int i = 1; i < coefs.length; i++) {
425                 assert buffInt.compareTo(coefs[i]) >= 0;
426                 buffInt = coefs[i];
427             }
428 
429         }
430     }
431 
432     /**
433      * sort partially coefficient and literal arrays
434      * 
435      * @param from
436      *            index for the beginning of the sort
437      * @param to
438      *            index for the end of the sort
439      */
440     final protected void sort(int from, int to) {
441         int width = to - from;
442         if (to - from <= 15)
443             selectionSort(from, to);
444 
445         else {
446             BigInteger pivot = coefs[rand.nextInt(width) + from];
447             BigInteger tmp;
448             int i = from - 1;
449             int j = to;
450             int tmp2;
451 
452             for (;;) {
453                 do
454                     i++;
455                 while (coefs[i].compareTo(pivot) > 0);
456                 do
457                     j--;
458                 while (pivot.compareTo(coefs[j]) > 0);
459 
460                 if (i >= j)
461                     break;
462 
463                 tmp = coefs[i];
464                 coefs[i] = coefs[j];
465                 coefs[j] = tmp;
466                 tmp2 = lits[i];
467                 lits[i] = lits[j];
468                 lits[j] = tmp2;
469             }
470 
471             sort(from, i);
472             sort(i, to);
473         }
474 
475     }
476 
477     @Override
478     public String toString() {
479         StringBuffer stb = new StringBuffer();
480 
481         if (lits.length > 0) {
482             for (int i = 0; i < lits.length; i++) {
483                 // if (voc.isUnassigned(lits[i])) {
484                 stb.append(" + ");
485                 stb.append(this.coefs[i]);
486                 stb.append(".");
487                 stb.append(Lits.toString(this.lits[i]));
488                 stb.append("[");
489                 stb.append(voc.valueToString(lits[i]));
490                 stb.append("@");
491                 stb.append(voc.getLevel(lits[i]));
492                 stb.append("]");
493                 stb.append(" ");
494                 // }
495             }
496             stb.append(">= ");
497             stb.append(this.degree);
498         }
499         return stb.toString();
500     }
501 
502     public void assertConstraint(UnitPropagationListener s) {
503         BigInteger tmp = slackConstraint();
504         for (int i = 0; i < lits.length; i++) {
505             if (voc.isUnassigned(lits[i]) && tmp.compareTo(coefs[i]) < 0) {
506                 boolean ret = s.enqueue(lits[i], this);
507                 assert ret;
508             }
509         }
510     }
511 
512     // protected abstract WatchPb watchPbNew(Lits voc, VecInt lits, VecInt
513     // coefs, boolean moreThan, int degree, int[] indexer);
514     /**
515      * @return Returns the degree.
516      */
517     public BigInteger getDegree() {
518         return degree;
519     }
520 
521     public void register() {
522         assert learnt;
523         try {
524             computeWatches();
525         } catch (ContradictionException e) {
526             System.out.println(this);
527             assert false;
528         }
529     }
530 
531     public static IVec<BigInteger> toVecBigInt(IVecInt vec) {
532         IVec<BigInteger> bigVec = new Vec<BigInteger>(vec.size());
533         for (int i = 0; i < vec.size(); ++i)
534             bigVec.push(BigInteger.valueOf(vec.get(i)));
535         return bigVec;
536     }
537 
538     public static BigInteger toBigInt(int i) {
539         return BigInteger.valueOf(i);
540     }
541 
542     public BigInteger[] getCoefs() {
543         BigInteger[] coefsBis = new BigInteger[coefs.length];
544         System.arraycopy(coefs, 0, coefsBis, 0, coefs.length);
545         return coefsBis;
546     }
547 
548     public int[] getLits() {
549         int[] litsBis = new int[lits.length];
550         System.arraycopy(lits, 0, litsBis, 0, lits.length);
551         return litsBis;
552     }
553 
554     public ILits getVocabulary() {
555         return voc;
556     }
557 
558     /**
559      * compute an implied clause on the literals with the greater coefficients
560      */
561     public IVecInt computeAnImpliedClause() {
562         BigInteger cptCoefs = BigInteger.ZERO;
563         int index = coefs.length;
564         while ((cptCoefs.compareTo(degree) > 0) && (index > 0)) {
565             cptCoefs = cptCoefs.add(coefs[--index]);
566         }
567         if (index > 0 && index < size() / 2) {
568             // System.out.println(this);
569             // System.out.println("index : "+index);
570             IVecInt literals = new VecInt(index);
571             for (int j = 0; j <= index; j++)
572                 literals.push(lits[j]);
573             return literals;
574         }
575         return null;
576     }
577 
578     public boolean coefficientsEqualToOne() {
579         return false;
580     }
581 
582 }