/*******************************************************************************
* SAT4J: a SATisfiability library for Java Copyright (C) 2004-2008 Daniel Le Berre
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU Lesser General Public License Version 2.1 or later (the
* "LGPL"), in which case the provisions of the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of the LGPL, and not to allow others to use your version of
* this file under the terms of the EPL, indicate your decision by deleting
* the provisions above and replace them with the notice and other provisions
* required by the LGPL. If you do not delete the provisions above, a recipient
* may use your version of this file under the terms of the EPL or the LGPL.
*
* Based on the original MiniSat specification from:
*
* An extensible SAT solver. Niklas Een and Niklas Sorensson. Proceedings of the
* Sixth International Conference on Theory and Applications of Satisfiability
* Testing, LNCS 2919, pp 502-518, 2003.
*
* See www.minisat.se for the original solver in C++.
*
*******************************************************************************/
package org.sat4j;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.PrintWriter;
import java.io.Serializable;
import java.net.URL;
import java.util.Properties;
import org.sat4j.core.ASolverFactory;
import org.sat4j.reader.ParseFormatException;
import org.sat4j.reader.Reader;
import org.sat4j.specs.ContradictionException;
import org.sat4j.specs.IProblem;
import org.sat4j.specs.ISolver;
import org.sat4j.specs.TimeoutException;
/**
* That class is used by launchers used to solve decision problems, i.e.
* problems with YES/NO/UNKNOWN answers.
*
* @author leberre
*
*/
public abstract class AbstractLauncher implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
public static final String SOLUTION_PREFIX = "v "; //$NON-NLS-1$
public static final String ANSWER_PREFIX = "s "; //$NON-NLS-1$
public static final String COMMENT_PREFIX = "c "; //$NON-NLS-1$
private long beginTime;
private ExitCode exitCode = ExitCode.UNKNOWN;
protected Reader reader;
private transient PrintWriter out = new PrintWriter(System.out, true);
protected transient Thread shutdownHook = new Thread() {
@Override
public void run() {
displayResult();
}
};
protected ISolver solver;
private boolean silent = false;
protected AbstractLauncher() {
Runtime.getRuntime().addShutdownHook(shutdownHook);
}
protected void displayResult() {
if (solver != null) {
double wallclocktime = (System.currentTimeMillis() - beginTime) / 1000.0;
solver.printStat(out, COMMENT_PREFIX);
out.println(ANSWER_PREFIX + exitCode);
if (exitCode == ExitCode.SATISFIABLE) {
int[] model = solver.model();
out.print(SOLUTION_PREFIX);
reader.decode(model, out);
out.println();
}
log("Total wall clock time (in seconds) : " + wallclocktime); //$NON-NLS-1$
}
}
public abstract void usage();
/**
* @throws IOException
*/
protected final void displayHeader() {
displayLicense();
URL url = AbstractLauncher.class.getResource("/sat4j.version"); //$NON-NLS-1$
if (url == null) {
log("no version file found!!!"); //$NON-NLS-1$
} else {
BufferedReader in = null;
try {
in = new BufferedReader(new InputStreamReader(url
.openStream()));
log("version " + in.readLine()); //$NON-NLS-1$
} catch (IOException e) {
log("c ERROR: "+e.getMessage());
} finally {
if (in!=null) {
try {
in.close();
} catch (IOException e) {
log("c ERROR: "+e.getMessage());
}
}
}
}
Properties prop = System.getProperties();
String[] infoskeys = {
"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$
for (String key : infoskeys) {
log(key + "\t" + prop.getProperty(key)); //$NON-NLS-1$
}
Runtime runtime = Runtime.getRuntime();
log("Free memory " + runtime.freeMemory()); //$NON-NLS-1$
log("Max memory " + runtime.maxMemory()); //$NON-NLS-1$
log("Total memory " + runtime.totalMemory()); //$NON-NLS-1$
log("Number of processors " + runtime.availableProcessors()); //$NON-NLS-1$
}
public void displayLicense() {
log("SAT4J: a SATisfiability library for Java (c) 2004-2008 Daniel Le Berre"); //$NON-NLS-1$
log("This is free software under the dual EPL/GNU LGPL licenses."); //$NON-NLS-1$
log("See www.sat4j.org for details."); //$NON-NLS-1$
}
/**
* Reads a problem file from the command line.
*
* @param problemname
* the fully qualified name of the problem.
* @return a reference to the problem to solve
* @throws FileNotFoundException
* if the file is not found
* @throws ParseFormatException
* if the problem is not expressed using the right format
* @throws IOException
* for other IO problems
* @throws ContradictionException
* if the problem is found trivially unsat
*/
protected IProblem readProblem(String problemname)
throws FileNotFoundException, ParseFormatException, IOException,
ContradictionException {
log("solving " + problemname); //$NON-NLS-1$
log("reading problem ... "); //$NON-NLS-1$
reader = createReader(solver, problemname);
IProblem problem = reader.parseInstance(problemname);
log("... done. Wall clock time " //$NON-NLS-1$
+ (System.currentTimeMillis() - beginTime) / 1000.0 + "s."); //$NON-NLS-1$
log("#vars " + problem.nVars()); //$NON-NLS-1$
log("#constraints " + problem.nConstraints()); //$NON-NLS-1$
problem.printInfos(out,COMMENT_PREFIX);
return problem;
}
protected abstract Reader createReader(ISolver theSolver, String problemname);
public void run(String[] args) {
try {
displayHeader();
solver = configureSolver(args);
if (solver == null)
return;
String instanceName = getInstanceName(args);
beginTime = System.currentTimeMillis();
IProblem problem = readProblem(instanceName);
try {
solve(problem);
} catch (TimeoutException e) {
log("timeout"); //$NON-NLS-1$
}
} catch (FileNotFoundException e) {
log("FATAL");
e.printStackTrace();
} catch (IOException e) {
log("FATAL");
e.printStackTrace();
} catch (ContradictionException e) {
exitCode = ExitCode.UNSATISFIABLE;
log("(trivial inconsistency)"); //$NON-NLS-1$
} catch (ParseFormatException e) {
log("FATAL");
e.printStackTrace();
}
}
protected abstract String getInstanceName(String[] args);
protected abstract ISolver configureSolver(String[] args);
/**
* Display messages as comments on STDOUT
*
* @param message
*/
public void log(String message) {
if (!silent)
out.println(COMMENT_PREFIX + message);
}
protected void solve(IProblem problem) throws TimeoutException {
exitCode = problem.isSatisfiable() ? ExitCode.SATISFIABLE
: ExitCode.UNSATISFIABLE;
}
/**
* Change the value of the exit code in the Launcher
*
* @param exitCode
* the new ExitCode
*/
public final void setExitCode(ExitCode exitCode) {
this.exitCode = exitCode;
}
/**
* Get the value of the ExitCode
*
* @return the current value of the Exitcode
*/
public final ExitCode getExitCode() {
return exitCode;
}
/**
* Obtaining the current time spent since the beginning of the solving
* process.
*
* @return the time signature at the beginning of the run() method.
*/
public final long getBeginTime() {
return beginTime;
}
/**
*
* @return the reader used to parse the instance
*/
public final Reader getReader() {
return reader;
}
/**
* To change the output stream on which statistics are displayed. By
* default, the solver displays everything on System.out.
*
* @param out
*/
public void setLogWriter(PrintWriter out) {
this.out = out;
}
public PrintWriter getLogWriter() {
return out;
}
protected void setSilent(boolean b) {
silent = b;
}
private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
stream.defaultReadObject();
out = new PrintWriter(System.out, true);
shutdownHook = new Thread() {
@Override
public void run() {
displayResult();
}
};
}
protected <T extends ISolver> void showAvailableSolvers(ASolverFactory<T> afactory) {
if (afactory != null) {
log("Available solvers: "); //$NON-NLS-1$
String[] names = afactory.solverNames();
for (int i = 0; i < names.length; i++) {
log(names[i]);
}
}
}
}