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.tools.xplain;
29  
30  import java.util.ArrayList;
31  import java.util.Collection;
32  import java.util.Collections;
33  import java.util.HashMap;
34  import java.util.List;
35  import java.util.Map;
36  
37  import org.sat4j.core.VecInt;
38  import org.sat4j.specs.ContradictionException;
39  import org.sat4j.specs.IConstr;
40  import org.sat4j.specs.ISolver;
41  import org.sat4j.specs.IVecInt;
42  import org.sat4j.specs.IteratorInt;
43  import org.sat4j.specs.TimeoutException;
44  import org.sat4j.tools.SolverDecorator;
45  
46  /**
47   * Explanation framework for SAT4J.
48   * 
49   * The explanation uses selector variables and assumptions.
50   * 
51   * It is based on a two steps method: 1) extraction of a set of assumptions
52   * implying the inconsistency 2) minimization of that set.
53   * 
54   * @author daniel
55   * 
56   * @param <T>
57   *            a subinterface to ISolver.
58   * @since 2.1
59   */
60  public class Xplain<T extends ISolver> extends SolverDecorator<T> implements
61  		Explainer {
62  
63  	protected Map<Integer, IConstr> constrs = new HashMap<Integer, IConstr>();
64  
65  	protected IVecInt assump;
66  
67  	private int lastCreatedVar;
68  	private boolean pooledVarId = false;
69  	private final IVecInt lastClause = new VecInt();
70  	private IConstr lastConstr;
71  	private final boolean skipDuplicatedEntries;
72  
73  	private MinimizationStrategy xplainStrategy = new DeletionStrategy();
74  
75  	public Xplain(T solver, boolean skipDuplicatedEntries) {
76  		super(solver);
77  		this.skipDuplicatedEntries = skipDuplicatedEntries;
78  	}
79  
80  	public Xplain(T solver) {
81  		this(solver, true);
82  	}
83  
84  	@Override
85  	public IConstr addClause(IVecInt literals) throws ContradictionException {
86  		if (skipDuplicatedEntries) {
87  			if (literals.equals(lastClause)) {
88  				// System.err.println("c Duplicated entry: " + literals);
89  				return null;
90  			}
91  			lastClause.clear();
92  			literals.copyTo(lastClause);
93  		}
94  		int newvar = createNewVar(literals);
95  		literals.push(newvar);
96  		lastConstr = super.addClause(literals);
97  		if (lastConstr == null) {
98  			discardLastestVar();
99  		} else {
100 			constrs.put(newvar, lastConstr);
101 		}
102 		return lastConstr;
103 	}
104 
105 	/**
106 	 * 
107 	 * @param literals
108 	 * @return
109 	 * @since 2.1
110 	 */
111 	protected int createNewVar(IVecInt literals) {
112 		if (pooledVarId) {
113 			pooledVarId = false;
114 			return lastCreatedVar;
115 		}
116 		lastCreatedVar = nextFreeVarId(true);
117 		return lastCreatedVar;
118 	}
119 
120 	protected void discardLastestVar() {
121 		pooledVarId = true;
122 	}
123 
124 	@Override
125 	public IConstr addExactly(IVecInt literals, int n)
126 			throws ContradictionException {
127 		throw new UnsupportedOperationException(
128 				"Explanation requires Pseudo Boolean support. See XplainPB class instead.");
129 	}
130 
131 	@Override
132 	public IConstr addAtLeast(IVecInt literals, int degree)
133 			throws ContradictionException {
134 		throw new UnsupportedOperationException(
135 				"Explanation requires Pseudo Boolean support. See XplainPB class instead.");
136 	}
137 
138 	@Override
139 	public IConstr addAtMost(IVecInt literals, int degree)
140 			throws ContradictionException {
141 		throw new UnsupportedOperationException(
142 				"Explanation requires Pseudo Boolean support. See XplainPB class instead.");
143 	}
144 
145 	/**
146 	 * 
147 	 */
148 	private static final long serialVersionUID = 1L;
149 
150 	/**
151 	 * @since 2.2.4
152 	 * @return
153 	 * @throws TimeoutException
154 	 */
155 	private IVecInt explanationKeys() throws TimeoutException {
156 		assert !isSatisfiable(assump);
157 		ISolver solver = decorated();
158 		if (solver instanceof SolverDecorator<?>) {
159 			solver = ((SolverDecorator<? extends ISolver>) solver).decorated();
160 		}
161 		return xplainStrategy.explain(solver, constrs, assump);
162 	}
163 
164 	public int[] minimalExplanation() throws TimeoutException {
165 		IVecInt keys = explanationKeys();
166 		keys.sort();
167 		List<Integer> allKeys = new ArrayList<Integer>(constrs.keySet());
168 		Collections.sort(allKeys);
169 		int[] model = new int[keys.size()];
170 		int i = 0;
171 		for (IteratorInt it = keys.iterator(); it.hasNext();) {
172 			model[i++] = allKeys.indexOf(it.next()) + 1;
173 		}
174 		return model;
175 	}
176 
177 	/**
178 	 * @since 2.1
179 	 * @return
180 	 * @throws TimeoutException
181 	 */
182 	public Collection<IConstr> explain() throws TimeoutException {
183 		IVecInt keys = explanationKeys();
184 		Collection<IConstr> explanation = new ArrayList<IConstr>(keys.size());
185 		for (IteratorInt it = keys.iterator(); it.hasNext();) {
186 			explanation.add(constrs.get(it.next()));
187 		}
188 		return explanation;
189 	}
190 
191 	/**
192 	 * @since 2.1
193 	 */
194 	public void cancelExplanation() {
195 		xplainStrategy.cancelExplanationComputation();
196 	}
197 
198 	/**
199 	 * 
200 	 * @since 2.1
201 	 */
202 	public Collection<IConstr> getConstraints() {
203 		return constrs.values();
204 	}
205 
206 	@Override
207 	public int[] findModel() throws TimeoutException {
208 		assump = VecInt.EMPTY;
209 		IVecInt extraVariables = new VecInt();
210 		for (Integer p : constrs.keySet()) {
211 			extraVariables.push(-p);
212 		}
213 		return super.findModel(extraVariables);
214 	}
215 
216 	@Override
217 	public int[] findModel(IVecInt assumps) throws TimeoutException {
218 		assump = assumps;
219 		IVecInt extraVariables = new VecInt();
220 		assumps.copyTo(extraVariables);
221 		for (Integer p : constrs.keySet()) {
222 			extraVariables.push(-p);
223 		}
224 		return super.findModel(extraVariables);
225 	}
226 
227 	@Override
228 	public boolean isSatisfiable() throws TimeoutException {
229 		assump = VecInt.EMPTY;
230 		IVecInt extraVariables = new VecInt();
231 		for (Integer p : constrs.keySet()) {
232 			extraVariables.push(-p);
233 		}
234 		return super.isSatisfiable(extraVariables);
235 	}
236 
237 	@Override
238 	public boolean isSatisfiable(boolean global) throws TimeoutException {
239 		assump = VecInt.EMPTY;
240 		IVecInt extraVariables = new VecInt();
241 		for (Integer p : constrs.keySet()) {
242 			extraVariables.push(-p);
243 		}
244 		return super.isSatisfiable(extraVariables, global);
245 	}
246 
247 	@Override
248 	public boolean isSatisfiable(IVecInt assumps) throws TimeoutException {
249 		assump = assumps;
250 		IVecInt extraVariables = new VecInt();
251 		assumps.copyTo(extraVariables);
252 		for (Integer p : constrs.keySet()) {
253 			extraVariables.push(-p);
254 		}
255 		return super.isSatisfiable(extraVariables);
256 	}
257 
258 	@Override
259 	public boolean isSatisfiable(IVecInt assumps, boolean global)
260 			throws TimeoutException {
261 		assump = assumps;
262 		IVecInt extraVariables = new VecInt();
263 		assumps.copyTo(extraVariables);
264 		for (Integer p : constrs.keySet()) {
265 			extraVariables.push(-p);
266 		}
267 		return super.isSatisfiable(extraVariables, global);
268 	}
269 
270 	@Override
271 	public int[] model() {
272 		int[] fullmodel = super.modelWithInternalVariables();
273 		if (fullmodel == null) {
274 			return null;
275 		}
276 		int[] model = new int[fullmodel.length - constrs.size()];
277 		int j = 0;
278 		for (int i = 0; i < fullmodel.length; i++) {
279 			if (constrs.get(Math.abs(fullmodel[i])) == null) {
280 				model[j++] = fullmodel[i];
281 			}
282 		}
283 		return model;
284 	}
285 
286 	@Override
287 	public String toString(String prefix) {
288 		System.out.println(prefix + "Explanation (MUS) enabled solver");
289 		System.out.println(prefix + xplainStrategy);
290 		return super.toString(prefix);
291 	}
292 
293 	public void setMinimizationStrategy(MinimizationStrategy strategy) {
294 		xplainStrategy = strategy;
295 	}
296 
297 	@Override
298 	public boolean removeConstr(IConstr c) {
299 		if (lastConstr == c) {
300 			lastClause.clear();
301 			lastConstr = null;
302 		}
303 		return super.removeConstr(c);
304 	}
305 
306 	@Override
307 	public boolean removeSubsumedConstr(IConstr c) {
308 		if (lastConstr == c) {
309 			lastClause.clear();
310 			lastConstr = null;
311 		}
312 		return super.removeSubsumedConstr(c);
313 	}
314 
315 }