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
115 .addOption("d", "dot", true,
116 "create a sat4j.dot file in current directory representing the search");
117 options
118 .addOption("f", "filename", true,
119 "specifies the file to use (in conjunction with -d for instance)");
120 options.addOption("m", "mute", false, "Set launcher in silent mode");
121 options
122 .addOption("k", "kleast", true,
123 "limit the search to models having at least k variables set to false");
124 options
125 .addOption("r", "trace", true,
126 "Search Listener to use for tracing the behavior of the solver");
127 Option op = options.getOption("l");
128 op.setArgName("libname");
129 op = options.getOption("s");
130 op.setArgName("solvername");
131 op = options.getOption("S");
132 op.setArgName("solverStringDefinition");
133 op = options.getOption("t");
134 op.setArgName("number");
135 op = options.getOption("T");
136 op.setArgName("number");
137 op = options.getOption("C");
138 op.setArgName("number");
139 op = options.getOption("k");
140 op.setArgName("number");
141 op = options.getOption("d");
142 op.setArgName("filename");
143 op = options.getOption("f");
144 op.setArgName("filename");
145 op = options.getOption("r");
146 op.setArgName("searchlistener");
147 return options;
148 }
149
150
151
152
153
154
155
156
157 @SuppressWarnings( { "nls", "unchecked" })
158 @Override
159 protected ISolver configureSolver(String[] args) {
160 Options options = createCLIOptions();
161 if (args.length == 0) {
162 HelpFormatter helpf = new HelpFormatter();
163 helpf.printHelp("java -jar sat4j.jar", options, true);
164 return null;
165 }
166 try {
167 CommandLine cmd = new PosixParser().parse(options, args);
168
169 String framework = cmd.getOptionValue("l");
170 if (framework == null) {
171 framework = "minisat";
172 }
173
174 try {
175 Class<?> clazz = Class
176 .forName("org.sat4j." + framework + ".SolverFactory");
177 Class<?>[] params = {};
178 Method m = clazz.getMethod("instance", params);
179 factory = (ASolverFactory) m.invoke(null, (Object[]) null);
180 } catch (Exception e) {
181 log("Wrong framework: " + framework
182 + ". Using minisat instead.");
183 factory = org.sat4j.minisat.SolverFactory.instance();
184 }
185
186 ISolver asolver;
187 if (cmd.hasOption("s")) {
188 log("Available solvers: "
189 + Arrays.asList(factory.solverNames()));
190 String solvername = cmd.getOptionValue("s");
191 if (solvername == null) {
192 asolver = factory.defaultSolver();
193 } else {
194 asolver = factory.createSolverByName(solvername);
195 }
196 } else {
197 asolver = factory.defaultSolver();
198 }
199
200 if (cmd.hasOption("S")) {
201 String configuredSolver = cmd.getOptionValue("S");
202 if (configuredSolver == null) {
203 stringUsage();
204 return null;
205 }
206 asolver = configureFromString(configuredSolver, asolver);
207 }
208
209 String timeout = cmd.getOptionValue("t");
210 if (timeout == null) {
211 timeout = cmd.getOptionValue("T");
212 if (timeout != null) {
213 asolver.setTimeoutMs(Long.parseLong(timeout));
214 }
215 } else {
216 if (cmd.hasOption("C")) {
217 asolver.setTimeoutOnConflicts(Integer.parseInt(timeout));
218 } else {
219 asolver.setTimeout(Integer.parseInt(timeout));
220 }
221 }
222 filename = cmd.getOptionValue("f");
223
224 if (cmd.hasOption("d")) {
225 String dotfilename = null;
226 if (filename != null) {
227 dotfilename = cmd.getOptionValue("d");
228 }
229 if (dotfilename == null) {
230 dotfilename = "sat4j.dot";
231 }
232 asolver.setSearchListener(new DotSearchTracing(dotfilename,
233 null));
234 }
235
236 if (cmd.hasOption("m")) {
237 setSilent(true);
238 }
239
240 if (cmd.hasOption("k")) {
241 Integer myk = Integer.valueOf(cmd.getOptionValue("k"));
242 if (myk != null) {
243 k = myk.intValue();
244 }
245 }
246 if (cmd.hasOption("r")) {
247 String listener = cmd.getOptionValue("r");
248 try {
249
250 SearchListener slistener = (SearchListener) Class.forName(
251 listener).getConstructor(String.class).newInstance(
252 "sat4j.trace");
253 asolver.setSearchListener(slistener);
254 } catch (InstantiationException e) {
255 log("wrong parameter for search listener: "
256 + e.getLocalizedMessage());
257 } catch (IllegalAccessException e) {
258 log("wrong parameter for search listener: "
259 + e.getLocalizedMessage());
260 } catch (ClassNotFoundException e) {
261 log("wrong parameter for search listener: " + listener);
262 } catch (IllegalArgumentException e) {
263 log("wrong parameter for search listener: "
264 + e.getLocalizedMessage());
265 } catch (SecurityException e) {
266 log("wrong parameter for search listener: "
267 + e.getLocalizedMessage());
268 } catch (InvocationTargetException e) {
269 log("wrong parameter for search listener: "
270 + e.getLocalizedMessage());
271 } catch (NoSuchMethodException e) {
272 log("wrong parameter for search listener: "
273 + e.getLocalizedMessage());
274 }
275 }
276 int others = 0;
277 String[] rargs = cmd.getArgs();
278 if (filename == null && rargs.length > 0) {
279 filename = rargs[others++];
280 }
281
282
283 while (others < rargs.length) {
284 String[] param = rargs[others].split("=");
285 assert param.length == 2;
286 log("setting " + param[0] + " to " + param[1]);
287 try {
288 BeanUtils.setProperty(asolver, param[0], param[1]);
289 } catch (Exception e) {
290 log("Cannot set parameter : "
291 + args[others]);
292 }
293 others++;
294 }
295
296 log(asolver.toString(COMMENT_PREFIX));
297 return asolver;
298 } catch (ParseException e1) {
299 HelpFormatter helpf = new HelpFormatter();
300 helpf.printHelp("java -jar sat4j.jar", options, true);
301 usage();
302 }
303 return null;
304 }
305
306 @Override
307 protected Reader createReader(ISolver theSolver, String problemname) {
308 if (theSolver instanceof IPBSolver) {
309 return new PBInstanceReader((IPBSolver) theSolver);
310 }
311 return new InstanceReader(theSolver);
312 }
313
314 @Override
315 public void displayLicense() {
316 super.displayLicense();
317 log("This software uses some libraries from the Jakarta Commons project. See jakarta.apache.org for details.");
318 }
319
320 @Override
321 public void usage() {
322 showAvailableSolvers(factory);
323 }
324
325 @Override
326 protected String getInstanceName(String[] args) {
327 return filename;
328 }
329
330 @SuppressWarnings("unchecked")
331 private final ISolver configureFromString(String solverconfig,
332 ISolver theSolver) {
333
334
335 StringTokenizer stk = new StringTokenizer(solverconfig, ",");
336 Properties pf = new Properties();
337 String token;
338 String[] couple;
339 while (stk.hasMoreElements()) {
340 token = stk.nextToken();
341 couple = token.split("=");
342 pf.setProperty(couple[0], couple[1]);
343 }
344 Solver aSolver = (Solver) theSolver;
345 DataStructureFactory dsf = setupObject("DSF", pf);
346 if (dsf != null) {
347 aSolver.setDataStructureFactory(dsf);
348 }
349 LearningStrategy learning = setupObject("LEARNING", pf);
350 if (learning != null) {
351 aSolver.setLearner(learning);
352 learning.setSolver(aSolver);
353 }
354 IOrder order = setupObject("ORDER", pf);
355 if (order != null) {
356 aSolver.setOrder(order);
357 }
358 IPhaseSelectionStrategy pss = setupObject("PHASE", pf);
359 if (pss != null) {
360 aSolver.getOrder().setPhaseSelectionStrategy(pss);
361 }
362 RestartStrategy restarter = setupObject("RESTARTS", pf);
363 if (restarter != null) {
364 aSolver.setRestartStrategy(restarter);
365 }
366 String simp = pf.getProperty("SIMP");
367 if (simp != null) {
368 aSolver.setSimplifier(simp);
369 }
370 SearchParams params = setupObject("PARAMS", pf);
371 if (params != null) {
372 aSolver.setSearchParams(params);
373 }
374 String memory = pf.getProperty("MEMORY");
375 if ("GLUCOSE".equalsIgnoreCase(memory)) {
376 log("configuring MEMORY");
377 aSolver.setLearnedConstraintsDeletionStrategy(aSolver.glucose);
378 }
379 return theSolver;
380 }
381
382 private void stringUsage() {
383 log("Available building blocks: DSF, LEARNING, ORDER, PHASE, RESTARTS, SIMP, PARAMS");
384 log("Example: -S RESTARTS=org.sat4j.minisat.restarts.LubyRestarts/factor:512,LEARNING=org.sat4j.minisat.learning.MiniSATLearning");
385 }
386
387 @SuppressWarnings("unchecked")
388 private final <T> T setupObject(String component, Properties pf) {
389 try {
390 String configline = pf.getProperty(component);
391 if (configline == null) {
392 return null;
393 }
394 log("configuring " + component);
395 String[] config = configline.split("/");
396 T comp = (T) Class.forName(config[0]).newInstance();
397 for (int i = 1; i < config.length; i++) {
398 String[] param = config[i].split(":");
399 assert param.length == 2;
400 try {
401
402 BeanUtils.getProperty(comp, param[0]);
403 BeanUtils.setProperty(comp, param[0], param[1]);
404 } catch (Exception e) {
405 log("Problem with component " + config[0] + " " + e);
406 }
407 }
408 return comp;
409 } catch (InstantiationException e) {
410 log("Problem with component " + component + " " + e);
411 } catch (IllegalAccessException e) {
412 log("Problem with component " + component + " " + e);
413 } catch (ClassNotFoundException e) {
414 log("Problem with component " + component + " " + e);
415 }
416 return null;
417 }
418
419 @Override
420 protected IProblem readProblem(String problemname)
421 throws FileNotFoundException, ParseFormatException, IOException,
422 ContradictionException {
423 ISolver theSolver = (ISolver) super.readProblem(problemname);
424 if (k > 0) {
425 IVecInt literals = new VecInt();
426 for (int i = 1; i <= theSolver.nVars(); i++) {
427 literals.push(-i);
428 }
429 theSolver.addAtLeast(literals, k);
430 log("Limiting solutions to those having at least " + k
431 + " variables assigned to false");
432 }
433 return theSolver;
434 }
435 }