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 + " solution(s)");
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 int nbSolutions;
250 
251         private ExitCode exitCode = ExitCode.UNKNOWN;
252 
253         private boolean isIncomplete = false;
254 
255         public void setIncomplete(boolean isIncomplete) {
256             this.isIncomplete = isIncomplete;
257         }
258 
259         public void displayResult(ISolver solver, IProblem problem,
260                 ILogAble logger, PrintWriter out, Reader reader,
261                 long beginTime, boolean displaySolutionLine) {
262             if (solver == null) {
263                 return;
264             }
265             System.out.flush();
266             out.flush();
267             solver.printStat(out);
268             solver.printInfos(out);
269             out.println(ANSWER_PREFIX + exitCode);
270             if (exitCode == ExitCode.SATISFIABLE
271                     || exitCode == ExitCode.OPTIMUM_FOUND || isIncomplete
272                     && exitCode == ExitCode.UPPER_BOUND) {
273                 assert this.nbSolutions > 0;
274                 logger.log("Found " + this.nbSolutions + " solution(s)");
275 
276                 if (displaySolutionLine) {
277                     out.print(SOLUTION_PREFIX);
278                     reader.decode(problem.model(), out);
279                     out.println();
280                 }
281                 IOptimizationProblem optproblem = (IOptimizationProblem) problem;
282                 if (!optproblem.hasNoObjectiveFunction()) {
283                     String objvalue;
284                     if (optproblem instanceof LexicoDecorator<?>) {
285                         IVec<Number> values = new Vec<Number>();
286                         LexicoDecorator<?> lexico = (LexicoDecorator<?>) optproblem;
287                         for (int i = 0; i < lexico.numberOfCriteria(); i++) {
288                             values.push(lexico.getObjectiveValue(i));
289                         }
290                         objvalue = values.toString();
291 
292                     } else {
293                         objvalue = optproblem.getObjectiveValue().toString();
294                     }
295                     logger.log("objective function=" + objvalue); //$NON-NLS-1$
296                 }
297             }
298 
299             logger.log("Total wall clock time (in seconds): " //$NON-NLS-1$
300                     + (System.currentTimeMillis() - beginTime) / 1000.0);
301         }
302 
303         public void solve(IProblem problem, Reader reader, ILogAble logger,
304                 PrintWriter out, long beginTime) {
305             boolean isSatisfiable = false;
306             this.nbSolutions = 0;
307             IOptimizationProblem optproblem = (IOptimizationProblem) problem;
308             exitCode = ExitCode.UNKNOWN;
309 
310             try {
311                 while (optproblem.admitABetterSolution()) {
312                     ++this.nbSolutions;
313                     if (!isSatisfiable) {
314                         if (optproblem.nonOptimalMeansSatisfiable()) {
315                             logger.log("SATISFIABLE");
316                             exitCode = ExitCode.SATISFIABLE;
317                             if (optproblem.hasNoObjectiveFunction()) {
318                                 return;
319                             }
320                         } else if (isIncomplete) {
321                             exitCode = ExitCode.UPPER_BOUND;
322                         }
323                         isSatisfiable = true;
324                         logger.log("OPTIMIZING..."); //$NON-NLS-1$
325                     }
326                     logger.log("Got one! Elapsed wall clock time (in seconds):" //$NON-NLS-1$
327                             + (System.currentTimeMillis() - beginTime) / 1000.0);
328                     out.println(CURRENT_OPTIMUM_VALUE_PREFIX
329                             + optproblem.getObjectiveValue());
330                     optproblem.discardCurrentSolution();
331                 }
332                 if (isSatisfiable) {
333                     exitCode = ExitCode.OPTIMUM_FOUND;
334                 } else {
335                     exitCode = ExitCode.UNSATISFIABLE;
336                 }
337             } catch (ContradictionException ex) {
338                 assert isSatisfiable;
339                 exitCode = ExitCode.OPTIMUM_FOUND;
340             } catch (TimeoutException e) {
341                 logger.log("timeout");
342             }
343 
344         }
345 
346         public ExitCode getCurrentExitCode() {
347             return exitCode;
348         }
349 
350         public void onSolutionFound(int[] solution) {
351             throw new UnsupportedOperationException("Not implemented yet!");
352         }
353 
354         public void onSolutionFound(IVecInt solution) {
355             throw new UnsupportedOperationException("Not implemented yet!");
356         }
357 
358         public void onUnsatTermination() {
359             // do nothing
360         }
361 
362         public void setExitCode(ExitCode exitCode) {
363             this.exitCode = exitCode;
364         }
365     };
366 
367 }