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; 29 30 import org.sat4j.core.VecInt; 31 import org.sat4j.specs.ContradictionException; 32 import org.sat4j.specs.IConstr; 33 import org.sat4j.specs.ISolver; 34 import org.sat4j.specs.IVecInt; 35 import org.sat4j.specs.TimeoutException; 36 37 /** 38 * This solver decorator allows to detect whether or not the set of constraints 39 * available in the solver has only one solution or not. 40 * 41 * NOTE THAT THIS DECORATOR CANNOT BE USED WITH SOLVERS USING SPECIFIC DATA 42 * STRUCTURES FOR BINARY OR TERNARY CLAUSES! 43 * 44 * <code> 45 SingleSolutionDetector problem = 46 new SingleSolutionDetector(SolverFactory.newMiniSAT()); 47 // feed problem/solver as usual 48 49 if (problem.isSatisfiable()) { 50 if (problem.hasASingleSolution()) { 51 // great, the instance has a unique solution 52 int [] uniquesolution = problem.getModel(); 53 } else { 54 // too bad, got more than one 55 } 56 } 57 * </code> 58 * 59 * @author leberre 60 * 61 */ 62 public class SingleSolutionDetector extends SolverDecorator<ISolver> { 63 64 /** 65 * 66 */ 67 private static final long serialVersionUID = 1L; 68 69 public SingleSolutionDetector(ISolver solver) { 70 super(solver); 71 } 72 73 /** 74 * Please use that method only after a positive answer from isSatisfiable() 75 * (else a runtime exception will be launched). 76 * 77 * NOTE THAT THIS FUNCTION SHOULD NOT ONLY BE USED ONCE THE FINAL SOLUTION IS FOUND, 78 * SINCE THE METHOD ADDS CONSTRAINTS INTO THE SOLVER THAT MAY NOT BE REMOVED UNDER 79 * CERTAIN CONDITIONS (UNIT CONSTRAINTS LEARNT FOR INSTANCE). 80 * THAT ISSUE WILL BE RESOLVED ONCE REMOVECONSTR WILL WORK PROPERLY. 81 * 82 * @return true iff there is only one way to satisfy all the constraints in 83 * the solver. 84 * @throws TimeoutException 85 * @see {@link ISolver#removeConstr(IConstr)} 86 */ 87 public boolean hasASingleSolution() throws TimeoutException { 88 return hasASingleSolution(new VecInt()); 89 } 90 91 /** 92 * Please use that method only after a positive answer from 93 * isSatisfiable(assumptions) (else a runtime exception will be launched). 94 * 95 * @param assumptions 96 * a set of literals (dimacs numbering) that must be satisfied. 97 * @return true iff there is only one way to satisfy all the constraints in 98 * the solver using the provided set of assumptions. 99 * @throws TimeoutException 100 */ 101 public boolean hasASingleSolution(IVecInt assumptions) 102 throws TimeoutException { 103 int[] firstmodel = model(); 104 assert firstmodel != null; 105 IVecInt clause = new VecInt(firstmodel.length); 106 for (int q : firstmodel) { 107 clause.push(-q); 108 } 109 boolean result = false; 110 try { 111 IConstr added = addClause(clause); 112 result = !isSatisfiable(assumptions); 113 removeConstr(added); 114 } catch (ContradictionException e) { 115 result = true; 116 } 117 return result; 118 } 119 }