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  
79  	private static final XplainStrategy xplainStrategy = new QuickXplainStrategy();
80  
81  	public Xplain(T solver) {
82  		super(solver);
83  	}
84  
85  	@Override
86  	public IConstr addClause(IVecInt literals) throws ContradictionException {
87  		int newvar = createNewVar(literals);
88  		literals.push(newvar);
89  		IConstr constr = super.addClause(literals);
90  		if (constr == null) {
91  			discardLastestVar();
92  		} else {
93  			constrs.put(newvar, constr);
94  		}
95  		return constr;
96  	}
97  
98  	/**
99  	 * 
100 	 * @param literals
101 	 * @return
102 	 * @since 2.1
103 	 */
104 	protected int createNewVar(IVecInt literals) {
105 		if (pooledVarId) {
106 			pooledVarId = false;
107 			return lastCreatedVar;
108 		}
109 		lastCreatedVar = nextFreeVarId(true);
110 		return lastCreatedVar;
111 	}
112 
113 	protected void discardLastestVar() {
114 		pooledVarId = true;
115 	}
116 
117 	@Override
118 	public IConstr addAtLeast(IVecInt literals, int degree)
119 			throws ContradictionException {
120 		throw new UnsupportedOperationException();
121 	}
122 
123 	@Override
124 	public IConstr addAtMost(IVecInt literals, int degree)
125 			throws ContradictionException {
126 		throw new UnsupportedOperationException();
127 	}
128 
129 	/**
130 	 * 
131 	 */
132 	private static final long serialVersionUID = 1L;
133 
134 	/**
135 	 * @since 2.1
136 	 * @return
137 	 * @throws TimeoutException
138 	 */
139 	public Collection<IConstr> explain() throws TimeoutException {
140 		assert !isSatisfiable(assump);
141 		ISolver solver = decorated();
142 		if (solver instanceof IOptimizationProblem) {
143 			solver = ((SolverDecorator<? extends ISolver>) solver).decorated();
144 		}
145 		IVecInt keys = xplainStrategy.explain(solver, constrs, assump);
146 		Collection<IConstr> explanation = new ArrayList<IConstr>(keys.size());
147 		for (IteratorInt it = keys.iterator(); it.hasNext();) {
148 			explanation.add(constrs.get(it.next()));
149 		}
150 		return explanation;
151 	}
152 
153 	/**
154 	 * @since 2.1
155 	 */
156 	public void cancelExplanation() {
157 		xplainStrategy.cancelExplanationComputation();
158 	}
159 
160 	/**
161 	 * 
162 	 * @since 2.1
163 	 */
164 	public Collection<IConstr> getConstraints() {
165 		return constrs.values();
166 	}
167 
168 	@Override
169 	public int[] findModel() throws TimeoutException {
170 		assump = VecInt.EMPTY;
171 		IVecInt extraVariables = new VecInt();
172 		for (Integer p : constrs.keySet()) {
173 			extraVariables.push(-p);
174 		}
175 		return super.findModel(extraVariables);
176 	}
177 
178 	@Override
179 	public int[] findModel(IVecInt assumps) throws TimeoutException {
180 		assump = assumps;
181 		IVecInt extraVariables = new VecInt();
182 		assumps.copyTo(extraVariables);
183 		for (Integer p : constrs.keySet()) {
184 			extraVariables.push(-p);
185 		}
186 		return super.findModel(extraVariables);
187 	}
188 
189 	@Override
190 	public boolean isSatisfiable() throws TimeoutException {
191 		assump = VecInt.EMPTY;
192 		IVecInt extraVariables = new VecInt();
193 		for (Integer p : constrs.keySet()) {
194 			extraVariables.push(-p);
195 		}
196 		return super.isSatisfiable(extraVariables);
197 	}
198 
199 	@Override
200 	public boolean isSatisfiable(boolean global) throws TimeoutException {
201 		assump = VecInt.EMPTY;
202 		IVecInt extraVariables = new VecInt();
203 		for (Integer p : constrs.keySet()) {
204 			extraVariables.push(-p);
205 		}
206 		return super.isSatisfiable(extraVariables, global);
207 	}
208 
209 	@Override
210 	public boolean isSatisfiable(IVecInt assumps) throws TimeoutException {
211 		assump = assumps;
212 		IVecInt extraVariables = new VecInt();
213 		assumps.copyTo(extraVariables);
214 		for (Integer p : constrs.keySet()) {
215 			extraVariables.push(-p);
216 		}
217 		return super.isSatisfiable(extraVariables);
218 	}
219 
220 	@Override
221 	public boolean isSatisfiable(IVecInt assumps, boolean global)
222 			throws TimeoutException {
223 		assump = assumps;
224 		IVecInt extraVariables = new VecInt();
225 		assumps.copyTo(extraVariables);
226 		for (Integer p : constrs.keySet()) {
227 			extraVariables.push(-p);
228 		}
229 		return super.isSatisfiable(extraVariables, global);
230 	}
231 
232 	@Override
233 	public int[] model() {
234 		int[] fullmodel = super.model();
235 		int[] model = new int[fullmodel.length - constrs.size()];
236 		int j = 0;
237 		for (int i = 0; i < fullmodel.length; i++) {
238 			if (constrs.get(Math.abs(fullmodel[i])) == null) {
239 				model[j++] = fullmodel[i];
240 			}
241 		}
242 		return model;
243 	}
244 
245 }