View Javadoc

1   /*******************************************************************************
2    * SAT4J: a SATisfiability library for Java Copyright (C) 2004-2008 Daniel Le Berre
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 pseudo boolean algorithms described in:
20   * A fast pseudo-Boolean constraint solver Chai, D.; Kuehlmann, A.
21   * Computer-Aided Design of Integrated Circuits and Systems, IEEE Transactions on
22   * Volume 24, Issue 3, March 2005 Page(s): 305 - 317
23   * 
24   * and 
25   * Heidi E. Dixon, 2004. Automating Pseudo-Boolean Inference within a DPLL 
26   * Framework. Ph.D. Dissertation, University of Oregon.
27   *******************************************************************************/
28  package org.sat4j.pb.constraints.pb;
29  
30  import java.math.BigInteger;
31  
32  import org.sat4j.minisat.core.ILits;
33  import org.sat4j.minisat.core.UnitPropagationListener;
34  import org.sat4j.specs.ContradictionException;
35  
36  /**
37   * Data structure for pseudo-boolean constraint with watched literals.
38   * 
39   * All literals are watched. The sum of the literals satisfied or unvalued is
40   * always memorized, to detect conflict.
41   * 
42   * @author anne
43   * 
44   */
45  public final class MaxWatchPb extends WatchPb {
46  
47  	private static final long serialVersionUID = 1L;
48  
49  	/**
50  	 * sum of the coefficients of the literals satisfied or unvalued
51  	 */
52  	private BigInteger watchCumul = BigInteger.ZERO;
53  
54  	/**
55  	 * Builds a PB constraint for a0.x0 + a1.x1 + ... + an.xn >= k
56  	 * 
57  	 * This constructor is called for learnt pseudo boolean constraints.
58  	 * 
59  	 * @param voc
60  	 *            all the possible variables (vocabulary)
61  	 * @param mpb
62  	 *            data structure which contains literals of the constraint,
63  	 *            coefficients (a0, a1, ... an), and the degree of the
64  	 *            constraint (k). The constraint is a "more than" constraint.
65  	 */
66  	private MaxWatchPb(ILits voc, IDataStructurePB mpb) {
67  
68  		super(mpb);
69  		this.voc = voc;
70  
71  		activity = 0;
72  		watchCumul = BigInteger.ZERO;
73  	}
74  
75  	/**
76  	 * Builds a PB constraint for a0.x0 + a1.x1 + ... + an.xn >= k
77  	 * 
78  	 * @param voc
79  	 *            all the possible variables (vocabulary)
80  	 * @param lits
81  	 *            literals of the constraint (x0,x1, ... xn)
82  	 * @param coefs
83  	 *            coefficients of the left side of the constraint (a0, a1, ...
84  	 *            an)
85  	 * @param degree
86  	 *            degree of the constraint (k)
87  	 */
88  	private MaxWatchPb(ILits voc, int[] lits, BigInteger[] coefs,
89  			BigInteger degree) {
90  
91  		super(lits, coefs, degree);
92  		this.voc = voc;
93  
94  		activity = 0;
95  		watchCumul = BigInteger.ZERO;
96  	}
97  
98  	/**
99  	 * All the literals are watched.
100 	 * 
101 	 * @see org.sat4j.pb.constraints.pb.WatchPb#computeWatches()
102 	 */
103 	@Override
104 	protected void computeWatches() throws ContradictionException {
105 		assert watchCumul.equals(BigInteger.ZERO);
106 		for (int i = 0; i < lits.length; i++) {
107 			if (voc.isFalsified(lits[i])) {
108 				if (learnt) {
109 					voc.undos(lits[i] ^ 1).push(this);
110 					voc.watch(lits[i] ^ 1, this);
111 				}
112 			} else {
113 				// updating of the initial value for the counter
114 				voc.watch(lits[i] ^ 1, this);
115 				watchCumul = watchCumul.add(coefs[i]);
116 			}
117 		}
118 
119 		assert watchCumul.compareTo(computeLeftSide()) >= 0;
120 		if (!learnt && watchCumul.compareTo(degree) < 0) {
121 			throw new ContradictionException("non satisfiable constraint");
122 		}
123 	}
124 
125 	/*
126 	 * This method propagates any possible value.
127 	 * 
128 	 * This method is only called in the factory methods.
129 	 * 
130 	 * @see org.sat4j.minisat.constraints.WatchPb#computePropagation()
131 	 */
132 	@Override
133 	protected void computePropagation(UnitPropagationListener s)
134 			throws ContradictionException {
135 		// propagate any possible value
136 		int ind = 0;
137 		while (ind < coefs.length
138 				&& watchCumul.subtract(coefs[ind]).compareTo(degree) < 0) {
139 			if (voc.isUnassigned(lits[ind]) && !s.enqueue(lits[ind], this))
140 				// because this happens during the building of a constraint.
141 				throw new ContradictionException("non satisfiable constraint");
142 			ind++;
143 		}
144 		assert watchCumul.compareTo(computeLeftSide()) >= 0;
145 	}
146 
147 	/**
148 	 * Propagation of a falsified literal
149 	 * 
150 	 * @param s
151 	 *            the solver
152 	 * @param p
153 	 *            the propagated literal (it must be falsified)
154 	 * @return false iff there is a conflict
155 	 */
156 	public boolean propagate(UnitPropagationListener s, int p) {
157 		voc.watch(p, this);
158 
159 		assert watchCumul.compareTo(computeLeftSide()) >= 0 : "" + watchCumul
160 				+ "/" + computeLeftSide() + ":" + learnt;
161 
162 		// finding the index for p in the array of literals
163 		int indiceP = 0;
164 		while ((lits[indiceP] ^ 1) != p)
165 			indiceP++;
166 
167 		// compute the new value for watchCumul
168 		BigInteger coefP = coefs[indiceP];
169 		BigInteger newcumul = watchCumul.subtract(coefP);
170 
171 		if (newcumul.compareTo(degree) < 0) {
172 			// there is a conflict
173 			assert !isSatisfiable();
174 			return false;
175 		}
176 
177 		// if no conflict, not(p) can be propagated
178 		// allow a later un-assignation
179 		voc.undos(p).push(this);
180 		// really update watchCumul
181 		watchCumul = newcumul;
182 
183 		// propagation
184 		int ind = 0;
185 		// limit is the margin between the sum of the coefficients of the
186 		// satisfied+unassigned literals
187 		// and the degree of the constraint
188 		BigInteger limit = watchCumul.subtract(degree);
189 		// for each coefficient greater than limit
190 		while (ind < coefs.length && limit.compareTo(coefs[ind]) < 0) {
191 			// its corresponding literal is implied
192 			if (voc.isUnassigned(lits[ind]) && (!s.enqueue(lits[ind], this))) {
193 				// if it is not possible then there is a conflict
194 				assert !isSatisfiable();
195 				return false;
196 			}
197 			ind++;
198 		}
199 
200 		assert learnt || watchCumul.compareTo(computeLeftSide()) >= 0;
201 		assert watchCumul.compareTo(computeLeftSide()) >= 0;
202 		return true;
203 	}
204 
205 	/**
206 	 * Remove a constraint from the solver
207 	 */
208 	public void remove(UnitPropagationListener upl) {
209 		for (int i = 0; i < lits.length; i++) {
210 			if (!voc.isFalsified(lits[i]))
211 				voc.watches(lits[i] ^ 1).remove(this);
212 		}
213 	}
214 
215 	/**
216 	 * this method is called during backtrack
217 	 * 
218 	 * @param p
219 	 *            an unassigned literal
220 	 */
221 	public void undo(int p) {
222 		int indiceP = 0;
223 		while ((lits[indiceP] ^ 1) != p)
224 			indiceP++;
225 
226 		assert coefs[indiceP].signum() > 0;
227 
228 		watchCumul = watchCumul.add(coefs[indiceP]);
229 	}
230 
231 	/**
232 	 * build a pseudo boolean constraint. Coefficients are positive integers
233 	 * less than or equal to the degree (this is called a normalized
234 	 * constraint).
235 	 * 
236 	 * @param s
237 	 *            a unit propagation listener (usually the solver)
238 	 * @param voc
239 	 *            the vocabulary
240 	 * @param lits
241 	 *            the literals of the constraint
242 	 * @param coefs
243 	 *            the coefficients of the constraint
244 	 * @param degree
245 	 *            the degree of the constraint
246 	 * @return a new PB constraint or null if a trivial inconsistency is
247 	 *         detected.
248 	 */
249 	public static MaxWatchPb normalizedMaxWatchPbNew(UnitPropagationListener s,
250 			ILits voc, int[] lits, BigInteger[] coefs, BigInteger degree)
251 			throws ContradictionException {
252 		// Parameters must not be modified
253 		MaxWatchPb outclause = new MaxWatchPb(voc, lits, coefs, degree);
254 
255 		if (outclause.degree.signum() <= 0) {
256 			return null;
257 		}
258 
259 		outclause.computeWatches();
260 
261 		outclause.computePropagation(s);
262 
263 		return outclause;
264 
265 	}
266 
267 	/**
268 	 * build a pseudo boolean constraint from a specific data structure. For
269 	 * learnt constraints.
270 	 * 
271 	 * @param s
272 	 *            a unit propagation listener (usually the solver)
273 	 * @param mpb
274 	 *            data structure which contains literals of the constraint,
275 	 *            coefficients (a0, a1, ... an), and the degree of the
276 	 *            constraint (k). The constraint is a "more than" constraint.
277 	 * @return a new PB constraint or null if a trivial inconsistency is
278 	 *         detected.
279 	 */
280 	public static WatchPb normalizedWatchPbNew(ILits voc, IDataStructurePB mpb) {
281 		return new MaxWatchPb(voc, mpb);
282 	}
283 
284 }