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.cnf;
29  
30  import static org.sat4j.core.LiteralsUtils.neg;
31  
32  import java.io.Serializable;
33  
34  import org.sat4j.minisat.core.Constr;
35  import org.sat4j.minisat.core.ILits;
36  import org.sat4j.minisat.core.UnitPropagationListener;
37  import org.sat4j.specs.IVecInt;
38  
39  /**
40   * Lazy data structure for clause using the Head Tail data structure from SATO,
41   * The original scheme is improved by avoiding moving pointers to literals but
42   * moving the literals themselves.
43   * 
44   * We suppose here that the clause contains at least 3 literals. Use the
45   * BinaryClause or UnaryClause clause data structures to deal with binary and
46   * unit clauses.
47   * 
48   * @author leberre
49   * @see BinaryClause
50   * @see UnitClause
51   * @since 2.1
52   */
53  public abstract class HTClause implements Constr, Serializable {
54  
55  	private static final long serialVersionUID = 1L;
56  
57  	protected double activity;
58  
59  	protected final int[] middleLits;
60  
61  	protected final ILits voc;
62  
63  	protected int head;
64  
65  	protected int tail;
66  
67  	/**
68  	 * Creates a new basic clause
69  	 * 
70  	 * @param voc
71  	 *            the vocabulary of the formula
72  	 * @param ps
73  	 *            A VecInt that WILL BE EMPTY after calling that method.
74  	 */
75  	public HTClause(IVecInt ps, ILits voc) {
76  		assert ps.size() > 1;
77  		head = ps.get(0);
78  		tail = ps.last();
79  		final int size = ps.size() - 2;
80  		assert size > 0;
81  		middleLits = new int[size];
82  		System.arraycopy(ps.toArray(), 1, middleLits, 0, size);
83  		ps.clear();
84  		assert ps.size() == 0;
85  		this.voc = voc;
86  		activity = 0;
87  	}
88  
89  	/*
90  	 * (non-Javadoc)
91  	 * 
92  	 * @see Constr#calcReason(Solver, Lit, Vec)
93  	 */
94  	public void calcReason(int p, IVecInt outReason) {
95  		if (voc.isFalsified(head)) {
96  			outReason.push(neg(head));
97  		}
98  		final int[] mylits = middleLits;
99  		for (int i = 0; i < mylits.length; i++) {
100 			if (voc.isFalsified(mylits[i])) {
101 				outReason.push(neg(mylits[i]));
102 			}
103 		}
104 		if (voc.isFalsified(tail)) {
105 			outReason.push(neg(tail));
106 		}
107 	}
108 
109 	/*
110 	 * (non-Javadoc)
111 	 * 
112 	 * @see Constr#remove(Solver)
113 	 */
114 	public void remove(UnitPropagationListener upl) {
115 		voc.watches(neg(head)).remove(this);
116 		voc.watches(neg(tail)).remove(this);
117 	}
118 
119 	/*
120 	 * (non-Javadoc)
121 	 * 
122 	 * @see Constr#simplify(Solver)
123 	 */
124 	public boolean simplify() {
125 		if (voc.isSatisfied(head) || voc.isSatisfied(tail)) {
126 			return true;
127 		}
128 		for (int i = 0; i < middleLits.length; i++) {
129 			if (voc.isSatisfied(middleLits[i])) {
130 				return true;
131 			}
132 		}
133 		return false;
134 	}
135 
136 	public boolean propagate(UnitPropagationListener s, int p) {
137 
138 		if (head == neg(p)) {
139 			final int[] mylits = middleLits;
140 			int temphead = 0;
141 			// moving head on the right
142 			while (temphead < mylits.length
143 					&& voc.isFalsified(mylits[temphead])) {
144 				temphead++;
145 			}
146 			assert temphead <= mylits.length;
147 			if (temphead == mylits.length) {
148 				voc.watch(p, this);
149 				return s.enqueue(tail, this);
150 			}
151 			head = mylits[temphead];
152 			mylits[temphead] = neg(p);
153 			voc.watch(neg(head), this);
154 			return true;
155 		}
156 		assert tail == neg(p);
157 		final int[] mylits = middleLits;
158 		int temptail = mylits.length - 1;
159 		// moving tail on the left
160 		while (temptail >= 0 && voc.isFalsified(mylits[temptail])) {
161 			temptail--;
162 		}
163 		assert -1 <= temptail;
164 		if (-1 == temptail) {
165 			voc.watch(p, this);
166 			return s.enqueue(head, this);
167 		}
168 		tail = mylits[temptail];
169 		mylits[temptail] = neg(p);
170 		voc.watch(neg(tail), this);
171 		return true;
172 	}
173 
174 	/*
175 	 * For learnt clauses only @author leberre
176 	 */
177 	public boolean locked() {
178 		return voc.getReason(head) == this || voc.getReason(tail) == this;
179 	}
180 
181 	/**
182 	 * @return the activity of the clause
183 	 */
184 	public double getActivity() {
185 		return activity;
186 	}
187 
188 	@Override
189 	public String toString() {
190 		StringBuffer stb = new StringBuffer();
191 		stb.append(Lits.toString(head));
192 		stb.append("["); //$NON-NLS-1$
193 		stb.append(voc.valueToString(head));
194 		stb.append("]"); //$NON-NLS-1$
195 		stb.append(" "); //$NON-NLS-1$
196 		for (int i = 0; i < middleLits.length; i++) {
197 			stb.append(Lits.toString(middleLits[i]));
198 			stb.append("["); //$NON-NLS-1$
199 			stb.append(voc.valueToString(middleLits[i]));
200 			stb.append("]"); //$NON-NLS-1$
201 			stb.append(" "); //$NON-NLS-1$
202 		}
203 		stb.append(Lits.toString(tail));
204 		stb.append("["); //$NON-NLS-1$
205 		stb.append(voc.valueToString(tail));
206 		stb.append("]"); //$NON-NLS-1$
207 		return stb.toString();
208 	}
209 
210 	/**
211 	 * Return the ith literal of the clause. Note that the order of the literals
212 	 * does change during the search...
213 	 * 
214 	 * @param i
215 	 *            the index of the literal
216 	 * @return the literal
217 	 */
218 	public int get(int i) {
219 		if (i == 0)
220 			return head;
221 		if (i == middleLits.length + 1)
222 			return tail;
223 		return middleLits[i - 1];
224 	}
225 
226 	/**
227 	 * @param d
228 	 */
229 	public void rescaleBy(double d) {
230 		activity *= d;
231 	}
232 
233 	public int size() {
234 		return middleLits.length + 2;
235 	}
236 
237 	public void assertConstraint(UnitPropagationListener s) {
238 		assert voc.isUnassigned(head);
239 		boolean ret = s.enqueue(head, this);
240 		assert ret;
241 	}
242 
243 	public ILits getVocabulary() {
244 		return voc;
245 	}
246 
247 	public int[] getLits() {
248 		int[] tmp = new int[size()];
249 		System.arraycopy(middleLits, 0, tmp, 1, middleLits.length);
250 		tmp[0] = head;
251 		tmp[tmp.length - 1] = tail;
252 		return tmp;
253 	}
254 
255 	@Override
256 	public boolean equals(Object obj) {
257 		if (obj == null)
258 			return false;
259 		try {
260 			HTClause wcl = (HTClause) obj;
261 			if (wcl.head != head || wcl.tail != tail) {
262 				return false;
263 			}
264 			if (middleLits.length != wcl.middleLits.length)
265 				return false;
266 			boolean ok;
267 			for (int lit : middleLits) {
268 				ok = false;
269 				for (int lit2 : wcl.middleLits)
270 					if (lit == lit2) {
271 						ok = true;
272 						break;
273 					}
274 				if (!ok)
275 					return false;
276 			}
277 			return true;
278 		} catch (ClassCastException e) {
279 			return false;
280 		}
281 	}
282 
283 	@Override
284 	public int hashCode() {
285 		long sum = head + tail;
286 		for (int p : middleLits) {
287 			sum += p;
288 		}
289 		return (int) sum / middleLits.length;
290 	}
291 }