1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.sat4j.sat;
20
21 import java.io.FileNotFoundException;
22 import java.io.IOException;
23 import java.lang.reflect.InvocationTargetException;
24 import java.lang.reflect.Method;
25 import java.util.Arrays;
26 import java.util.Properties;
27 import java.util.StringTokenizer;
28
29 import org.apache.commons.beanutils.BeanUtils;
30 import org.apache.commons.cli.CommandLine;
31 import org.apache.commons.cli.HelpFormatter;
32 import org.apache.commons.cli.Option;
33 import org.apache.commons.cli.Options;
34 import org.apache.commons.cli.ParseException;
35 import org.apache.commons.cli.PosixParser;
36 import org.sat4j.AbstractLauncher;
37 import org.sat4j.core.ASolverFactory;
38 import org.sat4j.core.VecInt;
39 import org.sat4j.minisat.core.DataStructureFactory;
40 import org.sat4j.minisat.core.IOrder;
41 import org.sat4j.minisat.core.IPhaseSelectionStrategy;
42 import org.sat4j.minisat.core.LearningStrategy;
43 import org.sat4j.minisat.core.RestartStrategy;
44 import org.sat4j.minisat.core.SearchParams;
45 import org.sat4j.minisat.core.Solver;
46 import org.sat4j.pb.IPBSolver;
47 import org.sat4j.pb.reader.PBInstanceReader;
48 import org.sat4j.reader.InstanceReader;
49 import org.sat4j.reader.ParseFormatException;
50 import org.sat4j.reader.Reader;
51 import org.sat4j.specs.ContradictionException;
52 import org.sat4j.specs.IProblem;
53 import org.sat4j.specs.ISolver;
54 import org.sat4j.specs.IVecInt;
55 import org.sat4j.specs.SearchListener;
56 import org.sat4j.tools.DotSearchTracing;
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72 public class Lanceur extends AbstractLauncher {
73
74
75
76
77 private static final long serialVersionUID = 1L;
78
79
80
81
82
83
84
85
86 public static void main(final String[] args) {
87 AbstractLauncher lanceur = new Lanceur();
88 lanceur.run(args);
89 System.exit(lanceur.getExitCode().value());
90 }
91
92 protected ASolverFactory<ISolver> factory;
93
94 private String filename;
95
96 private int k = -1;
97
98 @SuppressWarnings("nls")
99 private Options createCLIOptions() {
100 Options options = new Options();
101
102 options.addOption("l", "library", true,
103 "specifies the name of the library used (minisat by default)");
104 options.addOption("s", "solver", true,
105 "specifies the name of a prebuilt solver from the library");
106 options.addOption("S", "Solver", true,
107 "setup a solver using a solver config string");
108 options.addOption("t", "timeout", true,
109 "specifies the timeout (in seconds)");
110 options.addOption("T", "timeoutms", true,
111 "specifies the timeout (in milliseconds)");
112 options.addOption("C", "conflictbased", false,
113 "conflict based timeout (for deterministic behavior)");
114 options.addOption("d", "dot", true,
115 "create a sat4j.dot file in current directory representing the search");
116 options.addOption("f", "filename", true,
117 "specifies the file to use (in conjunction with -d for instance)");
118 options.addOption("m", "mute", false, "Set launcher in silent mode");
119 options.addOption("k", "kleast", true,
120 "limit the search to models having at least k variables set to false");
121 options.addOption("r", "trace", true,
122 "Search Listener to use for tracing the behavior of the solver");
123 Option op = options.getOption("l");
124 op.setArgName("libname");
125 op = options.getOption("s");
126 op.setArgName("solvername");
127 op = options.getOption("S");
128 op.setArgName("solverStringDefinition");
129 op = options.getOption("t");
130 op.setArgName("number");
131 op = options.getOption("T");
132 op.setArgName("number");
133 op = options.getOption("C");
134 op.setArgName("number");
135 op = options.getOption("k");
136 op.setArgName("number");
137 op = options.getOption("d");
138 op.setArgName("filename");
139 op = options.getOption("f");
140 op.setArgName("filename");
141 op = options.getOption("r");
142 op.setArgName("searchlistener");
143 return options;
144 }
145
146
147
148
149
150
151
152
153 @SuppressWarnings({ "nls", "unchecked" })
154 @Override
155 protected ISolver configureSolver(String[] args) {
156 Options options = createCLIOptions();
157 if (args.length == 0) {
158 HelpFormatter helpf = new HelpFormatter();
159 helpf.printHelp("java -jar sat4j.jar", options, true);
160 return null;
161 }
162 try {
163 CommandLine cmd = new PosixParser().parse(options, args);
164
165 String framework = cmd.getOptionValue("l");
166 if (framework == null) {
167 framework = "minisat";
168 }
169
170 try {
171 Class<?> clazz = Class
172 .forName("org.sat4j." + framework + ".SolverFactory");
173 Class<?>[] params = {};
174 Method m = clazz.getMethod("instance", params);
175 factory = (ASolverFactory) m.invoke(null, (Object[]) null);
176 } catch (Exception e) {
177 log("Wrong framework: " + framework
178 + ". Using minisat instead.");
179 factory = org.sat4j.minisat.SolverFactory.instance();
180 }
181
182 ISolver asolver;
183 if (cmd.hasOption("s")) {
184 log("Available solvers: "
185 + Arrays.asList(factory.solverNames()));
186 String solvername = cmd.getOptionValue("s");
187 if (solvername == null) {
188 asolver = factory.defaultSolver();
189 } else {
190 asolver = factory.createSolverByName(solvername);
191 }
192 } else {
193 asolver = factory.defaultSolver();
194 }
195
196 if (cmd.hasOption("S")) {
197 String configuredSolver = cmd.getOptionValue("S");
198 if (configuredSolver == null) {
199 stringUsage();
200 return null;
201 }
202 asolver = configureFromString(configuredSolver, asolver);
203 }
204
205 String timeout = cmd.getOptionValue("t");
206 if (timeout == null) {
207 timeout = cmd.getOptionValue("T");
208 if (timeout != null) {
209 asolver.setTimeoutMs(Long.parseLong(timeout));
210 }
211 } else {
212 if (cmd.hasOption("C")) {
213 asolver.setTimeoutOnConflicts(Integer.parseInt(timeout));
214 } else {
215 asolver.setTimeout(Integer.parseInt(timeout));
216 }
217 }
218 filename = cmd.getOptionValue("f");
219
220 if (cmd.hasOption("d")) {
221 String dotfilename = null;
222 if (filename != null) {
223 dotfilename = cmd.getOptionValue("d");
224 }
225 if (dotfilename == null) {
226 dotfilename = "sat4j.dot";
227 }
228 asolver.setSearchListener(new DotSearchTracing(dotfilename,
229 null));
230 }
231
232 if (cmd.hasOption("m")) {
233 setSilent(true);
234 }
235
236 if (cmd.hasOption("k")) {
237 Integer myk = Integer.valueOf(cmd.getOptionValue("k"));
238 if (myk != null) {
239 k = myk.intValue();
240 }
241 }
242 if (cmd.hasOption("r")) {
243 String listener = cmd.getOptionValue("r");
244 try {
245
246 SearchListener slistener = (SearchListener) Class
247 .forName(listener).getConstructor(String.class)
248 .newInstance("sat4j.trace");
249 asolver.setSearchListener(slistener);
250 } catch (InstantiationException e) {
251 log("wrong parameter for search listener: "
252 + e.getLocalizedMessage());
253 } catch (IllegalAccessException e) {
254 log("wrong parameter for search listener: "
255 + e.getLocalizedMessage());
256 } catch (ClassNotFoundException e) {
257 log("wrong parameter for search listener: " + listener);
258 } catch (IllegalArgumentException e) {
259 log("wrong parameter for search listener: "
260 + e.getLocalizedMessage());
261 } catch (SecurityException e) {
262 log("wrong parameter for search listener: "
263 + e.getLocalizedMessage());
264 } catch (InvocationTargetException e) {
265 log("wrong parameter for search listener: "
266 + e.getLocalizedMessage());
267 } catch (NoSuchMethodException e) {
268 log("wrong parameter for search listener: "
269 + e.getLocalizedMessage());
270 }
271 }
272 int others = 0;
273 String[] rargs = cmd.getArgs();
274 if (filename == null && rargs.length > 0) {
275 filename = rargs[others++];
276 }
277
278
279 while (others < rargs.length) {
280 String[] param = rargs[others].split("=");
281 assert param.length == 2;
282 log("setting " + param[0] + " to " + param[1]);
283 try {
284 BeanUtils.setProperty(asolver, param[0], param[1]);
285 } catch (Exception e) {
286 log("Cannot set parameter : "
287 + args[others]);
288 }
289 others++;
290 }
291
292 getLogWriter().println(asolver.toString(COMMENT_PREFIX));
293 return asolver;
294 } catch (ParseException e1) {
295 HelpFormatter helpf = new HelpFormatter();
296 helpf.printHelp("java -jar sat4j.jar", options, true);
297 usage();
298 }
299 return null;
300 }
301
302 @Override
303 protected Reader createReader(ISolver theSolver, String problemname) {
304 if (theSolver instanceof IPBSolver) {
305 return new PBInstanceReader((IPBSolver) theSolver);
306 }
307 return new InstanceReader(theSolver);
308 }
309
310 @Override
311 public void displayLicense() {
312 super.displayLicense();
313 log("This software uses some libraries from the Jakarta Commons project. See jakarta.apache.org for details.");
314 }
315
316 @Override
317 public void usage() {
318 showAvailableSolvers(factory);
319 }
320
321 @Override
322 protected String getInstanceName(String[] args) {
323 return filename;
324 }
325
326 @SuppressWarnings("unchecked")
327 private final ISolver configureFromString(String solverconfig,
328 ISolver theSolver) {
329
330
331 StringTokenizer stk = new StringTokenizer(solverconfig, ",");
332 Properties pf = new Properties();
333 String token;
334 String[] couple;
335 while (stk.hasMoreElements()) {
336 token = stk.nextToken();
337 couple = token.split("=");
338 pf.setProperty(couple[0], couple[1]);
339 }
340 Solver aSolver = (Solver) theSolver;
341 DataStructureFactory dsf = setupObject("DSF", pf);
342 if (dsf != null) {
343 aSolver.setDataStructureFactory(dsf);
344 }
345 LearningStrategy learning = setupObject("LEARNING", pf);
346 if (learning != null) {
347 aSolver.setLearner(learning);
348 learning.setSolver(aSolver);
349 }
350 IOrder order = setupObject("ORDER", pf);
351 if (order != null) {
352 aSolver.setOrder(order);
353 }
354 IPhaseSelectionStrategy pss = setupObject("PHASE", pf);
355 if (pss != null) {
356 aSolver.getOrder().setPhaseSelectionStrategy(pss);
357 }
358 RestartStrategy restarter = setupObject("RESTARTS", pf);
359 if (restarter != null) {
360 aSolver.setRestartStrategy(restarter);
361 }
362 String simp = pf.getProperty("SIMP");
363 if (simp != null) {
364 aSolver.setSimplifier(simp);
365 }
366 SearchParams params = setupObject("PARAMS", pf);
367 if (params != null) {
368 aSolver.setSearchParams(params);
369 }
370 String memory = pf.getProperty("MEMORY");
371 if ("GLUCOSE".equalsIgnoreCase(memory)) {
372 log("configuring MEMORY");
373 aSolver.setLearnedConstraintsDeletionStrategy(aSolver.glucose);
374 }
375 return theSolver;
376 }
377
378 private void stringUsage() {
379 log("Available building blocks: DSF, LEARNING, ORDER, PHASE, RESTARTS, SIMP, PARAMS");
380 log("Example: -S RESTARTS=org.sat4j.minisat.restarts.LubyRestarts/factor:512,LEARNING=org.sat4j.minisat.learning.MiniSATLearning");
381 }
382
383 @SuppressWarnings("unchecked")
384 private final <T> T setupObject(String component, Properties pf) {
385 try {
386 String configline = pf.getProperty(component);
387 if (configline == null) {
388 return null;
389 }
390 log("configuring " + component);
391 String[] config = configline.split("/");
392 T comp = (T) Class.forName(config[0]).newInstance();
393 for (int i = 1; i < config.length; i++) {
394 String[] param = config[i].split(":");
395 assert param.length == 2;
396 try {
397
398 BeanUtils.getProperty(comp, param[0]);
399 BeanUtils.setProperty(comp, param[0], param[1]);
400 } catch (Exception e) {
401 log("Problem with component " + config[0] + " " + e);
402 }
403 }
404 return comp;
405 } catch (InstantiationException e) {
406 log("Problem with component " + component + " " + e);
407 } catch (IllegalAccessException e) {
408 log("Problem with component " + component + " " + e);
409 } catch (ClassNotFoundException e) {
410 log("Problem with component " + component + " " + e);
411 }
412 return null;
413 }
414
415 @Override
416 protected IProblem readProblem(String problemname)
417 throws FileNotFoundException, ParseFormatException, IOException,
418 ContradictionException {
419 ISolver theSolver = (ISolver) super.readProblem(problemname);
420 if (k > 0) {
421 IVecInt literals = new VecInt();
422 for (int i = 1; i <= theSolver.nVars(); i++) {
423 literals.push(-i);
424 }
425 theSolver.addAtLeast(literals, k);
426 log("Limiting solutions to those having at least " + k
427 + " variables assigned to false");
428 }
429 return theSolver;
430 }
431 }