1 /******************************************************************************* 2 * SAT4J: a SATisfiability library for Java Copyright (C) 2004, 2012 Artois University and CNRS 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 * Contributors: 28 * CRIL - initial API and implementation 29 *******************************************************************************/ 30 package org.sat4j.tools; 31 32 import org.sat4j.core.VecInt; 33 import org.sat4j.specs.ContradictionException; 34 import org.sat4j.specs.ISolver; 35 import org.sat4j.specs.IVecInt; 36 import org.sat4j.specs.TimeoutException; 37 38 /** 39 * That class allows to iterate through all the models (implicants) of a 40 * formula. 41 * 42 * <pre> 43 * ISolver solver = new ModelIterator(SolverFactory.OneSolver()); 44 * boolean unsat = true; 45 * while (solver.isSatisfiable()) { 46 * unsat = false; 47 * int[] model = solver.model(); 48 * // do something with model 49 * } 50 * if (unsat) { 51 * // UNSAT case 52 * } 53 * </pre> 54 * 55 * It is also possible to limit the number of models returned: 56 * 57 * <pre> 58 * ISolver solver = new ModelIterator(SolverFactory.OneSolver(), 10); 59 * </pre> 60 * 61 * will return at most 10 models. 62 * 63 * @author leberre 64 */ 65 public class ModelIterator extends SolverDecorator<ISolver> { 66 67 private static final long serialVersionUID = 1L; 68 69 private boolean trivialfalsity = false; 70 private final long bound; 71 private long nbModelFound = 0; 72 73 /** 74 * Create an iterator over the solutions available in <code>solver</code>. 75 * The iterator will look for one new model at each call to isSatisfiable() 76 * and will discard that model at each call to model(). 77 * 78 * @param solver 79 * a solver containing the constraints to satisfy. 80 * @see #isSatisfiable() 81 * @see #isSatisfiable(boolean) 82 * @see #isSatisfiable(IVecInt) 83 * @see #isSatisfiable(IVecInt, boolean) 84 * @see #model() 85 */ 86 public ModelIterator(ISolver solver) { 87 this(solver, Long.MAX_VALUE); 88 } 89 90 /** 91 * Create an iterator over a limited number of solutions available in 92 * <code>solver</code>. The iterator will look for one new model at each 93 * call to isSatisfiable() and will discard that model at each call to 94 * model(). At most <code>bound</code> calls to models() will be allowed 95 * before the method <code>isSatisfiable()</code> returns false. 96 * 97 * @param solver 98 * a solver containing the constraints to satisfy. 99 * @param bound 100 * the maximum number of models to return. 101 * @since 2.1 102 * @see #isSatisfiable() 103 * @see #isSatisfiable(boolean) 104 * @see #isSatisfiable(IVecInt) 105 * @see #isSatisfiable(IVecInt, boolean) 106 * @see #model() 107 */ 108 public ModelIterator(ISolver solver, long bound) { 109 super(solver); 110 this.bound = bound; 111 } 112 113 /* 114 * (non-Javadoc) 115 * 116 * @see org.sat4j.ISolver#model() 117 */ 118 @Override 119 public int[] model() { 120 int[] last = super.model(); 121 this.nbModelFound++; 122 IVecInt clause = new VecInt(last.length); 123 for (int q : last) { 124 clause.push(-q); 125 } 126 try { 127 addBlockingClause(clause); 128 } catch (ContradictionException e) { 129 this.trivialfalsity = true; 130 } 131 return last; 132 } 133 134 /* 135 * (non-Javadoc) 136 * 137 * @see org.sat4j.ISolver#isSatisfiable() 138 */ 139 @Override 140 public boolean isSatisfiable() throws TimeoutException { 141 if (this.trivialfalsity || this.nbModelFound >= this.bound) { 142 return false; 143 } 144 this.trivialfalsity = false; 145 return super.isSatisfiable(true); 146 } 147 148 /* 149 * (non-Javadoc) 150 * 151 * @see org.sat4j.ISolver#isSatisfiable(org.sat4j.datatype.VecInt) 152 */ 153 @Override 154 public boolean isSatisfiable(IVecInt assumps) throws TimeoutException { 155 if (this.trivialfalsity || this.nbModelFound >= this.bound) { 156 return false; 157 } 158 this.trivialfalsity = false; 159 return super.isSatisfiable(assumps, true); 160 } 161 162 /* 163 * (non-Javadoc) 164 * 165 * @see org.sat4j.ISolver#reset() 166 */ 167 @Override 168 public void reset() { 169 this.trivialfalsity = false; 170 this.nbModelFound = 0; 171 super.reset(); 172 } 173 174 @Override 175 public int[] primeImplicant() { 176 int[] last = super.primeImplicant(); 177 this.nbModelFound += Math.pow(2, nVars() - last.length); 178 IVecInt clause = new VecInt(last.length); 179 for (int q : last) { 180 clause.push(-q); 181 } 182 try { 183 addBlockingClause(clause); 184 } catch (ContradictionException e) { 185 this.trivialfalsity = true; 186 } 187 return last; 188 } 189 190 /** 191 * To know the number of models already found. 192 * 193 * @return the number of models found so far. 194 * @since 2.3 195 */ 196 public long numberOfModelsFoundSoFar() { 197 return this.nbModelFound; 198 } 199 }