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.HashMap;
33  import java.util.Map;
34  
35  import org.sat4j.core.VecInt;
36  import org.sat4j.specs.ContradictionException;
37  import org.sat4j.specs.IConstr;
38  import org.sat4j.specs.IOptimizationProblem;
39  import org.sat4j.specs.ISolver;
40  import org.sat4j.specs.IVecInt;
41  import org.sat4j.specs.IteratorInt;
42  import org.sat4j.specs.TimeoutException;
43  import org.sat4j.tools.SolverDecorator;
44  
45  /**
46   * An implementation of the QuickXplain algorithm as explained by Ulrich Junker
47   * in the following paper:
48   * 
49   * @inproceedings{ junker01:quickxplain:inp, author={Ulrich Junker},
50   *                 title={QUICKXPLAIN: Conflict Detection for Arbitrary
51   *                 Constraint Propagation Algorithms}, booktitle={IJCAI'01
52   *                 Workshop on Modelling and Solving problems with constraints
53   *                 (CONS-1)}, year={2001}, month={August}, address={Seattle, WA,
54   *                 USA}, url={citeseer.ist.psu.edu/junker01quickxplain.html},
55   *                 url={http://www.lirmm.fr/~bessiere/ws_ijcai01/junker.ps.gz} }
56   * 
57   *                 The algorithm has been adapted to work properly in a context
58   *                 where we can afford to add a selector variable to each clause
59   *                 to enable or disable each constraint.
60   * 
61   *                 Note that for the moment, QuickXplain does not work properly
62   *                 in an optimization setting.
63   * 
64   * @author daniel
65   * 
66   * @param <T>
67   *            a subinterface to ISolver.
68   * @since 2.1
69   */
70  public class Xplain<T extends ISolver> extends SolverDecorator<T> {
71  
72  	protected Map<Integer, IConstr> constrs = new HashMap<Integer, IConstr>();
73  
74  	protected IVecInt assump;
75  
76  	private int lastCreatedVar;
77  	private boolean pooledVarId = false;
78  	private final IVecInt lastClause = new VecInt();
79  
80  	private static final XplainStrategy XPLAIN_STRATEGY = new QuickXplainStrategy();
81  
82  	public Xplain(T solver) {
83  		super(solver);
84  	}
85  
86  	@Override
87  	public IConstr addClause(IVecInt literals) throws ContradictionException {
88  		if (literals.equals(lastClause)) {
89  			// System.err.println("c Duplicated entry: " + literals);
90  			return null;
91  		}
92  		lastClause.clear();
93  		literals.copyTo(lastClause);
94  		int newvar = createNewVar(literals);
95  		literals.push(newvar);
96  		IConstr constr = super.addClause(literals);
97  		if (constr == null) {
98  			discardLastestVar();
99  		} else {
100 			constrs.put(newvar, constr);
101 		}
102 		return constr;
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 addAtLeast(IVecInt literals, int degree)
126 			throws ContradictionException {
127 		throw new UnsupportedOperationException();
128 	}
129 
130 	@Override
131 	public IConstr addAtMost(IVecInt literals, int degree)
132 			throws ContradictionException {
133 		throw new UnsupportedOperationException();
134 	}
135 
136 	/**
137 	 * 
138 	 */
139 	private static final long serialVersionUID = 1L;
140 
141 	/**
142 	 * @since 2.1
143 	 * @return
144 	 * @throws TimeoutException
145 	 */
146 	public Collection<IConstr> explain() throws TimeoutException {
147 		assert !isSatisfiable(assump);
148 		ISolver solver = decorated();
149 		if (solver instanceof IOptimizationProblem) {
150 			solver = ((SolverDecorator<? extends ISolver>) solver).decorated();
151 		}
152 		IVecInt keys = XPLAIN_STRATEGY.explain(solver, constrs, assump);
153 		Collection<IConstr> explanation = new ArrayList<IConstr>(keys.size());
154 		for (IteratorInt it = keys.iterator(); it.hasNext();) {
155 			explanation.add(constrs.get(it.next()));
156 		}
157 		return explanation;
158 	}
159 
160 	/**
161 	 * @since 2.1
162 	 */
163 	public void cancelExplanation() {
164 		XPLAIN_STRATEGY.cancelExplanationComputation();
165 	}
166 
167 	/**
168 	 * 
169 	 * @since 2.1
170 	 */
171 	public Collection<IConstr> getConstraints() {
172 		return constrs.values();
173 	}
174 
175 	@Override
176 	public int[] findModel() throws TimeoutException {
177 		assump = VecInt.EMPTY;
178 		IVecInt extraVariables = new VecInt();
179 		for (Integer p : constrs.keySet()) {
180 			extraVariables.push(-p);
181 		}
182 		return super.findModel(extraVariables);
183 	}
184 
185 	@Override
186 	public int[] findModel(IVecInt assumps) throws TimeoutException {
187 		assump = assumps;
188 		IVecInt extraVariables = new VecInt();
189 		assumps.copyTo(extraVariables);
190 		for (Integer p : constrs.keySet()) {
191 			extraVariables.push(-p);
192 		}
193 		return super.findModel(extraVariables);
194 	}
195 
196 	@Override
197 	public boolean isSatisfiable() throws TimeoutException {
198 		assump = VecInt.EMPTY;
199 		IVecInt extraVariables = new VecInt();
200 		for (Integer p : constrs.keySet()) {
201 			extraVariables.push(-p);
202 		}
203 		return super.isSatisfiable(extraVariables);
204 	}
205 
206 	@Override
207 	public boolean isSatisfiable(boolean global) 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.isSatisfiable(extraVariables, global);
214 	}
215 
216 	@Override
217 	public boolean isSatisfiable(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.isSatisfiable(extraVariables);
225 	}
226 
227 	@Override
228 	public boolean isSatisfiable(IVecInt assumps, boolean global)
229 			throws TimeoutException {
230 		assump = assumps;
231 		IVecInt extraVariables = new VecInt();
232 		assumps.copyTo(extraVariables);
233 		for (Integer p : constrs.keySet()) {
234 			extraVariables.push(-p);
235 		}
236 		return super.isSatisfiable(extraVariables, global);
237 	}
238 
239 	@Override
240 	public int[] model() {
241 		int[] fullmodel = super.model();
242 		if (fullmodel == null) {
243 			return null;
244 		}
245 		int[] model = new int[fullmodel.length - constrs.size()];
246 		int j = 0;
247 		for (int i = 0; i < fullmodel.length; i++) {
248 			if (constrs.get(Math.abs(fullmodel[i])) == null) {
249 				model[j++] = fullmodel[i];
250 			}
251 		}
252 		return model;
253 	}
254 
255 }