View Javadoc

1   /*******************************************************************************
2    * SAT4J: a SATisfiability library for Java Copyright (C) 2004-2008 Daniel Le
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.minisat.core.IOrder;
26  import org.sat4j.minisat.core.Solver;
27  import org.sat4j.pb.IPBSolver;
28  import org.sat4j.pb.ObjectiveFunction;
29  import org.sat4j.pb.PBSolverDecorator;
30  import org.sat4j.pb.orders.VarOrderHeapObjective;
31  import org.sat4j.specs.ContradictionException;
32  import org.sat4j.specs.IConstr;
33  import org.sat4j.specs.IOptimizationProblem;
34  import org.sat4j.specs.IVec;
35  import org.sat4j.specs.IVecInt;
36  import org.sat4j.specs.IteratorInt;
37  import org.sat4j.specs.TimeoutException;
38  
39  /**
40   * A decorator for solving weighted MAX SAT problems.
41   * 
42   * The first value of the list of literals in the addClause() method contains
43   * the weight of the clause.
44   * 
45   * @author daniel
46   * 
47   */
48  public class WeightedMaxSatDecorator extends PBSolverDecorator implements
49          IOptimizationProblem {
50  
51      public static final BigInteger SAT4J_MAX_BIG_INTEGER = new BigInteger("100000000000000000000000000000000000000000");
52  
53  	/**
54       * 
55       */
56      private static final long serialVersionUID = 1L;
57  
58      protected int nborigvars;
59  
60      private int nbexpectedclauses;
61  
62      private BigInteger falsifiedWeight = BigInteger.ZERO;
63  
64      protected int nbnewvar;
65  
66  	protected int[] prevmodel;
67  	protected boolean[] prevboolmodel;
68  
69      protected int[] prevfullmodel;
70      
71      private IConstr previousPBConstr;
72  
73      public WeightedMaxSatDecorator(IPBSolver solver) {
74          super(solver);
75          IOrder order = ((Solver<?>) solver).getOrder();
76          if (order instanceof VarOrderHeapObjective) {
77              ((VarOrderHeapObjective) order).setObjectiveFunction(obj);
78          }
79      }
80  
81      @Override
82      public int newVar(int howmany) {
83          nborigvars = super.newVar(howmany);
84          return nborigvars;
85      }
86  
87      @Override
88      public void setExpectedNumberOfClauses(int nb) {
89          nbexpectedclauses = nb;
90          lits.ensure(nb);
91          falsifiedWeight = BigInteger.ZERO;
92          super.setExpectedNumberOfClauses(nb);
93          super.newVar(nborigvars + nbexpectedclauses);
94      }
95  
96      @Override
97      public int[] model() {
98  		return prevmodel;
99      }
100 
101 	@Override
102 	public boolean model(int var) {
103 		return prevboolmodel[var - 1];
104     }
105 
106     protected BigInteger top = SAT4J_MAX_BIG_INTEGER;
107 
108     public void setTopWeight(BigInteger top) {
109         this.top = top;
110     }
111 
112 	/**
113 	 * Add a set of literals to the solver.
114 	 * 
115 	 * Here the assumption is that the first literal (literals[0]) is the weight
116 	 * of the constraint as found in the MAXSAT evaluation. if the weight is
117 	 * greater or equal to the top weight, then the clause is hard, else it is
118 	 * soft.
119 	 * 
120 	 * @param literals
121 	 *            a weighted clause, the weight being the first element of the
122 	 *            vector.
123 	 * @see #setTopWeight(int)
124 	 */
125     @Override
126     public IConstr addClause(IVecInt literals) throws ContradictionException {
127         int weight = literals.get(0);
128 		literals.delete(0);
129 		return addSoftClause(weight, literals);
130 	}
131 
132 	/**
133 	 * Add a hard clause in the solver, i.e. a clause that must be satisfied.
134 	 * 
135 	 * @param literals
136 	 *            the clause
137 	 * @return the constraint is it is not trivially satisfied.
138 	 * @throws ContradictionException
139 	 */
140 	public IConstr addHardClause(IVecInt literals)
141 			throws ContradictionException {
142 		return super.addClause(literals);
143 	}
144 
145 	/**
146 	 * Add a soft clause in the solver, i.e. a clause with a weight of 1.
147 	 * 
148 	 * @param literals
149 	 *            the clause.
150 	 * @return the constraint is it is not trivially satisfied.
151 	 * @throws ContradictionException
152 	 */
153 	public IConstr addSoftClause(IVecInt literals)
154 			throws ContradictionException {
155 		return addSoftClause(1, literals);
156 	}
157 
158 	/**
159 	 * Add a soft clause to the solver.
160 	 * 
161 	 * if the weight of the clause is greater of equal to the top weight, the
162 	 * clause will be considered as a hard clause.
163 	 * 
164 	 * @param weight
165 	 *            the weight of the clause
166 	 * @param literals
167 	 *            the clause
168 	 * @return the constraint is it is not trivially satisfied.
169 	 * @throws ContradictionException
170 	 */
171 	public IConstr addSoftClause(int weight, IVecInt literals)
172 			throws ContradictionException {
173 		return addSoftClause(BigInteger.valueOf(weight),literals);
174 	}
175 
176 	public IConstr addSoftClause(BigInteger weight, IVecInt literals)
177 		throws ContradictionException {
178         if (weight.compareTo(top)<0) {
179 
180             if (literals.size() == 1) {
181                 // if there is only a coefficient and a literal, no need to
182                 // create
183                 // a new variable
184                 // check first if the literal is already in the list:
185                 int lit = -literals.get(0);
186                 int index = lits.containsAt(lit);
187                 if (index != -1) {
188                     coefs.set(index, coefs.get(index).add(weight));
189                 } else {
190                     // check if the opposite literal is already there
191                     index = lits.containsAt(-lit);
192                     if (index != -1) {
193                     	falsifiedWeight = falsifiedWeight.add(weight);
194                         BigInteger oldw = coefs.get(index);
195                         BigInteger diff = oldw.subtract(weight);
196                         if (diff.signum() > 0) {
197                             coefs.set(index, diff);
198                         } else if (diff.signum() < 0) {
199                             lits.set(index, lit);
200                             coefs.set(index, diff.abs());
201                             // remove from falsifiedWeight the
202                             // part of the weight that will remain 
203                             // in the objective function
204                             falsifiedWeight = falsifiedWeight.add(diff);
205                         } else {
206                             assert diff.signum() == 0;                            
207                             lits.delete(index);
208                             coefs.delete(index);
209                         }
210                     } else {
211                         lits.push(lit);
212                         coefs.push(weight);
213                     }
214                 }
215                 return null;
216             }
217             coefs.push(weight);
218             int newvar = nborigvars + ++nbnewvar;
219 			literals.push(newvar);
220             lits.push(newvar);
221         }
222         return super.addClause(literals);
223     }
224 
225 	/**
226 	 * Set some literals whose sum must be minimized.
227 	 * 
228 	 * @param literals
229 	 *            the sum of those literals must be minimized.
230 	 */
231 	public void addLiteralsToMinimize(IVecInt literals) {
232 		for (IteratorInt it = literals.iterator(); it.hasNext();) {
233 			lits.push(it.next());
234 			coefs.push(BigInteger.ONE);
235 		}
236 	}
237 
238 	/**
239 	 * Set some literals whose sum must be minimized.
240 	 * 
241 	 * @param literals
242 	 *            the sum of those literals must be minimized.
243 	 * @param coefficients
244 	 *            the weight of the literals.
245 	 */
246 	public void addWeightedLiteralsToMinimize(IVecInt literals,
247 			IVec<BigInteger> coefficients) {
248 		if (literals.size() != coefs.size())
249 			throw new IllegalArgumentException();
250 		for (int i = 0; i < literals.size(); i++) {
251 			lits.push(literals.get(i));
252 			coefs.push(coefficients.get(i));
253 		}
254 	}
255 
256 	/**
257 	 * Set some literals whose sum must be minimized.
258 	 * 
259 	 * @param literals
260 	 *            the sum of those literals must be minimized.
261 	 * @param coefficients
262 	 *            the weight of the literals.
263 	 */
264 	public void addWeightedLiteralsToMinimize(IVecInt literals,
265 			IVecInt coefficients) {
266 		if (literals.size() != coefficients.size())
267 			throw new IllegalArgumentException();
268 		for (int i = 0; i < literals.size(); i++) {
269 			lits.push(literals.get(i));
270 			coefs.push(BigInteger.valueOf(coefficients.get(i)));
271 		}
272     }
273     
274     public boolean admitABetterSolution() throws TimeoutException {
275     	return admitABetterSolution(VecInt.EMPTY);
276     }
277     
278     public boolean admitABetterSolution(IVecInt assumps)
279 		throws TimeoutException {
280         boolean result = super.isSatisfiable(assumps,true);
281         if (result) {
282 			prevboolmodel = new boolean[nVars()];
283 			for (int i = 0; i < nVars(); i++) {
284 				prevboolmodel[i] = decorated().model(i + 1);
285 			}
286             int nbtotalvars = nborigvars + nbnewvar;
287             if (prevfullmodel == null)
288                 prevfullmodel = new int[nbtotalvars];
289             for (int i = 1; i <= nbtotalvars; i++) {
290                 prevfullmodel[i - 1] = super.model(i) ? i : -i;
291             }
292             prevmodel = new int[nborigvars];
293 			for (int i = 0; i < nborigvars; i++) {
294 				prevmodel[i] = prevfullmodel[i];
295 			}
296 			calculateObjective();
297         } else {
298 			if (previousPBConstr != null) {
299 				decorated().removeConstr(previousPBConstr);
300 				previousPBConstr = null;
301 			}
302 		}
303         return result;
304     }
305 
306     @Override
307     public void reset() {
308         coefs.clear();
309         lits.clear();
310         nbnewvar = 0;
311         previousPBConstr = null;
312         super.reset();
313     }
314 
315     public boolean hasNoObjectiveFunction() {
316         return false;
317     }
318 
319     public boolean nonOptimalMeansSatisfiable() {
320         return false;
321     }
322 
323     private BigInteger counter;
324 
325     public Number calculateObjective() {
326         counter = BigInteger.ZERO;
327         for (int q : prevfullmodel) {
328             int index = lits.containsAt(q);
329             if (index != -1) {
330                 counter = counter.add(coefs.get(index));
331             }
332         }
333         return falsifiedWeight.add(counter);
334     }
335 
336     private final IVecInt lits = new VecInt();
337 
338     private final IVec<BigInteger> coefs = new Vec<BigInteger>();
339 
340     private final ObjectiveFunction obj = new ObjectiveFunction(lits, coefs);
341 
342     public void discardCurrentSolution() throws ContradictionException {
343         assert lits.size() == coefs.size();
344         if (previousPBConstr!=null) {
345         	removeSubsumedConstr(previousPBConstr);
346         }
347         previousPBConstr = super.addPseudoBoolean(lits, coefs, false, counter.add(BigInteger.ONE.negate()));
348     }
349 
350 	public Number getObjectiveValue() {
351 		return falsifiedWeight.add(counter);
352 	}
353 
354 	public void discard() throws ContradictionException {
355 		discardCurrentSolution();
356 	}
357 
358 	public void forceObjectiveValueTo(Number forcedValue)
359 			throws ContradictionException {
360 		super.addPseudoBoolean(lits, coefs, false, (BigInteger)forcedValue);
361 	}
362 }