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  public class MinWatchPb extends WatchPb {
37  
38  	private static final long serialVersionUID = 1L;
39  
40  	/**
41  	 * Liste des indices des litt???raux regardant la contrainte
42  	 */
43  	protected boolean[] watched;
44  
45  	/**
46  	 * Sert ??? d???terminer si la clause est watched par le litt???ral
47  	 */
48  	protected int[] watching;
49  
50  	/**
51  	 * Liste des indices des litt???raux regardant la contrainte
52  	 */
53  	protected int watchingCount = 0;
54  
55  	/**
56  	 * Constructeur de base des contraintes
57  	 * 
58  	 * @param voc
59  	 *            Informations sur le vocabulaire employ???
60  	 * @param mpb
61  	 *            a mutable PB constraint
62  	 */
63  	protected MinWatchPb(ILits voc, IDataStructurePB mpb) {
64  
65  		super(mpb);
66  		this.voc = voc;
67  
68  		watching = new int[this.coefs.length];
69  		watched = new boolean[this.coefs.length];
70  		activity = 0;
71  		watchCumul = BigInteger.ZERO;
72  		watchingCount = 0;
73  
74  	}
75  
76  	protected MinWatchPb(ILits voc, int[] lits, BigInteger[] coefs,
77  			BigInteger degree) {
78  
79  		super(lits, coefs, degree);
80  		this.voc = voc;
81  
82  		watching = new int[this.coefs.length];
83  		watched = new boolean[this.coefs.length];
84  		activity = 0;
85  		watchCumul = BigInteger.ZERO;
86  		watchingCount = 0;
87  
88  	}
89  
90  	/*
91  	 * (non-Javadoc)
92  	 * 
93  	 * @see org.sat4j.minisat.constraints.WatchPb#computeWatches()
94  	 */
95  	@Override
96  	protected void computeWatches() throws ContradictionException {
97  		assert watchCumul.signum() == 0;
98  		assert watchingCount == 0;
99  		for (int i = 0; i < lits.length
100 				&& watchCumul.subtract(coefs[0]).compareTo(degree) < 0; i++) {
101 			if (!voc.isFalsified(lits[i])) {
102 				voc.watch(lits[i] ^ 1, this);
103 				watching[watchingCount++] = i;
104 				watched[i] = true;
105 				// Mise ??? jour de la possibilit??? initiale
106 				watchCumul = watchCumul.add(coefs[i]);
107 			}
108 		}
109 
110 		if (learnt)
111 			watchMoreForLearntConstraint();
112 
113 		if (watchCumul.compareTo(degree) < 0) {
114 			throw new ContradictionException("non satisfiable constraint");
115 		}
116 		assert nbOfWatched() == watchingCount;
117 	}
118 
119 	private void watchMoreForLearntConstraint() {
120 		// chercher tous les litteraux a regarder
121 		// par ordre de niveau decroissant
122 		int free = 1;
123 		int maxlevel, maxi, level;
124 
125 		while ((watchCumul.subtract(coefs[0]).compareTo(degree) < 0)
126 				&& (free > 0)) {
127 			free = 0;
128 			// regarder le litteral falsifie au plus bas niveau
129 			maxlevel = -1;
130 			maxi = -1;
131 			for (int i = 0; i < lits.length; i++) {
132 				if (voc.isFalsified(lits[i]) && !watched[i]) {
133 					free++;
134 					level = voc.getLevel(lits[i]);
135 					if (level > maxlevel) {
136 						maxi = i;
137 						maxlevel = level;
138 					}
139 				}
140 			}
141 
142 			if (free > 0) {
143 				assert maxi >= 0;
144 				voc.watch(lits[maxi] ^ 1, this);
145 				watching[watchingCount++] = maxi;
146 				watched[maxi] = true;
147 				// Mise ??? jour de la possibilit??? initiale
148 				watchCumul = watchCumul.add(coefs[maxi]);
149 				free--;
150 				assert free >= 0;
151 			}
152 		}
153 		assert lits.length == 1 || watchingCount > 1;
154 	}
155 
156 	/*
157 	 * (non-Javadoc)
158 	 * 
159 	 * @see
160 	 * org.sat4j.minisat.constraints.WatchPb#computePropagation(org.sat4j.minisat
161 	 * .UnitPropagationListener)
162 	 */
163 	@Override
164 	protected void computePropagation(UnitPropagationListener s)
165 			throws ContradictionException {
166 		// On propage si n???cessaire
167 		int ind = 0;
168 		while (ind < lits.length
169 				&& watchCumul.subtract(coefs[watching[ind]]).compareTo(degree) < 0) {
170 			if (voc.isUnassigned(lits[ind]) && !s.enqueue(lits[ind], this)) {
171 				throw new ContradictionException("non satisfiable constraint");
172 			}
173 			ind++;
174 		}
175 	}
176 
177 	/**
178 	 * @param s
179 	 *            a unit propagation listener
180 	 * @param voc
181 	 *            the vocabulary
182 	 * @param lits
183 	 *            the literals
184 	 * @param coefs
185 	 *            the coefficients
186 	 * @param degree
187 	 *            the degree of the constraint to normalize.
188 	 * @return a new PB constraint or null if a trivial inconsistency is
189 	 *         detected.
190 	 */
191 	public static MinWatchPb normalizedMinWatchPbNew(UnitPropagationListener s,
192 			ILits voc, int[] lits, BigInteger[] coefs, BigInteger degree)
193 			throws ContradictionException {
194 		// Il ne faut pas modifier les param?tres
195 		MinWatchPb outclause = new MinWatchPb(voc, lits, coefs, degree);
196 
197 		if (outclause.degree.signum() <= 0) {
198 			return null;
199 		}
200 
201 		outclause.computeWatches();
202 
203 		outclause.computePropagation(s);
204 
205 		return outclause;
206 
207 	}
208 
209 	/**
210 	 * Nombre de litt???raux actuellement observ???
211 	 * 
212 	 * @return nombre de litt???raux regard???s
213 	 */
214 	protected int nbOfWatched() {
215 		int retour = 0;
216 		for (int ind = 0; ind < this.watched.length; ind++) {
217 			for (int i = 0; i < watchingCount; i++)
218 				if (watching[i] == ind)
219 					assert watched[ind];
220 			retour += (this.watched[ind]) ? 1 : 0;
221 		}
222 		return retour;
223 	}
224 
225 	/**
226 	 * Propagation de la valeur de v???rit??? d'un litt???ral falsifi???
227 	 * 
228 	 * @param s
229 	 *            un prouveur
230 	 * @param p
231 	 *            le litt???ral propag??? (il doit etre falsifie)
232 	 * @return false ssi une inconsistance est d???t???ct???e
233 	 */
234 	public boolean propagate(UnitPropagationListener s, int p) {
235 		assert nbOfWatched() == watchingCount;
236 		assert watchingCount > 1;
237 
238 		// Recherche de l'indice du litt???ral p
239 		int pIndiceWatching = 0;
240 		while (pIndiceWatching < watchingCount
241 				&& (lits[watching[pIndiceWatching]] ^ 1) != p)
242 			pIndiceWatching++;
243 		int pIndice = watching[pIndiceWatching];
244 
245 		assert p == (lits[pIndice] ^ 1);
246 		assert watched[pIndice];
247 
248 		// Recherche du coefficient maximal parmi ceux des litt???raux
249 		// observ???s
250 		BigInteger maxCoef = maximalCoefficient(pIndice);
251 
252 		// Recherche de la compensation
253 		maxCoef = updateWatched(maxCoef, pIndice);
254 
255 		BigInteger upWatchCumul = watchCumul.subtract(coefs[pIndice]);
256 		assert nbOfWatched() == watchingCount;
257 
258 		// Effectuer les propagations, return si l'une est impossible
259 		if (upWatchCumul.compareTo(degree) < 0) {
260 			// conflit
261 			voc.watch(p, this);
262 			assert watched[pIndice];
263 			assert !isSatisfiable();
264 			return false;
265 		} else if (upWatchCumul.compareTo(degree.add(maxCoef)) < 0) {
266 
267 			assert watchingCount != 0;
268 			BigInteger limit = upWatchCumul.subtract(degree);
269 			for (int i = 0; i < watchingCount; i++) {
270 				if (limit.compareTo(coefs[watching[i]]) < 0
271 						&& i != pIndiceWatching
272 						&& !voc.isSatisfied(lits[watching[i]])
273 						&& !s.enqueue(lits[watching[i]], this)) {
274 					voc.watch(p, this);
275 					assert !isSatisfiable();
276 					return false;
277 				}
278 			}
279 			// Si propagation ajoute la contrainte aux undos de p, conserver p
280 			voc.undos(p).push(this);
281 		}
282 
283 		// sinon p peut sortir de la liste de watched
284 		watched[pIndice] = false;
285 		watchCumul = upWatchCumul;
286 		watching[pIndiceWatching] = watching[--watchingCount];
287 
288 		assert watchingCount != 0;
289 		assert nbOfWatched() == watchingCount;
290 
291 		return true;
292 	}
293 
294 	/**
295 	 * Enl???ve une contrainte du prouveur
296 	 */
297 	public void remove(UnitPropagationListener upl) {
298 		for (int i = 0; i < watchingCount; i++) {
299 			voc.watches(lits[watching[i]] ^ 1).remove(this);
300 			this.watched[this.watching[i]] = false;
301 		}
302 		watchingCount = 0;
303 		assert nbOfWatched() == watchingCount;
304 	}
305 
306 	/**
307 	 * M???thode appel???e lors du backtrack
308 	 * 
309 	 * @param p
310 	 *            un litt???ral d???saffect???
311 	 */
312 	public void undo(int p) {
313 		voc.watch(p, this);
314 		int pIndice = 0;
315 		while ((lits[pIndice] ^ 1) != p)
316 			pIndice++;
317 
318 		assert pIndice < lits.length;
319 
320 		watchCumul = watchCumul.add(coefs[pIndice]);
321 
322 		assert watchingCount == nbOfWatched();
323 
324 		watched[pIndice] = true;
325 		watching[watchingCount++] = pIndice;
326 
327 		assert watchingCount == nbOfWatched();
328 	}
329 
330 	/**
331      * 
332      */
333 	public static WatchPb normalizedWatchPbNew(ILits voc, IDataStructurePB mpb) {
334 		return new MinWatchPb(voc, mpb);
335 	}
336 
337 	/**
338 	 * 
339 	 * @param pIndice
340 	 *            propagated literal : its coefficient is excluded from the
341 	 *            search of the maximal coefficient
342 	 * @return the maximal coefficient for the watched literals
343 	 */
344 	protected BigInteger maximalCoefficient(int pIndice) {
345 		BigInteger maxCoef = BigInteger.ZERO;
346 		for (int i = 0; i < watchingCount; i++)
347 			if (coefs[watching[i]].compareTo(maxCoef) > 0
348 					&& watching[i] != pIndice) {
349 				maxCoef = coefs[watching[i]];
350 			}
351 
352 		assert learnt || maxCoef.signum() != 0;
353 		// DLB assert maxCoef!=0;
354 		return maxCoef;
355 	}
356 
357 	protected BigInteger updateWatched(BigInteger mc, int pIndice) {
358 		BigInteger maxCoef = mc;
359 		if (watchingCount < size()) {
360 			BigInteger upWatchCumul = watchCumul.subtract(coefs[pIndice]);
361 
362 			BigInteger degreePlusMaxCoef = degree.add(maxCoef); // dvh
363 			for (int ind = 0; ind < lits.length; ind++) {
364 				if (upWatchCumul.compareTo(degreePlusMaxCoef) >= 0) {
365 					// note: logic negated to old version // dvh
366 					break;
367 				}
368 
369 				if (!voc.isFalsified(lits[ind]) && !watched[ind]) {
370 					upWatchCumul = upWatchCumul.add(coefs[ind]);
371 					watched[ind] = true;
372 					assert watchingCount < size();
373 					watching[watchingCount++] = ind;
374 					voc.watch(lits[ind] ^ 1, this);
375 					// Si on obtient un nouveau coefficient maximum
376 					if (coefs[ind].compareTo(maxCoef) > 0) {
377 						maxCoef = coefs[ind];
378 						degreePlusMaxCoef = degree.add(maxCoef); // update
379 						// that one
380 						// too
381 					}
382 				}
383 			}
384 			watchCumul = upWatchCumul.add(coefs[pIndice]);
385 		}
386 		return maxCoef;
387 	}
388 
389 }