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;
31  
32  import java.io.PrintWriter;
33  
34  import org.sat4j.core.Vec;
35  import org.sat4j.reader.Reader;
36  import org.sat4j.specs.ContradictionException;
37  import org.sat4j.specs.ILogAble;
38  import org.sat4j.specs.IOptimizationProblem;
39  import org.sat4j.specs.IProblem;
40  import org.sat4j.specs.ISolver;
41  import org.sat4j.specs.IVec;
42  import org.sat4j.specs.IVecInt;
43  import org.sat4j.specs.TimeoutException;
44  import org.sat4j.tools.Backbone;
45  import org.sat4j.tools.LexicoDecorator;
46  import org.sat4j.tools.SolutionFoundListener;
47  
48  /**
49   * Allow to change the behavior of the launcher (either decision or optimization
50   * mode)
51   * 
52   * @since 2.3.3
53   * @author sroussel
54   * 
55   */
56  public interface ILauncherMode extends SolutionFoundListener {
57  
58      String SOLUTION_PREFIX = "v "; //$NON-NLS-1$
59  
60      String ANSWER_PREFIX = "s "; //$NON-NLS-1$
61  
62      String CURRENT_OPTIMUM_VALUE_PREFIX = "o ";
63  
64      /**
65       * Output of the launcher when the solver stops
66       * 
67       * @param solver
68       *            the solver that is launched by the launcher
69       * @param problem
70       *            the problem that is solved
71       * @param logger
72       *            the element that is able to log the result
73       * @param out
74       *            the printwriter to associate to the solver
75       * @param reader
76       *            the problem reader
77       * @param beginTime
78       *            the time at which the solver was launched
79       * @param displaySolutionLine
80       *            indicates whether the solution line shound be displayed or not
81       *            (not recommended for large solutions)
82       */
83      void displayResult(ISolver solver, IProblem problem, ILogAble logger,
84              PrintWriter out, Reader reader, long beginTime,
85              boolean displaySolutionLine);
86  
87      /**
88       * Main solver call: one call for a decision problem, a loop for an
89       * optimization problem.
90       * 
91       * @param problem
92       *            the problem to solve
93       * @param logger
94       *            the element that is able to log the result
95       * @param out
96       *            the printwriter to associate to the solver
97       * @param beginTime
98       *            the time at which the solver starts
99       * @return
100      */
101     void solve(IProblem problem, Reader reader, ILogAble logger,
102             PrintWriter out, long beginTime);
103 
104     /**
105      * Allows the launcher to specifically return an upper bound of the optimal
106      * solution in case of a time out (for maxsat competitions for instance).
107      * 
108      * @param isIncomplete
109      */
110     void setIncomplete(boolean isIncomplete);
111 
112     /**
113      * Allow the launcher to get the current status of the problem: SAT, UNSAT,
114      * UPPER_BOUND, etc.
115      * 
116      * @return
117      */
118     ExitCode getCurrentExitCode();
119 
120     /**
121      * Allow to set a specific exit code to the launcher (in case of trivial
122      * unsatisfiability for instance).
123      */
124     void setExitCode(ExitCode exitCode);
125 
126     /**
127      * The launcher is in decision mode: the answer is either SAT, UNSAT or
128      * UNKNOWN
129      */
130     ILauncherMode DECISION = new ILauncherMode() {
131 
132         private ExitCode exitCode = ExitCode.UNKNOWN;
133 
134         public void displayResult(ISolver solver, IProblem problem,
135                 ILogAble logger, PrintWriter out, Reader reader,
136                 long beginTime, boolean displaySolutionLine) {
137             if (solver != null) {
138                 out.flush();
139                 double wallclocktime = (System.currentTimeMillis() - beginTime) / 1000.0;
140                 solver.printStat(out);
141                 solver.printInfos(out);
142                 out.println(ANSWER_PREFIX + exitCode);
143                 if (exitCode != ExitCode.UNKNOWN
144                         && exitCode != ExitCode.UNSATISFIABLE) {
145                     int[] model = solver.model();
146                     if (System.getProperty("prime") != null) {
147                         int initiallength = model.length;
148                         logger.log("returning a prime implicant ...");
149                         long beginpi = System.currentTimeMillis();
150                         model = solver.primeImplicant();
151                         long endpi = System.currentTimeMillis();
152                         logger.log("removed " + (initiallength - model.length)
153                                 + " literals");
154                         logger.log("pi computation time: " + (endpi - beginpi)
155                                 + " ms");
156                     }
157                     if (System.getProperty("backbone") != null) {
158                         logger.log("computing the backbone of the formula ...");
159                         long beginpi = System.currentTimeMillis();
160                         model = solver.primeImplicant();
161                         try {
162                             IVecInt backbone = Backbone.compute(solver, model);
163                             long endpi = System.currentTimeMillis();
164                             out.print(solver.getLogPrefix());
165                             reader.decode(backbone.toArray(), out);
166                             out.println();
167                             logger.log("backbone computation time: "
168                                     + (endpi - beginpi) + " ms");
169                         } catch (TimeoutException e) {
170                             logger.log("timeout, cannot compute the backbone.");
171                         }
172 
173                     }
174                     if (nbSolutionFound > 1) {
175                         logger.log("Found " + nbSolutionFound + " solutions");
176                     }
177                     out.print(SOLUTION_PREFIX);
178                     reader.decode(model, out);
179                     out.println();
180                 }
181                 logger.log("Total wall clock time (in seconds) : " + wallclocktime); //$NON-NLS-1$
182             }
183         }
184 
185         private int nbSolutionFound;
186 
187         private PrintWriter out;
188         private long beginTime;
189 
190         public void solve(IProblem problem, Reader reader, ILogAble logger,
191                 PrintWriter out, long beginTime) {
192             this.exitCode = ExitCode.UNKNOWN;
193             this.out = out;
194             this.nbSolutionFound = 0;
195             this.beginTime = beginTime;
196             try {
197                 if (problem.isSatisfiable()) {
198                     if (this.exitCode == ExitCode.UNKNOWN) {
199                         this.exitCode = ExitCode.SATISFIABLE;
200                     }
201                 } else {
202                     if (this.exitCode == ExitCode.UNKNOWN) {
203                         this.exitCode = ExitCode.UNSATISFIABLE;
204                     }
205                 }
206             } catch (TimeoutException e) {
207                 logger.log("timeout");
208             }
209 
210         }
211 
212         public void setIncomplete(boolean isIncomplete) {
213         }
214 
215         public ExitCode getCurrentExitCode() {
216             return this.exitCode;
217         };
218 
219         public void onSolutionFound(int[] solution) {
220             this.nbSolutionFound++;
221             this.exitCode = ExitCode.SATISFIABLE;
222             this.out.printf("c Found solution #%d  (%.2f)s%n", nbSolutionFound,
223                     (System.currentTimeMillis() - beginTime) / 1000.0);
224         }
225 
226         public void onSolutionFound(IVecInt solution) {
227             throw new UnsupportedOperationException("Not implemented yet!");
228         }
229 
230         public void onUnsatTermination() {
231             if (this.exitCode == ExitCode.SATISFIABLE) {
232                 this.exitCode = ExitCode.OPTIMUM_FOUND;
233             }
234         }
235 
236         public void setExitCode(ExitCode exitCode) {
237             this.exitCode = exitCode;
238         }
239     };
240 
241     /**
242      * The launcher is in optimization mode: the answer is either SAT,
243      * UPPER_BOUND, OPTIMUM_FOUND, UNSAT or UNKNOWN. Using the incomplete
244      * property, the solver returns an upper bound of the optimal solution when
245      * a time out occurs.
246      */
247     ILauncherMode OPTIMIZATION = new ILauncherMode() {
248 
249         private ExitCode exitCode = ExitCode.UNKNOWN;
250 
251         private boolean isIncomplete = false;
252 
253         public void setIncomplete(boolean isIncomplete) {
254             this.isIncomplete = isIncomplete;
255         }
256 
257         public void displayResult(ISolver solver, IProblem problem,
258                 ILogAble logger, PrintWriter out, Reader reader,
259                 long beginTime, boolean displaySolutionLine) {
260             if (solver == null) {
261                 return;
262             }
263             System.out.flush();
264             out.flush();
265             solver.printStat(out);
266             solver.printInfos(out);
267             out.println(ANSWER_PREFIX + exitCode);
268             if (exitCode == ExitCode.SATISFIABLE
269                     || exitCode == ExitCode.OPTIMUM_FOUND || isIncomplete
270                     && exitCode == ExitCode.UPPER_BOUND) {
271                 if (displaySolutionLine) {
272                     out.print(SOLUTION_PREFIX);
273                     reader.decode(problem.model(), out);
274                     out.println();
275                 }
276                 IOptimizationProblem optproblem = (IOptimizationProblem) problem;
277                 if (!optproblem.hasNoObjectiveFunction()) {
278                     String objvalue;
279                     if (optproblem instanceof LexicoDecorator<?>) {
280                         IVec<Number> values = new Vec<Number>();
281                         LexicoDecorator<?> lexico = (LexicoDecorator<?>) optproblem;
282                         for (int i = 0; i < lexico.numberOfCriteria(); i++) {
283                             values.push(lexico.getObjectiveValue(i));
284                         }
285                         objvalue = values.toString();
286 
287                     } else {
288                         objvalue = optproblem.getObjectiveValue().toString();
289                     }
290                     logger.log("objective function=" + objvalue); //$NON-NLS-1$
291                 }
292             }
293 
294             logger.log("Total wall clock time (in seconds): " //$NON-NLS-1$
295                     + (System.currentTimeMillis() - beginTime) / 1000.0);
296         }
297 
298         public void solve(IProblem problem, Reader reader, ILogAble logger,
299                 PrintWriter out, long beginTime) {
300             boolean isSatisfiable = false;
301             IOptimizationProblem optproblem = (IOptimizationProblem) problem;
302             exitCode = ExitCode.UNKNOWN;
303 
304             try {
305                 while (optproblem.admitABetterSolution()) {
306                     if (!isSatisfiable) {
307                         if (optproblem.nonOptimalMeansSatisfiable()) {
308                             logger.log("SATISFIABLE");
309                             exitCode = ExitCode.SATISFIABLE;
310                             if (optproblem.hasNoObjectiveFunction()) {
311                                 return;
312                             }
313                         } else if (isIncomplete) {
314                             exitCode = ExitCode.UPPER_BOUND;
315                         }
316                         isSatisfiable = true;
317                         logger.log("OPTIMIZING..."); //$NON-NLS-1$
318                     }
319                     logger.log("Got one! Elapsed wall clock time (in seconds):" //$NON-NLS-1$
320                             + (System.currentTimeMillis() - beginTime) / 1000.0);
321                     out.println(CURRENT_OPTIMUM_VALUE_PREFIX
322                             + optproblem.getObjectiveValue());
323                     optproblem.discardCurrentSolution();
324                 }
325                 if (isSatisfiable) {
326                     exitCode = ExitCode.OPTIMUM_FOUND;
327                 } else {
328                     exitCode = ExitCode.UNSATISFIABLE;
329                 }
330             } catch (ContradictionException ex) {
331                 assert isSatisfiable;
332                 exitCode = ExitCode.OPTIMUM_FOUND;
333             } catch (TimeoutException e) {
334                 logger.log("timeout");
335             }
336 
337         }
338 
339         public ExitCode getCurrentExitCode() {
340             return exitCode;
341         }
342 
343         public void onSolutionFound(int[] solution) {
344             throw new UnsupportedOperationException("Not implemented yet!");
345         }
346 
347         public void onSolutionFound(IVecInt solution) {
348             throw new UnsupportedOperationException("Not implemented yet!");
349         }
350 
351         public void onUnsatTermination() {
352             // do nothing
353         }
354 
355         public void setExitCode(ExitCode exitCode) {
356             this.exitCode = exitCode;
357         }
358     };
359 
360 }