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  package org.sat4j.maxsat;
20  
21  import java.math.BigInteger;
22  
23  import org.sat4j.core.Vec;
24  import org.sat4j.core.VecInt;
25  import org.sat4j.pb.IPBSolver;
26  import org.sat4j.pb.PBSolverDecorator;
27  import org.sat4j.specs.ContradictionException;
28  import org.sat4j.specs.IConstr;
29  import org.sat4j.specs.IOptimizationProblem;
30  import org.sat4j.specs.IVec;
31  import org.sat4j.specs.IVecInt;
32  import org.sat4j.specs.TimeoutException;
33  
34  /**
35   * A decorator that computes minimal cost models. That problem is also known as
36   * binate covering problem.
37   * 
38   * Please make sure that newVar(howmany) is called first to setup the decorator.
39   * 
40   * @author daniel
41   * 
42   */
43  public class MinCostDecorator extends PBSolverDecorator implements
44  		IOptimizationProblem {
45  
46  	/**
47       * 
48       */
49  	private static final long serialVersionUID = 1L;
50  
51  	private int[] costs;
52  
53  	private int[] prevmodel;
54  
55  	private final IVecInt vars = new VecInt();
56  
57  	private final IVec<BigInteger> coeffs = new Vec<BigInteger>();
58  
59  	private int objectivevalue;
60  
61  	private IConstr prevConstr;
62  
63  	private boolean isSolutionOptimal;
64  	
65  	public MinCostDecorator(IPBSolver solver) {
66  		super(solver);
67  	}
68  
69  	/*
70  	 * (non-Javadoc)
71  	 * 
72  	 * @see org.sat4j.tools.SolverDecorator#newVar()
73  	 */
74  	@Override
75  	public int newVar() {
76  		throw new UnsupportedOperationException();
77  	}
78  
79  	/**
80  	 * Setup the number of variables to use inside the solver.
81  	 * 
82  	 * It is mandatory to call that method before setting the cost of the
83  	 * variables.
84  	 * 
85  	 * @param howmany
86  	 *            the maximum number of variables in the solver.
87  	 */
88  	@Override
89  	public int newVar(int howmany) {
90  		costs = new int[howmany + 1];
91  		// Arrays.fill(costs, 1);
92  		vars.clear();
93  		coeffs.clear();
94  		for (int i = 1; i <= howmany; i++) {
95  			vars.push(i);
96  			coeffs.push(BigInteger.ZERO);
97  		}
98  		// should the default cost be 1????
99  		// here it is 0
100 		return super.newVar(howmany);
101 	}
102 
103 	/**
104 	 * to know the cost of a given var.
105 	 * 
106 	 * @param var
107 	 *            a variable in dimacs format
108 	 * @return the cost of that variable when assigned to true
109 	 */
110 	public int costOf(int var) {
111 		return costs[var];
112 	}
113 
114 	/**
115 	 * to set the cost of a given var.
116 	 * 
117 	 * @param var
118 	 *            a variable in dimacs format
119 	 * @param cost
120 	 *            the cost of var when assigned to true
121 	 */
122 	public void setCost(int var, int cost) {
123 		costs[var] = cost;
124 		coeffs.set(var - 1, BigInteger.valueOf(cost));
125 	}
126 
127 	public boolean admitABetterSolution() throws TimeoutException {
128 		return admitABetterSolution(VecInt.EMPTY);
129 	}
130 
131 	public boolean admitABetterSolution(IVecInt assumps)
132 			throws TimeoutException {
133 		isSolutionOptimal = false;
134 		boolean result = super.isSatisfiable(assumps, true);
135 		if (result) {
136 			prevmodel = super.model();
137 			calculateObjective();
138 		} else {
139 			isSolutionOptimal = true;
140 		}
141 		return result;
142 	}
143 
144 	public boolean hasNoObjectiveFunction() {
145 		return false;
146 	}
147 
148 	public boolean nonOptimalMeansSatisfiable() {
149 		return true;
150 	}
151 
152 	public Number calculateObjective() {
153 		objectivevalue = calculateDegree(prevmodel);
154 		return new Integer(objectivevalue);
155 	}
156 
157 	private int calculateDegree(int[] prevmodel2) {
158 		int tmpcost = 0;
159 		for (int i = 1; i < costs.length; i++) {
160 			if (prevmodel2[i - 1] > 0) {
161 				tmpcost += costs[i];
162 			}
163 		}
164 		return tmpcost;
165 	}
166 
167 	public void discardCurrentSolution() throws ContradictionException {
168 		if (prevConstr!=null) {
169 			super.removeSubsumedConstr(prevConstr);
170 		}
171 		try {
172 			prevConstr = super.addPseudoBoolean(vars, coeffs, false, BigInteger
173 					.valueOf(objectivevalue - 1));
174 		} catch (ContradictionException e) {
175 			isSolutionOptimal = true;
176 			throw e;
177 		}
178 	}
179 
180 	@Override
181 	public void reset() {
182 		prevConstr = null;
183 		super.reset();
184 	}
185 
186 	@Override
187 	public int[] model() {
188 		// DLB findbugs ok
189 		return prevmodel;
190 	}
191 
192 	public Number getObjectiveValue() {
193 		return objectivevalue;
194 	}
195 
196 	public void discard() throws ContradictionException {
197 		discardCurrentSolution();
198 	}
199 
200 	public void forceObjectiveValueTo(Number forcedValue)
201 			throws ContradictionException {
202 		super.addPseudoBoolean(vars, coeffs, false, (BigInteger)
203 				forcedValue);
204 	}
205 
206 	public boolean isOptimal() {
207 		return isSolutionOptimal;
208 	}
209 }