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   * 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   *******************************************************************************/
28  package org.sat4j;
29  
30  import java.io.BufferedReader;
31  import java.io.FileNotFoundException;
32  import java.io.IOException;
33  import java.io.InputStreamReader;
34  import java.io.ObjectInputStream;
35  import java.io.PrintWriter;
36  import java.io.Serializable;
37  import java.net.URL;
38  import java.util.Properties;
39  
40  import org.sat4j.core.ASolverFactory;
41  import org.sat4j.reader.ParseFormatException;
42  import org.sat4j.reader.Reader;
43  import org.sat4j.specs.ContradictionException;
44  import org.sat4j.specs.IProblem;
45  import org.sat4j.specs.ISolver;
46  import org.sat4j.specs.TimeoutException;
47  
48  /**
49   * That class is used by launchers used to solve decision problems, i.e.
50   * problems with YES/NO/UNKNOWN answers.
51   * 
52   * @author leberre
53   * 
54   */
55  public abstract class AbstractLauncher implements Serializable {
56  
57  	/**
58  	 * 
59  	 */
60  	private static final long serialVersionUID = 1L;
61  
62  	public static final String SOLUTION_PREFIX = "v "; //$NON-NLS-1$
63  
64  	public static final String ANSWER_PREFIX = "s "; //$NON-NLS-1$
65  
66  	public static final String COMMENT_PREFIX = "c "; //$NON-NLS-1$
67  
68  	private long beginTime;
69  
70  	private ExitCode exitCode = ExitCode.UNKNOWN;
71  
72  	protected Reader reader;
73  
74  	private transient PrintWriter out = new PrintWriter(System.out, true);
75  
76  	protected transient Thread shutdownHook = new Thread() {
77  		@Override
78  		public void run() {
79  			displayResult();
80  		}
81  	};
82  
83  	protected ISolver solver;
84  
85  	private boolean silent = false;
86  
87  	protected AbstractLauncher() {
88  		Runtime.getRuntime().addShutdownHook(shutdownHook);
89  	}
90  
91  	protected void displayResult() {
92  		if (solver != null) {
93  			System.out.flush();
94  			out.flush();
95  			double wallclocktime = (System.currentTimeMillis() - beginTime) / 1000.0;
96  			solver.printStat(out, COMMENT_PREFIX);
97  			solver.printInfos(out, COMMENT_PREFIX);
98  			out.println(ANSWER_PREFIX + exitCode);
99  			if (exitCode == ExitCode.SATISFIABLE) {
100 				int[] model = solver.model();
101 				out.print(SOLUTION_PREFIX);
102 				reader.decode(model, out);
103 				out.println();
104 			}
105 			log("Total wall clock time (in seconds) : " + wallclocktime); //$NON-NLS-1$
106 		}
107 	}
108 
109 	public abstract void usage();
110 
111 	/**
112 	 * @throws IOException
113 	 */
114 	protected final void displayHeader() {
115 		displayLicense();
116 		URL url = AbstractLauncher.class.getResource("/sat4j.version"); //$NON-NLS-1$
117 		if (url == null) {
118 			log("no version file found!!!"); //$NON-NLS-1$			
119 		} else {
120 			BufferedReader in = null;
121 			try {
122 				in = new BufferedReader(new InputStreamReader(url.openStream()));
123 				log("version " + in.readLine()); //$NON-NLS-1$
124 			} catch (IOException e) {
125 				log("c ERROR: " + e.getMessage());
126 			} finally {
127 				if (in != null) {
128 					try {
129 						in.close();
130 					} catch (IOException e) {
131 						log("c ERROR: " + e.getMessage());
132 					}
133 				}
134 			}
135 		}
136 		Properties prop = System.getProperties();
137 		String[] infoskeys = {
138 				"java.runtime.name", "java.vm.name", "java.vm.version", "java.vm.vendor", "sun.arch.data.model", "java.version", "os.name", "os.version", "os.arch" }; //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$//$NON-NLS-5$
139 		for (int i = 0; i < infoskeys.length; i++) {
140 			String key = infoskeys[i];
141 			log(key
142 					+ ((key.length() < 14) ? "\t\t" : "\t") + prop.getProperty(key)); //$NON-NLS-1$
143 		}
144 		Runtime runtime = Runtime.getRuntime();
145 		log("Free memory \t\t" + runtime.freeMemory()); //$NON-NLS-1$
146 		log("Max memory \t\t" + runtime.maxMemory()); //$NON-NLS-1$
147 		log("Total memory \t\t" + runtime.totalMemory()); //$NON-NLS-1$
148 		log("Number of processors \t" + runtime.availableProcessors()); //$NON-NLS-1$
149 	}
150 
151 	public void displayLicense() {
152 		log("SAT4J: a SATisfiability library for Java (c) 2004-2010 Daniel Le Berre"); //$NON-NLS-1$
153 		log("This is free software under the dual EPL/GNU LGPL licenses."); //$NON-NLS-1$
154 		log("See www.sat4j.org for details."); //$NON-NLS-1$
155 	}
156 
157 	/**
158 	 * Reads a problem file from the command line.
159 	 * 
160 	 * @param problemname
161 	 *            the fully qualified name of the problem.
162 	 * @return a reference to the problem to solve
163 	 * @throws FileNotFoundException
164 	 *             if the file is not found
165 	 * @throws ParseFormatException
166 	 *             if the problem is not expressed using the right format
167 	 * @throws IOException
168 	 *             for other IO problems
169 	 * @throws ContradictionException
170 	 *             if the problem is found trivially unsat
171 	 */
172 	protected IProblem readProblem(String problemname)
173 			throws FileNotFoundException, ParseFormatException, IOException,
174 			ContradictionException {
175 		log("solving " + problemname); //$NON-NLS-1$
176 		log("reading problem ... "); //$NON-NLS-1$
177 		reader = createReader(solver, problemname);
178 		IProblem problem = reader.parseInstance(problemname);
179 		log("... done. Wall clock time " //$NON-NLS-1$
180 				+ (System.currentTimeMillis() - beginTime) / 1000.0 + "s."); //$NON-NLS-1$
181 		log("#vars     " + problem.nVars()); //$NON-NLS-1$
182 		log("#constraints  " + problem.nConstraints()); //$NON-NLS-1$
183 		problem.printInfos(out, COMMENT_PREFIX);
184 		return problem;
185 	}
186 
187 	protected abstract Reader createReader(ISolver theSolver, String problemname);
188 
189 	public void run(String[] args) {
190 
191 		try {
192 			displayHeader();
193 			solver = configureSolver(args);
194 			if (solver == null) {
195 				usage();
196 				return;
197 			}
198 			String instanceName = getInstanceName(args);
199 			if (instanceName == null) {
200 				usage();
201 				return;
202 			}
203 			beginTime = System.currentTimeMillis();
204 			IProblem problem = readProblem(instanceName);
205 			try {
206 				solve(problem);
207 			} catch (TimeoutException e) {
208 				log("timeout"); //$NON-NLS-1$
209 			}
210 		} catch (FileNotFoundException e) {
211 			System.err.println("FATAL " + e.getLocalizedMessage());
212 		} catch (IOException e) {
213 			System.err.println("FATAL " + e.getLocalizedMessage());
214 		} catch (ContradictionException e) {
215 			exitCode = ExitCode.UNSATISFIABLE;
216 			log("(trivial inconsistency)"); //$NON-NLS-1$
217 		} catch (ParseFormatException e) {
218 			System.err.println("FATAL " + e.getLocalizedMessage());
219 		}
220 	}
221 
222 	protected abstract String getInstanceName(String[] args);
223 
224 	protected abstract ISolver configureSolver(String[] args);
225 
226 	/**
227 	 * Display messages as comments on STDOUT
228 	 * 
229 	 * @param message
230 	 */
231 	public void log(String message) {
232 		if (!silent)
233 			out.println(COMMENT_PREFIX + message);
234 	}
235 
236 	protected void solve(IProblem problem) throws TimeoutException {
237 		exitCode = problem.isSatisfiable() ? ExitCode.SATISFIABLE
238 				: ExitCode.UNSATISFIABLE;
239 	}
240 
241 	/**
242 	 * Change the value of the exit code in the Launcher
243 	 * 
244 	 * @param exitCode
245 	 *            the new ExitCode
246 	 */
247 	public final void setExitCode(ExitCode exitCode) {
248 		this.exitCode = exitCode;
249 	}
250 
251 	/**
252 	 * Get the value of the ExitCode
253 	 * 
254 	 * @return the current value of the Exitcode
255 	 */
256 	public final ExitCode getExitCode() {
257 		return exitCode;
258 	}
259 
260 	/**
261 	 * Obtaining the current time spent since the beginning of the solving
262 	 * process.
263 	 * 
264 	 * @return the time signature at the beginning of the run() method.
265 	 */
266 	public final long getBeginTime() {
267 		return beginTime;
268 	}
269 
270 	/**
271 	 * 
272 	 * @return the reader used to parse the instance
273 	 */
274 	public final Reader getReader() {
275 		return reader;
276 	}
277 
278 	/**
279 	 * To change the output stream on which statistics are displayed. By
280 	 * default, the solver displays everything on System.out.
281 	 * 
282 	 * @param out
283 	 */
284 	public void setLogWriter(PrintWriter out) {
285 		this.out = out;
286 	}
287 
288 	public PrintWriter getLogWriter() {
289 		return out;
290 	}
291 
292 	protected void setSilent(boolean b) {
293 		silent = b;
294 	}
295 
296 	private void readObject(ObjectInputStream stream) throws IOException,
297 			ClassNotFoundException {
298 		stream.defaultReadObject();
299 		out = new PrintWriter(System.out, true);
300 		shutdownHook = new Thread() {
301 			@Override
302 			public void run() {
303 				displayResult();
304 			}
305 		};
306 	}
307 
308 	protected <T extends ISolver> void showAvailableSolvers(
309 			ASolverFactory<T> afactory) {
310 		if (afactory != null) {
311 			log("Available solvers: "); //$NON-NLS-1$
312 			String[] names = afactory.solverNames();
313 			for (int i = 0; i < names.length; i++) {
314 				log(names[i]);
315 			}
316 		}
317 	}
318 }