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 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   *******************************************************************************/
28  package org.sat4j.minisat.constraints.card;
29  
30  import java.io.Serializable;
31  
32  import org.sat4j.minisat.constraints.cnf.Lits;
33  import org.sat4j.minisat.core.Constr;
34  import org.sat4j.minisat.core.ILits;
35  import org.sat4j.minisat.core.Undoable;
36  import org.sat4j.minisat.core.UnitPropagationListener;
37  import org.sat4j.specs.ContradictionException;
38  import org.sat4j.specs.IVecInt;
39  
40  public class MinWatchCard implements Constr, Undoable, Serializable {
41  
42  	private static final long serialVersionUID = 1L;
43  
44  	public static final boolean ATLEAST = true;
45  
46  	public static final boolean ATMOST = false;
47  
48  	/**
49  	 * degree of the cardinality constraint
50  	 */
51  	protected int degree;
52  
53  	/**
54  	 * literals involved in the constraint
55  	 */
56  	private final int[] lits;
57  
58  	/**
59  	 * contains the sign of the constraint : ATLEAT or ATMOST
60  	 */
61  	private boolean moreThan;
62  
63  	/**
64  	 * contains the sum of the coefficients of the watched literals
65  	 */
66  	protected int watchCumul;
67  
68  	/**
69  	 * Vocabulary of the constraint
70  	 */
71  	private final ILits voc;
72  
73  	/**
74  	 * Constructs and normalizes a cardinality constraint. used by
75  	 * minWatchCardNew in the non-normalized case.
76  	 * 
77  	 * @param voc
78  	 *            vocabulary used by the constraint
79  	 * @param ps
80  	 *            literals involved in the constraint
81  	 * @param moreThan
82  	 *            should be ATLEAST or ATMOST;
83  	 * @param degree
84  	 *            degree of the constraint
85  	 */
86  	public MinWatchCard(ILits voc, IVecInt ps, boolean moreThan, int degree) {
87  		// On met en place les valeurs
88  		this.voc = voc;
89  		this.degree = degree;
90  		this.moreThan = moreThan;
91  
92  		// On simplifie ps
93  		int[] index = new int[voc.nVars() * 2 + 2];
94  		// Fresh array should have all elements set to 0
95  
96  		// On repertorie les litt?raux utiles
97  		for (int i = 0; i < ps.size(); i++) {
98  			int p = ps.get(i);
99  			if (index[p ^ 1] == 0) {
100 				index[p]++;
101 			} else {
102 				index[p ^ 1]--;
103 			}
104 		}
105 		// On supprime les litt?raux inutiles
106 		int ind = 0;
107 		while (ind < ps.size()) {
108 			if (index[ps.get(ind)] > 0) {
109 				index[ps.get(ind)]--;
110 				ind++;
111 			} else {
112 				// ??
113 				if ((ps.get(ind) & 1) != 0)
114 					this.degree--;
115 				ps.delete(ind);
116 			}
117 		}
118 
119 		// On copie les litt?raux de la contrainte
120 		lits = new int[ps.size()];
121 		ps.moveTo(lits);
122 
123 		// On normalise la contrainte au sens de Barth
124 		normalize();
125 
126 	}
127 
128 	/**
129 	 * Constructs and normalizes a cardinality constraint. used by
130 	 * MinWatchCardPB.normalizedMinWatchCardNew() in the normalized case. <br />
131 	 * <strong>Should not be used if parameters are not already
132 	 * normalized</strong><br />
133 	 * This constraint is always an ATLEAST constraint.
134 	 * 
135 	 * @param voc
136 	 *            vocabulary used by the constraint
137 	 * @param ps
138 	 *            literals involved in the constraint
139 	 * @param degree
140 	 *            degree of the constraint
141 	 */
142 	protected MinWatchCard(ILits voc, IVecInt ps, int degree) {
143 		// On met en place les valeurs
144 		this.voc = voc;
145 		this.degree = degree;
146 		this.moreThan = ATLEAST;
147 
148 		// On copie les litt?raux de la contrainte
149 		lits = new int[ps.size()];
150 		ps.moveTo(lits);
151 
152 	}
153 
154 	/**
155 	 * computes the reason for a literal
156 	 * 
157 	 * @param p
158 	 *            falsified literal (or Lit.UNDEFINED)
159 	 * @param outReason
160 	 *            the reason to be computed. Vector of literals.
161 	 * @see Constr#calcReason(int p, IVecInt outReason)
162 	 */
163 	public void calcReason(int p, IVecInt outReason) {
164 		// TODO calcReason: v?rifier par rapport ? l'article
165 		// Pour chaque litt?ral
166 		for (int i = 0; i < lits.length; i++) {
167 			// Si il est falsifi?
168 			if (voc.isFalsified(lits[i])) {
169 				// On ajoute sa n?gation au vecteur
170 				outReason.push(lits[i] ^ 1);
171 			}
172 		}
173 	}
174 
175 	/**
176 	 * Returns the activity of the constraint
177 	 * 
178 	 * @return activity value of the constraint
179 	 * @see Constr#getActivity()
180 	 */
181 	public double getActivity() {
182 		// TODO getActivity
183 		return 0;
184 	}
185 
186 	/**
187 	 * Increments activity of the constraint
188 	 * 
189 	 * @param claInc
190 	 *            value to be added to the activity of the constraint
191 	 * @see Constr#incActivity(double claInc)
192 	 */
193 	public void incActivity(double claInc) {
194 		// TODO incActivity
195 	}
196 
197 	/**
198 	 * Returns wether the constraint is learnt or not.
199 	 * 
200 	 * @return false : a MinWatchCard cannot be learnt.
201 	 * @see Constr#learnt()
202 	 */
203 	public boolean learnt() {
204 		return false;
205 	}
206 
207 	/**
208 	 * Simplifies the constraint w.r.t. the assignments of the literals
209 	 * 
210 	 * @param voc
211 	 *            vocabulary used
212 	 * @param ps
213 	 *            literals involved
214 	 * @return value to be added to the degree. This value is less than or equal
215 	 *         to 0.
216 	 */
217 	protected static int linearisation(ILits voc, IVecInt ps) {
218 		// Stockage de l'influence des modifications
219 		int modif = 0;
220 
221 		for (int i = 0; i < ps.size();) {
222 			// on verifie si le litteral est affecte
223 			if (voc.isUnassigned(ps.get(i))) {
224 				i++;
225 			} else {
226 				// Si le litteral est satisfait,
227 				// ?a revient ? baisser le degr?
228 				if (voc.isSatisfied(ps.get(i))) {
229 					modif--;
230 				}
231 				// dans tous les cas, s'il est assign?,
232 				// on enleve le ieme litteral
233 				ps.set(i, ps.last());
234 				ps.pop();
235 			}
236 		}
237 
238 		// DLB: inutile?
239 		// ps.shrinkTo(nbElement);
240 		assert modif <= 0;
241 
242 		return modif;
243 	}
244 
245 	/**
246 	 * Returns if the constraint is the reason for a unit propagation.
247 	 * 
248 	 * @return true
249 	 * @see Constr#locked()
250 	 */
251 	public boolean locked() {
252 		// TODO locked
253 		return true;
254 	}
255 
256 	/**
257 	 * Constructs a cardinality constraint with a minimal set of watched
258 	 * literals Permet la cr?ation de contrainte de cardinalit? ? observation
259 	 * minimale
260 	 * 
261 	 * @param s
262 	 *            tool for propagation
263 	 * @param voc
264 	 *            vocalulary used by the constraint
265 	 * @param ps
266 	 *            literals involved in the constraint
267 	 * @param moreThan
268 	 *            sign of the constraint. Should be ATLEAST or ATMOST.
269 	 * @param degree
270 	 *            degree of the constraint
271 	 * @return a new cardinality constraint, null if it is a tautology
272 	 * @throws ContradictionException
273 	 */
274 	public static MinWatchCard minWatchCardNew(UnitPropagationListener s,
275 			ILits voc, IVecInt ps, boolean moreThan, int degree)
276 			throws ContradictionException {
277 
278 		int mydegree = degree + linearisation(voc, ps);
279 
280 		if (ps.size() == 0 && mydegree > 0) {
281 			throw new ContradictionException();
282 		} else if (ps.size() == mydegree || ps.size() <= 0) {
283 			for (int i = 0; i < ps.size(); i++)
284 				if (!s.enqueue(ps.get(i))) {
285 					throw new ContradictionException();
286 				}
287 			return null;
288 		}
289 
290 		// La contrainte est maintenant cr??e
291 		MinWatchCard retour = new MinWatchCard(voc, ps, moreThan, mydegree);
292 
293 		if (retour.degree <= 0)
294 			return null;
295 
296 		retour.computeWatches();
297 
298 		retour.computePropagation(s);
299 
300 		return retour;
301 	}
302 
303 	/**
304 	 * normalize the constraint (cf. P.Barth normalization)
305 	 */
306 	public final void normalize() {
307 		// Gestion du signe
308 		if (!moreThan) {
309 			// On multiplie le degr? par -1
310 			this.degree = 0 - this.degree;
311 			// On r?vise chaque litt?ral
312 			for (int indLit = 0; indLit < lits.length; indLit++) {
313 				lits[indLit] = lits[indLit] ^ 1;
314 				this.degree++;
315 			}
316 			this.moreThan = true;
317 		}
318 	}
319 
320 	/**
321 	 * propagates the value of a falsified literal
322 	 * 
323 	 * @param s
324 	 *            tool for literal propagation
325 	 * @param p
326 	 *            falsified literal
327 	 * @return false if an inconistency is detected, else true
328 	 */
329 	public boolean propagate(UnitPropagationListener s, int p) {
330 
331 		// Si la contrainte est responsable de propagation unitaire
332 		if (watchCumul == degree) {
333 			voc.watch(p, this);
334 			return false;
335 		}
336 
337 		// Recherche du litt?ral falsifi?
338 		int indFalsified = 0;
339 		while ((lits[indFalsified] ^ 1) != p)
340 			indFalsified++;
341 		assert watchCumul > degree;
342 
343 		// Recherche du litt?ral swap
344 		int indSwap = degree + 1;
345 		while (indSwap < lits.length && voc.isFalsified(lits[indSwap]))
346 			indSwap++;
347 
348 		// Mise ? jour de la contrainte
349 		if (indSwap == lits.length) {
350 			// Si aucun litt?ral n'a ?t? trouv?
351 			voc.watch(p, this);
352 			// La limite est atteinte
353 			watchCumul--;
354 			assert watchCumul == degree;
355 			voc.undos(p).push(this);
356 
357 			// On met en queue les litt?raux impliqu?s
358 			for (int i = 0; i <= degree; i++)
359 				if ((p != (lits[i] ^ 1)) && !s.enqueue(lits[i], this))
360 					return false;
361 
362 			return true;
363 		}
364 		// Si un litt?ral a ?t? trouv? on les ?change
365 		int tmpInt = lits[indSwap];
366 		lits[indSwap] = lits[indFalsified];
367 		lits[indFalsified] = tmpInt;
368 
369 		// On observe le nouveau litt?ral
370 		voc.watch(tmpInt ^ 1, this);
371 
372 		return true;
373 	}
374 
375 	/**
376 	 * Removes a constraint from the solver
377 	 * 
378 	 * @since 2.1
379 	 */
380 	public void remove(UnitPropagationListener upl) {
381 		for (int i = 0; i <= degree; i++) {
382 			voc.watches(lits[i] ^ 1).remove(this);
383 		}
384 	}
385 
386 	/**
387 	 * Rescales the activity value of the constraint
388 	 * 
389 	 * @param d
390 	 *            rescale factor
391 	 */
392 	public void rescaleBy(double d) {
393 		// TODO rescaleBy
394 	}
395 
396 	/**
397 	 * simplifies the constraint
398 	 * 
399 	 * @return true if the constraint is satisfied, else false
400 	 */
401 	public boolean simplify() {
402 		// Calcul de la valeur actuelle
403 		for (int i = 0, count = 0; i < lits.length; i++)
404 			if (voc.isSatisfied(lits[i]) && (++count == degree))
405 				return true;
406 
407 		return false;
408 	}
409 
410 	/**
411 	 * Returns a string representation of the constraint.
412 	 * 
413 	 * @return representation of the constraint.
414 	 */
415 	@Override
416 	public String toString() {
417 		StringBuffer stb = new StringBuffer();
418 		stb.append("Card (" + lits.length + ") : ");
419 		if (lits.length > 0) {
420 			// if (voc.isUnassigned(lits[0])) {
421 			stb.append(Lits.toString(this.lits[0]));
422 			stb.append("[");
423 			stb.append(voc.valueToString(lits[0]));
424 			stb.append("@");
425 			stb.append(voc.getLevel(lits[0]));
426 			stb.append("]");
427 			stb.append(" "); //$NON-NLS-1$
428 			// }
429 			for (int i = 1; i < lits.length; i++) {
430 				// if (voc.isUnassigned(lits[i])) {
431 				stb.append(" + "); //$NON-NLS-1$
432 				stb.append(Lits.toString(this.lits[i]));
433 				stb.append("[");
434 				stb.append(voc.valueToString(lits[i]));
435 				stb.append("@");
436 				stb.append(voc.getLevel(lits[i]));
437 				stb.append("]");
438 				stb.append(" "); //$NON-NLS-1$
439 				// }
440 			}
441 			stb.append(">= "); //$NON-NLS-1$
442 			stb.append(this.degree);
443 		}
444 		return stb.toString();
445 	}
446 
447 	/**
448 	 * Updates information on the constraint in case of a backtrack
449 	 * 
450 	 * @param p
451 	 *            unassigned literal
452 	 */
453 	public void undo(int p) {
454 		// Le litt?ral observ? et falsifi? devient non assign?
455 		watchCumul++;
456 	}
457 
458 	public void setLearnt() {
459 		throw new UnsupportedOperationException();
460 	}
461 
462 	public void register() {
463 		throw new UnsupportedOperationException();
464 	}
465 
466 	public int size() {
467 		return lits.length;
468 	}
469 
470 	public int get(int i) {
471 		return lits[i];
472 	}
473 
474 	public void assertConstraint(UnitPropagationListener s) {
475 		throw new UnsupportedOperationException();
476 	}
477 
478 	protected void computeWatches() {
479 		int indSwap = lits.length;
480 		int tmpInt;
481 		for (int i = 0; i <= degree && i < indSwap; i++) {
482 			while (voc.isFalsified(lits[i]) && --indSwap > i) {
483 				tmpInt = lits[i];
484 				lits[i] = lits[indSwap];
485 				lits[indSwap] = tmpInt;
486 			}
487 
488 			// Si le litteral est observable
489 			if (!voc.isFalsified(lits[i])) {
490 				watchCumul++;
491 				voc.watch(lits[i] ^ 1, this);
492 			}
493 		}
494 		if (learnt()) {
495 			// chercher tous les litteraux a regarder
496 			// par ordre de niveau decroissant
497 			int free = 1;
498 			while ((watchCumul <= degree) && (free > 0)) {
499 				free = 0;
500 				// regarder le litteral falsifie au plus bas niveau
501 				int maxlevel = -1, maxi = -1;
502 				for (int i = watchCumul; i < lits.length; i++) {
503 					if (voc.isFalsified(lits[i])) {
504 						free++;
505 						int level = voc.getLevel(lits[i]);
506 						if (level > maxlevel) {
507 							maxi = i;
508 							maxlevel = level;
509 						}
510 					}
511 				}
512 				if (free > 0) {
513 					assert maxi >= 0;
514 					voc.watch(lits[maxi] ^ 1, this);
515 					tmpInt = lits[maxi];
516 					lits[maxi] = lits[watchCumul];
517 					lits[watchCumul] = tmpInt;
518 					watchCumul++;
519 					free--;
520 					assert free >= 0;
521 				}
522 			}
523 			assert lits.length == 1 || watchCumul > 1;
524 		}
525 
526 	}
527 
528 	protected MinWatchCard computePropagation(UnitPropagationListener s)
529 			throws ContradictionException {
530 
531 		// Si on a des litteraux impliques
532 		if (watchCumul == degree) {
533 			for (int i = 0; i < lits.length; i++)
534 				if (!s.enqueue(lits[i])) {
535 					throw new ContradictionException();
536 				}
537 			return null;
538 		}
539 
540 		// Si on n'observe pas suffisamment
541 		if (watchCumul < degree) {
542 			throw new ContradictionException();
543 		}
544 		return this;
545 	}
546 
547 	public int[] getLits() {
548 		int[] tmp = new int[size()];
549 		System.arraycopy(lits, 0, tmp, 0, size());
550 		return tmp;
551 	}
552 
553 	public ILits getVocabulary() {
554 		return voc;
555 	}
556 
557 	@Override
558 	public boolean equals(Object card) {
559 		if (card == null) {
560 			return false;
561 		}
562 		try {
563 			MinWatchCard mcard = (MinWatchCard) card;
564 			if (mcard.degree != degree)
565 				return false;
566 			if (lits.length != mcard.lits.length)
567 				return false;
568 			boolean ok;
569 			for (int lit : lits) {
570 				ok = false;
571 				for (int lit2 : mcard.lits)
572 					if (lit == lit2) {
573 						ok = true;
574 						break;
575 					}
576 				if (!ok)
577 					return false;
578 			}
579 			return true;
580 		} catch (ClassCastException e) {
581 			return false;
582 		}
583 	}
584 
585 	@Override
586 	public int hashCode() {
587 		long sum = 0;
588 		for (int p : lits) {
589 			sum += p;
590 		}
591 		sum += degree;
592 		return (int) sum / (lits.length + 1);
593 	}
594 
595 	/**
596 	 * @since 2.1
597 	 */
598 	public void forwardActivity(double claInc) {
599 		// do nothing
600 	}
601 }