View Javadoc

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.pb;
31  
32  import java.math.BigInteger;
33  
34  import org.sat4j.core.VecInt;
35  import org.sat4j.specs.ContradictionException;
36  import org.sat4j.specs.IConstr;
37  import org.sat4j.specs.IOptimizationProblem;
38  import org.sat4j.specs.IVecInt;
39  import org.sat4j.specs.TimeoutException;
40  
41  /**
42   * A decorator that computes minimal pseudo boolean models.
43   * 
44   * @author daniel
45   * 
46   */
47  public class PseudoOptDecorator extends PBSolverDecorator implements
48          IOptimizationProblem {
49  
50      /**
51       * 
52       */
53      private static final long serialVersionUID = 1L;
54  
55      private BigInteger objectiveValue;
56  
57      private int[] prevmodel;
58      private int[] prevmodelwithadditionalvars;
59  
60      private boolean[] prevfullmodel;
61  
62      private IConstr previousPBConstr;
63  
64      private boolean isSolutionOptimal;
65  
66      private final boolean nonOptimalMeansSatisfiable;
67  
68      private final boolean useAnImplicantForEvaluation;
69  
70      /**
71       * Create a PB decorator for which a non optimal solution means that the
72       * problem is satisfiable.
73       * 
74       * @param solver
75       *            a PB solver.
76       */
77      public PseudoOptDecorator(IPBSolver solver) {
78          this(solver, true);
79      }
80  
81      /**
82       * Create a PB decorator with a specific semantic of non optimal solution.
83       * 
84       * @param solver
85       *            a PB solver
86       * @param nonOptimalMeansSatisfiable
87       *            true if a suboptimal solution means that the problem is
88       *            satisfiable (e.g. as in the PB competition), else false (e.g.
89       *            as in the MAXSAT competition).
90       */
91      public PseudoOptDecorator(IPBSolver solver,
92              boolean nonOptimalMeansSatisfiable) {
93          this(solver, nonOptimalMeansSatisfiable, false);
94      }
95  
96      /**
97       * Create a PB decorator with a specific semantic of non optimal solution.
98       * 
99       * @param solver
100      *            a PB solver
101      * @param nonOptimalMeansSatisfiable
102      *            true if a suboptimal solution means that the problem is
103      *            satisfiable (e.g. as in the PB competition), else false (e.g.
104      *            as in the MAXSAT competition).
105      * @param useAnImplicantForEvaluation
106      *            uses an implicant (a prime implicant computed using
107      *            {@link #primeImplicant()}) instead of a plain model to
108      *            evaluate the objective function.
109      */
110     public PseudoOptDecorator(IPBSolver solver,
111             boolean nonOptimalMeansSatisfiable,
112             boolean useAnImplicantForEvaluation) {
113         super(solver);
114         this.nonOptimalMeansSatisfiable = nonOptimalMeansSatisfiable;
115         this.useAnImplicantForEvaluation = useAnImplicantForEvaluation;
116     }
117 
118     @Override
119     public boolean isSatisfiable() throws TimeoutException {
120         return isSatisfiable(VecInt.EMPTY);
121     }
122 
123     @Override
124     public boolean isSatisfiable(boolean global) throws TimeoutException {
125         return isSatisfiable(VecInt.EMPTY, global);
126     }
127 
128     @Override
129     public boolean isSatisfiable(IVecInt assumps, boolean global)
130             throws TimeoutException {
131         boolean result = super.isSatisfiable(assumps, true);
132         if (result) {
133             this.prevmodel = super.model();
134             this.prevmodelwithadditionalvars = super
135                     .modelWithInternalVariables();
136             this.prevfullmodel = new boolean[nVars()];
137             for (int i = 0; i < nVars(); i++) {
138                 this.prevfullmodel[i] = decorated().model(i + 1);
139             }
140         } else {
141             if (this.previousPBConstr != null) {
142                 decorated().removeConstr(this.previousPBConstr);
143                 this.previousPBConstr = null;
144             }
145         }
146         return result;
147     }
148 
149     @Override
150     public boolean isSatisfiable(IVecInt assumps) throws TimeoutException {
151         return isSatisfiable(assumps, true);
152     }
153 
154     @Override
155     public void setObjectiveFunction(ObjectiveFunction objf) {
156         decorated().setObjectiveFunction(objf);
157     }
158 
159     public boolean admitABetterSolution() throws TimeoutException {
160         return admitABetterSolution(VecInt.EMPTY);
161     }
162 
163     public boolean admitABetterSolution(IVecInt assumps)
164             throws TimeoutException {
165         try {
166             this.isSolutionOptimal = false;
167             boolean result = super.isSatisfiable(assumps, true);
168             if (result) {
169                 this.prevmodel = super.model();
170                 this.prevmodelwithadditionalvars = super
171                         .modelWithInternalVariables();
172                 this.prevfullmodel = new boolean[nVars()];
173                 for (int i = 0; i < nVars(); i++) {
174                     this.prevfullmodel[i] = decorated().model(i + 1);
175                 }
176                 if (decorated().getObjectiveFunction() != null) {
177                     calculateObjective();
178                 }
179             } else {
180                 this.isSolutionOptimal = true;
181                 if (this.previousPBConstr != null) {
182                     decorated().removeConstr(this.previousPBConstr);
183                     this.previousPBConstr = null;
184                 }
185             }
186             return result;
187         } catch (TimeoutException te) {
188             if (this.previousPBConstr != null) {
189                 decorated().removeConstr(this.previousPBConstr);
190                 this.previousPBConstr = null;
191             }
192             throw te;
193         }
194     }
195 
196     public boolean hasNoObjectiveFunction() {
197         return decorated().getObjectiveFunction() == null;
198     }
199 
200     public boolean nonOptimalMeansSatisfiable() {
201         return nonOptimalMeansSatisfiable;
202     }
203 
204     public Number calculateObjective() {
205         if (decorated().getObjectiveFunction() == null) {
206             throw new UnsupportedOperationException(
207                     "The problem does not contain an objective function");
208         }
209         if (this.useAnImplicantForEvaluation) {
210             this.objectiveValue = decorated().getObjectiveFunction()
211                     .calculateDegreeImplicant(decorated());
212         } else {
213             this.objectiveValue = decorated().getObjectiveFunction()
214                     .calculateDegree(decorated());
215         }
216         return getObjectiveValue();
217     }
218 
219     public void discardCurrentSolution() throws ContradictionException {
220         if (this.previousPBConstr != null) {
221             super.removeSubsumedConstr(this.previousPBConstr);
222         }
223         if (decorated().getObjectiveFunction() != null
224                 && this.objectiveValue != null) {
225             this.previousPBConstr = super.addPseudoBoolean(decorated()
226                     .getObjectiveFunction().getVars(), decorated()
227                     .getObjectiveFunction().getCoeffs(), false,
228                     this.objectiveValue.subtract(BigInteger.ONE));
229         }
230     }
231 
232     @Override
233     public void reset() {
234         this.previousPBConstr = null;
235         super.reset();
236     }
237 
238     @Override
239     public int[] model() {
240         // DLB findbugs ok
241         return this.prevmodel;
242     }
243 
244     @Override
245     public boolean model(int var) {
246         return this.prevfullmodel[var - 1];
247     }
248 
249     @Override
250     public String toString(String prefix) {
251         return prefix + "Pseudo Boolean Optimization by upper bound\n"
252                 + super.toString(prefix);
253     }
254 
255     public Number getObjectiveValue() {
256         return this.objectiveValue.add(decorated().getObjectiveFunction()
257                 .getCorrection());
258     }
259 
260     public void discard() throws ContradictionException {
261         discardCurrentSolution();
262     }
263 
264     public void forceObjectiveValueTo(Number forcedValue)
265             throws ContradictionException {
266         super.addPseudoBoolean(decorated().getObjectiveFunction().getVars(),
267                 decorated().getObjectiveFunction().getCoeffs(), false,
268                 (BigInteger) forcedValue);
269     }
270 
271     public boolean isOptimal() {
272         return this.isSolutionOptimal;
273     }
274 
275     @Override
276     public int[] modelWithInternalVariables() {
277         return this.prevmodelwithadditionalvars;
278     }
279 }