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