1 /*
2 Copyright (c) 2010-2015 Mate Soos
3
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 THE SOFTWARE.
21 */
22
23 #if defined(__GNUC__) && defined(__linux__)
24
25 #ifndef _GNU_SOURCE
26 #define _GNU_SOURCE
27 #endif
28
29 #include <fenv.h>
30 #endif
31
32 #define DEBUG_DIMACSPARSER_CMS
33
34 #include <ctime>
35 #include <cstring>
36 #include <errno.h>
37 #include <string.h>
38 #include <sstream>
39 #include <iostream>
40 #include <iomanip>
41 #include <map>
42 #include <set>
43 #include <fstream>
44 #include <sys/stat.h>
45 #include <string.h>
46 #include <list>
47 #include <array>
48 #include <thread>
49
50 #include "main.h"
51 #include "main_common.h"
52 #include "time_mem.h"
53 #include "dimacsparser.h"
54 #include "cryptominisat5/cryptominisat.h"
55 #include "signalcode.h"
56
57 #include <boost/lexical_cast.hpp>
58 using namespace CMSat;
59 using boost::lexical_cast;
60
61 using std::cout;
62 using std::cerr;
63 using std::endl;
64 using boost::lexical_cast;
65 using std::map;
66
67 struct WrongParam
68 {
WrongParamWrongParam69 WrongParam(string _param, string _msg) :
70 param(_param)
71 , msg(_msg)
72 {}
73
getMsgWrongParam74 const string& getMsg() const
75 {
76 return msg;
77 }
78
getParamWrongParam79 const string& getParam() const
80 {
81 return param;
82 }
83
84 string param;
85 string msg;
86 };
87
88
Main(int _argc,char ** _argv)89 Main::Main(int _argc, char** _argv) :
90 argc(_argc)
91 , argv(_argv)
92 , fileNamePresent (false)
93 {
94 }
95
readInAFile(SATSolver * solver2,const string & filename)96 void Main::readInAFile(SATSolver* solver2, const string& filename)
97 {
98 solver2->add_sql_tag("filename", filename);
99 if (conf.verbosity) {
100 cout << "c Reading file '" << filename << "'" << endl;
101 }
102 #ifndef USE_ZLIB
103 FILE * in = fopen(filename.c_str(), "rb");
104 DimacsParser<StreamBuffer<FILE*, FN>, SATSolver> parser(solver2, &debugLib, conf.verbosity);
105 #else
106 gzFile in = gzopen(filename.c_str(), "rb");
107 DimacsParser<StreamBuffer<gzFile, GZ>, SATSolver> parser(solver2, &debugLib, conf.verbosity);
108 #endif
109
110 if (in == NULL) {
111 std::cerr
112 << "ERROR! Could not open file '"
113 << filename
114 << "' for reading: " << strerror(errno) << endl;
115
116 std::exit(1);
117 }
118
119 bool strict_header = conf.preprocess;
120 if (!parser.parse_DIMACS(in, strict_header)) {
121 exit(-1);
122 }
123
124 if (!sampling_vars_str.empty() && !parser.sampling_vars.empty()) {
125 cerr << "ERROR! Sampling vars set in console but also in CNF." << endl;
126 exit(-1);
127 }
128
129 if (!sampling_vars_str.empty()) {
130 assert(sampling_vars.empty());
131
132 std::stringstream ss(sampling_vars_str);
133 uint32_t i;
134 while (ss >> i)
135 {
136 const uint32_t var = i-1;
137 sampling_vars.push_back(var);
138
139 if (ss.peek() == ',' || ss.peek() == ' ')
140 ss.ignore();
141 }
142 } else {
143 sampling_vars.swap(parser.sampling_vars);
144 }
145
146 if (sampling_vars.empty()) {
147 if (only_sampling_solution) {
148 cout << "ERROR: only sampling vars are requested in the solution, but no sampling vars have been set!" << endl;
149 exit(-1);
150 }
151 } else {
152 solver2->set_sampling_vars(&sampling_vars);
153 if (sampling_vars.size() > 100) {
154 cout
155 << "c Sampling var set contains over 100 variables, not displaying"
156 << endl;
157 } else {
158 cout << "c Sampling vars set (total num: "
159 << sampling_vars.size() << " ) : ";
160 for(size_t i = 0; i < sampling_vars.size(); i++) {
161 const uint32_t v = sampling_vars[i];
162 cout << v+1;
163 if (i+1 != sampling_vars.size())
164 cout << ",";
165 }
166 cout << endl;
167 }
168 }
169
170 call_after_parse();
171
172 #ifndef USE_ZLIB
173 fclose(in);
174 #else
175 gzclose(in);
176 #endif
177 }
178
readInStandardInput(SATSolver * solver2)179 void Main::readInStandardInput(SATSolver* solver2)
180 {
181 if (conf.verbosity) {
182 cout
183 << "c Reading from standard input... Use '-h' or '--help' for help."
184 << endl;
185 }
186
187 #ifndef USE_ZLIB
188 FILE * in = stdin;
189 #else
190 gzFile in = gzdopen(0, "rb"); //opens stdin, which is 0
191 #endif
192
193 if (in == NULL) {
194 std::cerr << "ERROR! Could not open standard input for reading" << endl;
195 std::exit(1);
196 }
197
198 #ifndef USE_ZLIB
199 DimacsParser<StreamBuffer<FILE*, FN>, SATSolver> parser(solver2, &debugLib, conf.verbosity);
200 #else
201 DimacsParser<StreamBuffer<gzFile, GZ>, SATSolver> parser(solver2, &debugLib, conf.verbosity);
202 #endif
203
204 if (!parser.parse_DIMACS(in, false)) {
205 exit(-1);
206 }
207
208 #ifdef USE_ZLIB
209 gzclose(in);
210 #endif
211 }
212
parseInAllFiles(SATSolver * solver2)213 void Main::parseInAllFiles(SATSolver* solver2)
214 {
215 const double myTimeTotal = cpuTimeTotal();
216 const double myTime = cpuTime();
217
218 //First read normal extra files
219 if (!debugLib.empty() && filesToRead.size() > 1) {
220 cout
221 << "ERROR: debugLib must be OFF"
222 << " to parse in more than one file"
223 << endl;
224
225 std::exit(-1);
226 }
227
228 for (const string& fname: filesToRead) {
229 readInAFile(solver2, fname.c_str());
230 }
231
232 solver->add_sql_tag("stdin", fileNamePresent ? "False" : "True");
233 if (!fileNamePresent) {
234 readInStandardInput(solver2);
235 }
236
237 if (conf.verbosity) {
238 if (num_threads > 1) {
239 cout
240 << "c Sum parsing time among all threads (wall time will differ): "
241 << std::fixed << std::setprecision(2)
242 << (cpuTimeTotal() - myTimeTotal)
243 << " s" << endl;
244 } else {
245 cout
246 << "c Parsing time: "
247 << std::fixed << std::setprecision(2)
248 << (cpuTime() - myTime)
249 << " s" << endl;
250 }
251 }
252 }
253
printResultFunc(std::ostream * os,const bool toFile,const lbool ret)254 void Main::printResultFunc(
255 std::ostream* os
256 , const bool toFile
257 , const lbool ret
258 ) {
259 if (ret == l_True) {
260 if(toFile) {
261 *os << "SAT" << endl;
262 }
263 else if (!printResult) *os << "s SATISFIABLE" << endl;
264 else *os << "s SATISFIABLE" << endl;
265 } else if (ret == l_False) {
266 if(toFile) {
267 *os << "UNSAT" << endl;
268 }
269 else if (!printResult) *os << "s UNSATISFIABLE" << endl;
270 else *os << "s UNSATISFIABLE" << endl;
271 } else {
272 *os << "s INDETERMINATE" << endl;
273 }
274 if (ret == l_True && !printResult && !toFile)
275 {
276 cout << "c Not printing satisfying assignement. "
277 "Use the '--printsol 1' option for that" << endl;
278 }
279
280 if (ret == l_True && (printResult || toFile)) {
281 if (toFile) {
282 auto fun = [&](uint32_t var) {
283 if (solver->get_model()[var] != l_Undef) {
284 *os << ((solver->get_model()[var] == l_True)? "" : "-") << var+1 << " ";
285 }
286 };
287
288 if (sampling_vars.empty() || !only_sampling_solution) {
289 for (uint32_t var = 0; var < solver->nVars(); var++) {
290 fun(var);
291 }
292
293 } else {
294 for (uint32_t var: sampling_vars) {
295 fun(var);
296 }
297 }
298 *os << "0" << endl;
299 } else {
300 uint32_t num_undef;
301 if (sampling_vars.empty() || !only_sampling_solution) {
302 num_undef = print_model(solver, os);
303 } else {
304 num_undef = print_model(solver, os, &sampling_vars);
305 }
306 if (num_undef && !toFile && conf.verbosity) {
307 cout << "c NOTE: " << num_undef << " variables are NOT set." << endl;
308 }
309 }
310 }
311 }
312
313 /* clang-format off */
add_supported_options()314 void Main::add_supported_options()
315 {
316 // Declare the supported options.
317 generalOptions.add_options()
318 ("help,h", "Print simple help")
319 ("hhelp", "Print extensive help")
320 ("version,v", "Print version info")
321 ("verb", po::value(&conf.verbosity)->default_value(conf.verbosity)
322 , "[0-10] Verbosity of solver. 0 = only solution")
323 ("random,r", po::value(&conf.origSeed)->default_value(conf.origSeed)
324 , "[0..] Random seed")
325 ("threads,t", po::value(&num_threads)->default_value(1)
326 ,"Number of threads")
327 ("maxtime", po::value(&maxtime),
328 "Stop solving after this much time (s)")
329 ("maxconfl", po::value(&maxconfl),
330 "Stop solving after this many conflicts")
331 ("mult,m", po::value(&conf.orig_global_timeout_multiplier)->default_value(conf.orig_global_timeout_multiplier)
332 , "Time multiplier for all simplification cutoffs")
333 ("memoutmult", po::value(&conf.var_and_mem_out_mult)->default_value(conf.var_and_mem_out_mult)
334 , "Multiplier for memory-out checks on inprocessing functions. It limits things such as clause-link-in. Useful when you have limited memory but still want to do some inprocessing")
335 ("preproc,p", po::value(&conf.preprocess)->default_value(conf.preprocess)
336 , "0 = normal run, 1 = preprocess and dump, 2 = read back dump and solution to produce final solution")
337 #ifdef STATS_NEEDED
338 ("clid", po::bool_switch(&clause_ID_needed)
339 , "Add clause IDs to DRAT output")
340 #endif
341 ;
342
343 #ifdef FINAL_PREDICTOR
344 po::options_description predictOptions("Predict options");
345 predictOptions.add_options()
346 ("predshort", po::value(&conf.pred_conf_short)->default_value(conf.pred_conf_short)
347 , "Predictor SHORT config to use")
348 ("predlong", po::value(&conf.pred_conf_long)->default_value(conf.pred_conf_long)
349 , "Predictor LONG config to use")
350 ("predforever", po::value(&conf.pred_conf_forever)->default_value(conf.pred_conf_forever)
351 , "Predictor FOREVER config to use")
352 ("predshortmult", po::value(&conf.pred_short_size_mult)->default_value(conf.pred_short_size_mult)
353 , "Pred short multiplier")
354 ("predlongmult", po::value(&conf.pred_long_size_mult)->default_value(conf.pred_long_size_mult)
355 , "Pred long multiplier")
356 ("predforevermult", po::value(&conf.pred_forever_size_mult)->default_value(conf.pred_forever_size_mult)
357 , "Pred forever multiplier")
358 ("predlongchunkmult", po::value(&conf.pred_long_chunk_mult)->default_value(conf.pred_long_chunk_mult)
359 , "Pred long chunk multiplier")
360 ("predforeverchunkmult", po::value(&conf.pred_forever_chunk_mult)->default_value(conf.pred_forever_chunk_mult)
361 , "Pred forever chunk multiplier")
362 ;
363 #endif
364
365 po::options_description polar_options("Polarity options");
366 polar_options.add_options()
367 ("polar", po::value<string>()->default_value("auto")
368 , "{true,false,rnd,auto} Selects polarity mode. 'true' -> selects only positive polarity when branching. 'false' -> selects only negative polarity when branching. 'auto' -> selects last polarity used (also called 'caching')")
369 ("polarstablen", po::value(&conf.polar_stable_every_n)->default_value(conf.polar_stable_every_n)
370 , "When to use stable polarities. 0 = always, otherwise every n. Negative is special, see code")
371 ("lucky", po::value(&conf.do_lucky_polar_every_n)->default_value(conf.do_lucky_polar_every_n)
372 , "Try computing lucky polarities")
373 ("polarbestinvmult", po::value(&conf.polar_best_inv_multip_n)->default_value(conf.polar_best_inv_multip_n)
374 , "How often should we use inverted best polarities instead of stable")
375 ("polarbestmult", po::value(&conf.polar_best_multip_n)->default_value(conf.polar_best_multip_n)
376 , "How often should we use best polarities instead of stable")
377 ;
378
379
380 std::ostringstream s_local_glue_multiplier;
381 s_local_glue_multiplier << std::setprecision(4) << conf.local_glue_multiplier;
382
383 po::options_description restartOptions("Restart options");
384 restartOptions.add_options()
385 ("restart", po::value<string>()
386 , "{geom, glue, luby} Restart strategy to follow.")
387 ("gluehist", po::value(&conf.shortTermHistorySize)->default_value(conf.shortTermHistorySize)
388 , "The size of the moving window for short-term glue history of redundant clauses. If higher, the minimal number of conflicts between restarts is longer")
389 ("lwrbndblkrest", po::value(&conf.lower_bound_for_blocking_restart)->default_value(conf.lower_bound_for_blocking_restart)
390 , "Lower bound on blocking restart -- don't block before this many conflicts")
391 ("locgmult" , po::value(&conf.local_glue_multiplier)->default_value(conf.local_glue_multiplier, s_local_glue_multiplier.str())
392 , "The multiplier used to determine if we should restart during glue-based restart")
393 ("ratiogluegeom", po::value(&conf.ratio_glue_geom)->default_value(conf.ratio_glue_geom)
394 , "Ratio of glue vs geometric restarts -- more is more glue")
395 ;
396
397 std::ostringstream s_incclean;
398
399 std::ostringstream s_adjust_low;
400 s_adjust_low << std::setprecision(2) << conf.adjust_glue_if_too_many_low;
401
402 po::options_description reduceDBOptions("Redundant clause options");
403 reduceDBOptions.add_options()
404 ("gluecut0", po::value(&conf.glue_put_lev0_if_below_or_eq)->default_value(conf.glue_put_lev0_if_below_or_eq)
405 , "Glue value for lev 0 ('keep') cut")
406 ("gluecut1", po::value(&conf.glue_put_lev1_if_below_or_eq)->default_value(conf.glue_put_lev1_if_below_or_eq)
407 , "Glue value for lev 1 cut ('give another shot'")
408 ("adjustglue", po::value(&conf.adjust_glue_if_too_many_low)->default_value(conf.adjust_glue_if_too_many_low, s_adjust_low.str())
409 , "If more than this % of clauses is LOW glue (level 0) then lower the glue cutoff by 1 -- once and never again")
410 ("everylev1", po::value(&conf.every_lev1_reduce)->default_value(conf.every_lev1_reduce)
411 , "Reduce lev1 clauses every N")
412 ("everylev2", po::value(&conf.every_lev2_reduce)->default_value(conf.every_lev2_reduce)
413 , "Reduce lev2 clauses every N")
414 #if defined(FINAL_PREDICTOR) || defined(STATS_NEEDED)
415 ("everylev4", po::value(&conf.every_lev3_reduce)->default_value(conf.every_lev3_reduce)
416 , "Reduce final predictor (lev3) clauses every N, and produce data at every N in case of STATS_NEEDED")
417 #endif
418 ("lev1usewithin", po::value(&conf.must_touch_lev1_within)->default_value(conf.must_touch_lev1_within)
419 , "Learnt clause must be used in lev1 within this timeframe or be dropped to lev2")
420 ;
421
422 po::options_description red_cl_dump_opts("Clause dumping after problem finishing");
423 reduceDBOptions.add_options()
424 ("dumpred", po::value(&dump_red_fname)->default_value(dump_red_fname)
425 , "Dump redundant clauses of gluecut0&1 to this filename")
426 ("dumpredmaxlen", po::value(&dump_red_max_len)->default_value(dump_red_max_len)
427 , "When dumping redundant clauses, only dump clauses at most this long")
428 ("dumpredmaxglue", po::value(&dump_red_max_len)->default_value(dump_red_max_glue)
429 , "When dumping redundant clauses, only dump clauses with at most this large glue")
430 ;
431
432 po::options_description varPickOptions("Variable branching options");
433 varPickOptions.add_options()
434 ("branchstr"
435 , po::value(&conf.branch_strategy_setup)->default_value(conf.branch_strategy_setup)
436 , "Branch strategy. E.g. 'vmtf+vsids+maple+rnd'")
437 ;
438
439
440 po::options_description iterativeOptions("Iterative solve options");
441 iterativeOptions.add_options()
442 ("maxsol", po::value(&max_nr_of_solutions)->default_value(max_nr_of_solutions)
443 , "Search for given amount of solutions. Thanks to Jannis Harder for the decision-based banning idea")
444 ("nobansol", po::bool_switch(&dont_ban_solutions)
445 , "Don't ban the solution once it's found")
446 ("debuglib", po::value<string>(&debugLib)
447 , "Parse special comments to run solve/simplify during parsing of CNF")
448 ;
449
450 po::options_description breakid_options("Breakid options");
451 breakid_options.add_options()
452 ("breakid", po::value(&conf.doBreakid)->default_value(conf.doBreakid)
453 , "Run BreakID to break symmetries.")
454 ("breakideveryn", po::value(&conf.breakid_every_n)->default_value(conf.breakid_every_n)
455 , "Run BreakID every N simplification iterations")
456 ("breakidmaxlits", po::value(&conf.breakid_lits_limit_K)->default_value(conf.breakid_lits_limit_K)
457 , "Maximum number of literals in thousands. If exceeded, BreakID will not run")
458 ("breakidmaxcls", po::value(&conf.breakid_cls_limit_K)->default_value(conf.breakid_cls_limit_K)
459 , "Maximum number of clauses in thousands. If exceeded, BreakID will not run")
460 ("breakidmaxvars", po::value(&conf.breakid_vars_limit_K)->default_value(conf.breakid_vars_limit_K)
461 , "Maximum number of variables in thousands. If exceeded, BreakID will not run")
462 ("breakidtime", po::value(&conf.breakid_time_limit_K)->default_value(conf.breakid_time_limit_K)
463 , "Maximum number of steps taken during automorphism finding.")
464 ("breakidcls", po::value(&conf.breakid_max_constr_per_permut)
465 ->default_value(conf.breakid_max_constr_per_permut)
466 , "Maximum number of breaking clauses per permutation.")
467 ("breakidmatrix", po::value(&conf.breakid_matrix_detect)
468 ->default_value(conf.breakid_matrix_detect)
469 , "Detect matrix row interchangability")
470 ;
471
472 po::options_description sls_options("Stochastic Local Search options");
473 sls_options.add_options()
474 ("sls", po::value(&conf.doSLS)->default_value(conf.doSLS)
475 , "Run SLS during simplification")
476 ("slstype", po::value(&conf.which_sls)->default_value(conf.which_sls)
477 , "Which SLS to run. Allowed values: walksat, yalsat, ccnr, ccnr_yalsat")
478 ("slsmaxmem", po::value(&conf.sls_memoutMB)->default_value(conf.sls_memoutMB)
479 , "Maximum number of MB to give to SLS solver. Doesn't run SLS solver if the memory usage would be more than this.")
480 ("slseveryn", po::value(&conf.sls_every_n)->default_value(conf.sls_every_n)
481 , "Run SLS solver every N simplifications only")
482 ("yalsatmems", po::value(&conf.yalsat_max_mems)->default_value(conf.yalsat_max_mems)
483 , "Run Yalsat with this many mems*million timeout. Limits time of yalsat run")
484 ("walksatruns", po::value(&conf.walksat_max_runs)->default_value(conf.walksat_max_runs)
485 , "Max 'runs' for WalkSAT. Limits time of WalkSAT run")
486 ("slsgetphase", po::value(&conf.sls_get_phase)->default_value(conf.sls_get_phase)
487 , "Get phase from SLS solver, set as new phase for CDCL")
488 ("slsccnraspire", po::value(&conf.sls_ccnr_asipire)->default_value(conf.sls_ccnr_asipire)
489 , "Turn aspiration on/off for CCANR")
490 ("slstobump", po::value(&conf.sls_how_many_to_bump)->default_value(conf.sls_how_many_to_bump)
491 , "How many variables to bump in CCNR")
492 ("slstobumpmaxpervar", po::value(&conf.sls_bump_var_max_n_times)->default_value(conf.sls_bump_var_max_n_times)
493 , "How many times to bump an individual variable's activity in CCNR")
494 ("slsbumptype", po::value(&conf.sls_bump_type)->default_value(conf.sls_bump_type)
495 , "How to calculate what variable to bump. 1 = clause-based, 2 = var-flip-based, 3 = var-score-based")
496 ("slsoffset", po::value(&conf.sls_set_offset)->default_value(conf.sls_set_offset)
497 , "Should SLS set the VSIDS/Maple offsetsd")
498 ;
499
500 po::options_description probeOptions("Probing options");
501 probeOptions.add_options()
502 ("transred", po::value(&conf.doTransRed)->default_value(conf.doTransRed)
503 , "Remove useless binary clauses (transitive reduction)")
504 ("intree", po::value(&conf.doIntreeProbe)->default_value(conf.doIntreeProbe)
505 , "Carry out intree-based probing")
506 ("intreemaxm", po::value(&conf.intree_time_limitM)->default_value(conf.intree_time_limitM)
507 , "Time in mega-bogoprops to perform intree probing")
508 ("otfhyper", po::value(&conf.do_hyperbin_and_transred)->default_value(conf.do_hyperbin_and_transred)
509 , "Perform hyper-binary resolution during probing")
510 ;
511
512 std::ostringstream ssERatio;
513 ssERatio << std::setprecision(4) << conf.varElimRatioPerIter;
514
515 std::ostringstream s_num_conflicts_of_search_inc;
516 s_num_conflicts_of_search_inc << std::setprecision(4) << conf.num_conflicts_of_search_inc;
517
518 po::options_description simp_schedules("Simplification schedules");
519 simp_schedules.add_options()
520 ("schedsimp", po::value(&conf.do_simplify_problem)->default_value(conf.do_simplify_problem)
521 , "Perform simplification rounds. If 0, we never perform any.")
522 ("presimp", po::value(&conf.simplify_at_startup)->default_value(conf.simplify_at_startup)
523 , "Perform simplification at the very start")
524 ("allpresimp", po::value(&conf.simplify_at_every_startup)->default_value(conf.simplify_at_every_startup)
525 , "Perform simplification at EVERY start -- only matters in library mode")
526 ("nonstop,n", po::value(&conf.never_stop_search)->default_value(conf.never_stop_search)
527 , "Never stop the search() process in class SATSolver")
528 ("maxnumsimppersolve", po::value(&conf.max_num_simplify_per_solve_call)->default_value(conf.max_num_simplify_per_solve_call)
529 , "Maximum number of simplifiactions to perform for every solve() call. After this, no more inprocessing will take place.")
530
531 ("schedule", po::value(&conf.simplify_schedule_nonstartup)
532 , "Schedule for simplification during run")
533 ("preschedule", po::value(&conf.simplify_schedule_startup)
534 , "Schedule for simplification at startup")
535
536 ("occsimp", po::value(&conf.perform_occur_based_simp)->default_value(conf.perform_occur_based_simp)
537 , "Perform occurrence-list-based optimisations (variable elimination, subsumption, bounded variable addition...)")
538
539
540 ("confbtwsimp", po::value(&conf.num_conflicts_of_search)->default_value(conf.num_conflicts_of_search)
541 , "Start first simplification after this many conflicts")
542 ("confbtwsimpinc", po::value(&conf.num_conflicts_of_search_inc)->default_value(conf.num_conflicts_of_search_inc, s_num_conflicts_of_search_inc.str())
543 , "Simp rounds increment by this power of N")
544 ;
545
546 std::ostringstream tern_keep;
547 tern_keep << std::setprecision(2) << conf.ternary_keep_mult;
548
549 std::ostringstream tern_max_create;
550 tern_max_create << std::setprecision(2) << conf.ternary_max_create;
551
552 po::options_description tern_res_options("Ternary resolution");
553 tern_res_options.add_options()
554 ("tern", po::value(&conf.doTernary)->default_value(conf.doTernary)
555 , "Perform Ternary resolution'")
556 ("terntimelim", po::value(&conf.ternary_res_time_limitM)->default_value(conf.ternary_res_time_limitM)
557 , "Time-out in bogoprops M of ternary resolution as per paper 'Look-Ahead Versus Look-Back for Satisfiability Problems'")
558 ("ternkeep", po::value(&conf.ternary_keep_mult)->default_value(conf.ternary_keep_mult, tern_keep.str())
559 , "Keep ternary resolution clauses only if they are touched within this multiple of 'lev1usewithin'")
560 ("terncreate", po::value(&conf.ternary_max_create)->default_value(conf.ternary_max_create, tern_max_create.str())
561 , "Create only this multiple (of linked in cls) ternary resolution clauses per simp run")
562 ("ternbincreate", po::value(&conf.allow_ternary_bin_create)->default_value(conf.allow_ternary_bin_create, tern_max_create.str())
563 , "Allow ternary resolving to generate binary clauses")
564 ;
565
566 po::options_description occ_mem_limits("Occ-based simplification memory limits");
567 occ_mem_limits.add_options()
568 ("occredmax", po::value(&conf.maxRedLinkInSize)->default_value(conf.maxRedLinkInSize)
569 , "Don't add to occur list any redundant clause larger than this")
570 ("occredmaxmb", po::value(&conf.maxOccurRedMB)->default_value(conf.maxOccurRedMB)
571 , "Don't allow redundant occur size to be beyond this many MB")
572 ("occirredmaxmb", po::value(&conf.maxOccurIrredMB)->default_value(conf.maxOccurIrredMB)
573 , "Don't allow irredundant occur size to be beyond this many MB")
574 ;
575
576 po::options_description sub_str_time_limits("Occ-based subsumption and strengthening time limits");
577 sub_str_time_limits.add_options()
578 ("strengthen", po::value(&conf.do_strengthen_with_occur)->default_value(conf.do_strengthen_with_occur)
579 , "Perform clause contraction through self-subsuming resolution as part of the occurrence-subsumption system")
580 ("substimelim", po::value(&conf.subsumption_time_limitM)->default_value(conf.subsumption_time_limitM)
581 , "Time-out in bogoprops M of subsumption of long clauses with long clauses, after computing occur")
582 ("substimelimbinratio", po::value(&conf.subsumption_time_limit_ratio_sub_str_w_bin)->default_value(conf.subsumption_time_limit_ratio_sub_str_w_bin)
583 , "Ratio of subsumption time limit to spend on sub&str long clauses with bin")
584 ("substimelimlongratio", po::value(&conf.subsumption_time_limit_ratio_sub_w_long)->default_value(conf.subsumption_time_limit_ratio_sub_w_long)
585 , "Ratio of subsumption time limit to spend on sub long clauses with long")
586 ("strstimelim", po::value(&conf.strengthening_time_limitM)->default_value(conf.strengthening_time_limitM)
587 , "Time-out in bogoprops M of strengthening of long clauses with long clauses, after computing occur")
588 ("sublonggothrough", po::value(&conf.subsume_gothrough_multip)->default_value(conf.subsume_gothrough_multip)
589 , "How many times go through subsume")
590 ;
591
592 po::options_description bva_options("BVA options");
593 bva_options.add_options()
594 ("bva", po::value(&conf.do_bva)->default_value(conf.do_bva)
595 , "Perform bounded variable addition")
596 ("bvaeveryn", po::value(&conf.bva_every_n)->default_value(conf.bva_every_n)
597 , "Perform BVA only every N occ-simplify calls")
598 ("bvalim", po::value(&conf.bva_limit_per_call)->default_value(conf.bva_limit_per_call)
599 , "Maximum number of variables to add by BVA per call")
600 ("bva2lit", po::value(&conf.bva_also_twolit_diff)->default_value(conf.bva_also_twolit_diff)
601 , "BVA with 2-lit difference hack, too. Beware, this reduces the effectiveness of 1-lit diff")
602 ("bvato", po::value(&conf.bva_time_limitM)->default_value(conf.bva_time_limitM)
603 , "BVA time limit in bogoprops M")
604 ;
605
606 po::options_description bve_options("BVE options");
607 bve_options.add_options()
608 ("varelim", po::value(&conf.doVarElim)->default_value(conf.doVarElim)
609 , "Perform variable elimination as per Een and Biere")
610 ("varelimto", po::value(&conf.varelim_time_limitM)->default_value(conf.varelim_time_limitM)
611 , "Var elimination bogoprops M time limit")
612 ("varelimover", po::value(&conf.min_bva_gain)->default_value(conf.min_bva_gain)
613 , "Do BVE until the resulting no. of clause increase is less than X. Only power of 2 makes sense, i.e. 2,4,8...")
614 ("emptyelim", po::value(&conf.do_empty_varelim)->default_value(conf.do_empty_varelim)
615 , "Perform empty resolvent elimination using bit-map trick")
616 ("varelimmaxmb", po::value(&conf.var_linkin_limit_MB)->default_value(conf.var_linkin_limit_MB)
617 , "Maximum extra MB of memory to use for new clauses during varelim")
618 ("eratio", po::value(&conf.varElimRatioPerIter)->default_value(conf.varElimRatioPerIter, ssERatio.str())
619 , "Eliminate this ratio of free variables at most per variable elimination iteration")
620 ("skipresol", po::value(&conf.skip_some_bve_resolvents)->default_value(conf.skip_some_bve_resolvents)
621 , "Skip BVE resolvents in case they belong to a gate")
622 ;
623
624 po::options_description xorOptions("XOR-related options");
625 xorOptions.add_options()
626 ("xor", po::value(&conf.doFindXors)->default_value(conf.doFindXors)
627 , "Discover long XORs")
628 ("maxxorsize", po::value(&conf.maxXorToFind)->default_value(conf.maxXorToFind)
629 , "Maximum XOR size to find")
630 ("xorfindtout", po::value(&conf.xor_finder_time_limitM)->default_value(conf.xor_finder_time_limitM)
631 , "Time limit for finding XORs")
632 ("varsperxorcut", po::value(&conf.xor_var_per_cut)->default_value(conf.xor_var_per_cut)
633 , "Number of _real_ variables per XOR when cutting them. So 2 will have XORs of size 4 because 1 = connecting to previous, 1 = connecting to next, 2 in the midde. If the XOR is 4 long, it will be just one 4-long XOR, no connectors")
634 ("maxxormat", po::value(&conf.maxXORMatrix)->default_value(conf.maxXORMatrix)
635 , "Maximum matrix size (=num elements) that we should try to echelonize")
636 ("forcepreservexors", po::value(&conf.force_preserve_xors)->default_value(conf.force_preserve_xors)
637 , "Force preserving XORs when they have been found. Easier to make sure XORs are not lost through simplifiactions such as strenghtening")
638 #ifdef USE_M4RI
639 ("m4ri", po::value(&conf.doM4RI)->default_value(conf.doM4RI)
640 , "Use M4RI")
641 #endif
642 //Not implemented yet
643 //("mix", po::value(&conf.doMixXorAndGates)->default_value(conf.doMixXorAndGates)
644 // , "Mix XORs and OrGates for new truths")
645 ;
646
647 po::options_description eqLitOpts("Equivalent literal options");
648 eqLitOpts.add_options()
649 ("scc", po::value(&conf.doFindAndReplaceEqLits)->default_value(conf.doFindAndReplaceEqLits)
650 , "Find equivalent literals through SCC and replace them")
651 ;
652
653 po::options_description gateOptions("Gate-related options");
654 gateOptions.add_options()
655 ("gates", po::value(&conf.doGateFind)->default_value(conf.doGateFind)
656 , "Find gates. Disables all sub-options below")
657 ("gorshort", po::value(&conf.doShortenWithOrGates)->default_value(conf.doShortenWithOrGates)
658 , "Shorten clauses with OR gates")
659 ("gandrem", po::value(&conf.doRemClWithAndGates)->default_value(conf.doRemClWithAndGates)
660 , "Remove clauses with AND gates")
661 ("gateeqlit", po::value(&conf.doFindEqLitsWithGates)->default_value(conf.doFindEqLitsWithGates)
662 , "Find equivalent literals using gates")
663 /*("maxgatesz", po::value(&conf.maxGateSize)->default_value(conf.maxGateSize)
664 , "Maximum gate size to discover")*/
665 ("printgatedot", po::value(&conf.doPrintGateDot)->default_value(conf.doPrintGateDot)
666 , "Print gate structure regularly to file 'gatesX.dot'")
667 ("gatefindto", po::value(&conf.gatefinder_time_limitM)->default_value(conf.gatefinder_time_limitM)
668 , "Max time in bogoprops M to find gates")
669 ("shortwithgatesto", po::value(&conf.shorten_with_gates_time_limitM)->default_value(conf.shorten_with_gates_time_limitM)
670 , "Max time to shorten with gates, bogoprops M")
671 ("remwithgatesto", po::value(&conf.remove_cl_with_gates_time_limitM)->default_value(conf.remove_cl_with_gates_time_limitM)
672 , "Max time to remove with gates, bogoprops M")
673 ;
674
675 po::options_description conflOptions("Conflict options");
676 conflOptions.add_options()
677 ("recur", po::value(&conf.doRecursiveMinim)->default_value(conf.doRecursiveMinim)
678 , "Perform recursive minimisation")
679 ("moreminim", po::value(&conf.doMinimRedMore)->default_value(conf.doMinimRedMore)
680 , "Perform strong minimisation at conflict gen.")
681 ("moremoreminim", po::value(&conf.doMinimRedMoreMore)->default_value(conf.doMinimRedMoreMore)
682 , "Perform even stronger minimisation at conflict gen.")
683 ("moremorealways", po::value(&conf.doAlwaysFMinim)->default_value(conf.doAlwaysFMinim)
684 , "Always strong-minimise clause")
685 ("decbased", po::value(&conf.do_decision_based_cl)->default_value(conf.do_decision_based_cl)
686 , "Create decision-based conflict clauses when the UIP clause is too large")
687 ;
688
689 po::options_description propOptions("Glue options");
690 propOptions.add_options()
691 ("updateglueonanalysis", po::value(&conf.update_glues_on_analyze)->default_value(conf.update_glues_on_analyze)
692 , "Update glues while analyzing")
693 ("maxgluehistltlimited", po::value(&conf.max_glue_cutoff_gluehistltlimited)->default_value(conf.max_glue_cutoff_gluehistltlimited)
694 , "Maximum glue used by glue-based restart strategy when populating glue history.")
695 ;
696
697 po::options_description chrono_bt_opts("Propagation options");
698 chrono_bt_opts.add_options()
699 ("diffdeclevelchrono", po::value(&conf.diff_declev_for_chrono)->default_value(conf.diff_declev_for_chrono)
700 , "Difference in decision level is more than this, perform chonological backtracking instead of non-chronological backtracking. Giving -1 means it is never turned on (overrides '--confltochrono -1' in this case).")
701 ;
702
703 po::options_description sqlOptions("SQL options");
704 sqlOptions.add_options()
705 ("sql", po::value(&sql)->default_value(0)
706 , "Write to SQL. 0 = no SQL, 1 or 2 = sqlite")
707 ("sqlitedb", po::value(&sqlite_filename)
708 , "Where to put the SQLite database")
709 ("sqlitedboverwrite", po::value(&conf.sql_overwrite_file)->default_value(conf.sql_overwrite_file)
710 , "Overwrite the SQLite database file if it exists")
711 ("cldatadumpratio", po::value(&conf.dump_individual_cldata_ratio)->default_value(conf.dump_individual_cldata_ratio)
712 , "Only dump this ratio of clauses' data, randomly selected. Since machine learning doesn't need that much data, this can reduce the data you have to deal with.")
713 ("cllockdatagen", po::value(&conf.lock_for_data_gen_ratio)->default_value(conf.lock_for_data_gen_ratio)
714 , "Lock for data generation into lev0, setting locked_for_data_gen. Only works when clause is marked for dumping ('--cldatadumpratio' )")
715 ;
716
717 po::options_description printOptions("Printing options");
718 printOptions.add_options()
719 ("verbstat", po::value(&conf.verbStats)->default_value(conf.verbStats)
720 , "Change verbosity of statistics at the end of the solving [0..3]")
721 ("verbrestart", po::value(&conf.print_full_restart_stat)->default_value(conf.print_full_restart_stat)
722 , "Print more thorough, but different stats")
723 ("verballrestarts", po::value(&conf.print_all_restarts)->default_value(conf.print_all_restarts)
724 , "Print a line for every restart")
725 ("printsol,s", po::value(&printResult)->default_value(printResult)
726 , "Print assignment if solution is SAT")
727 ("restartprint", po::value(&conf.print_restart_line_every_n_confl)->default_value(conf.print_restart_line_every_n_confl)
728 , "Print restart status lines at least every N conflicts")
729 ("dumpresult", po::value(&resultFilename)
730 , "Write solution(s) to this file")
731 ;
732
733 po::options_description componentOptions("Component options");
734 componentOptions.add_options()
735 ("comps", po::value(&conf.doCompHandler)->default_value(conf.doCompHandler)
736 , "Perform component-finding and separate handling")
737 ("compsfrom", po::value(&conf.handlerFromSimpNum)->default_value(conf.handlerFromSimpNum)
738 , "Component finding only after this many simplification rounds")
739 ("compsvar", po::value(&conf.compVarLimit)->default_value(conf.compVarLimit)
740 , "Only use components in case the number of variables is below this limit")
741 ("compslimit", po::value(&conf.comp_find_time_limitM)->default_value(conf.comp_find_time_limitM)
742 , "Limit how much time is spent in component-finding");
743
744 po::options_description distillOptions("Distill options");
745 distillOptions.add_options()
746 //("noparts", "Don't find&solve subproblems with subsolvers")
747 ("distill", po::value(&conf.do_distill_clauses)->default_value(conf.do_distill_clauses)
748 , "Regularly execute clause distillation")
749 ("distillmaxm", po::value(&conf.distill_long_cls_time_limitM)->default_value(conf.distill_long_cls_time_limitM)
750 , "Maximum number of Mega-bogoprops(~time) to spend on vivifying/distilling long cls by enqueueing and propagating")
751 ("distillto", po::value(&conf.distill_time_limitM)->default_value(conf.distill_time_limitM)
752 , "Maximum time in bogoprops M for distillation")
753 ("distillincconf", po::value(&conf.distill_increase_conf_ratio)->default_value(conf.distill_increase_conf_ratio)
754 , "Multiplier for current number of conflicts OTF distill")
755 ("distillminconf", po::value(&conf.distill_min_confl)->default_value(conf.distill_min_confl)
756 , "Minimum number of conflicts between OTF distill")
757 ("distilltier1ratio", po::value(&conf.distill_red_tier1_ratio)->default_value(conf.distill_red_tier1_ratio)
758 , "How much of tier 1 to distill")
759 ;
760
761 po::options_description mem_save_opts("Memory saving options");
762 mem_save_opts.add_options()
763 ("renumber", po::value(&conf.doRenumberVars)->default_value(conf.doRenumberVars)
764 , "Renumber variables to increase CPU cache efficiency")
765 ("savemem", po::value(&conf.doSaveMem)->default_value(conf.doSaveMem)
766 , "Save memory by deallocating variable space after renumbering. Only works if renumbering is active.")
767 ("mustrenumber", po::value(&conf.must_renumber)->default_value(conf.must_renumber)
768 , "Treat all 'renumber' strategies as 'must-renumber'")
769 ("fullwatchconseveryn", po::value(&conf.full_watch_consolidate_every_n_confl)->default_value(conf.full_watch_consolidate_every_n_confl)
770 , "Consolidate watchlists fully once every N conflicts. Scheduled during simplification rounds.")
771 ;
772
773 po::options_description miscOptions("Misc options");
774 miscOptions.add_options()
775 //("noparts", "Don't find&solve subproblems with subsolvers")
776 ("strmaxt", po::value(&conf.watch_based_str_time_limitM)->default_value(conf.watch_based_str_time_limitM)
777 , "Maximum MBP to spend on distilling long irred cls through watches")
778 ("implicitmanip", po::value(&conf.doStrSubImplicit)->default_value(conf.doStrSubImplicit)
779 , "Subsume and strengthen implicit clauses with each other")
780 ("implsubsto", po::value(&conf.subsume_implicit_time_limitM)->default_value(conf.subsume_implicit_time_limitM)
781 , "Timeout (in bogoprop Millions) of implicit subsumption")
782 ("implstrto", po::value(&conf.distill_implicit_with_implicit_time_limitM)->default_value(conf.distill_implicit_with_implicit_time_limitM)
783 , "Timeout (in bogoprop Millions) of implicit strengthening")
784 ("cardfind", po::value(&conf.doFindCard)->default_value(conf.doFindCard)
785 , "Find cardinality constraints")
786 ;
787
788 po::options_description reconfOptions("Reconf options");
789 reconfOptions.add_options()
790 ("reconfat", po::value(&conf.reconfigure_at)->default_value(conf.reconfigure_at)
791 , "Reconfigure after this many simplifications")
792 ("reconf", po::value(&conf.reconfigure_val)->default_value(conf.reconfigure_val)
793 , "Reconfigure after some time to this solver configuration [3,4,6,7,12,13,14,15,16]")
794 ;
795
796 hiddenOptions.add_options()
797 ("sync", po::value(&conf.sync_every_confl)->default_value(conf.sync_every_confl)
798 , "Sync threads every N conflicts")
799 ("dratdebug", po::bool_switch(&dratDebug)
800 , "Output DRAT verification into the console. Helpful to see where DRAT fails -- use in conjunction with --verb 20")
801 ("clearinter", po::value(&need_clean_exit)->default_value(0)
802 , "Interrupt threads cleanly, all the time")
803 ("zero-exit-status", po::bool_switch(&zero_exit_status)
804 , "Exit with status zero in case the solving has finished without an issue")
805 ("printtimes", po::value(&conf.do_print_times)->default_value(conf.do_print_times)
806 , "Print time it took for each simplification run. If set to 0, logs are easier to compare")
807 ("savedstate", po::value(&conf.saved_state_file)->default_value(conf.saved_state_file)
808 , "The file to save the saved state of the solver")
809 ("maxsccdepth", po::value(&conf.max_scc_depth)->default_value(conf.max_scc_depth)
810 , "The maximum for scc search depth")
811 ("simdrat", po::value(&conf.simulate_drat)->default_value(conf.simulate_drat)
812 , "Simulate DRAT")
813 ("sampling", po::value(&sampling_vars_str)->default_value(sampling_vars_str)
814 , "Sampling vars, separated by comma")
815 ("onlysampling", po::bool_switch(&only_sampling_solution)
816 , "Print and ban(!) solutions only in terms of variables declared in 'c ind' or as --sampling '...'")
817 ("assump", po::value(&assump_filename)->default_value(assump_filename)
818 , "Assumptions file")
819
820 //these a kind of special and determine positional options' meanings
821 ("input", po::value< vector<string> >(), "file(s) to read")
822 ("drat,d", po::value(&dratfilname)
823 , "Put DRAT verification information into this file")
824 ;
825
826 #ifdef USE_BOSPHORUS
827 po::options_description bosph_options("Gauss options");
828 bosph_options.add_options()
829 ("bosph", po::value(&conf.do_bosphorus)->default_value(conf.do_bosphorus)
830 , "Execute bosphorus")
831 ("bospheveryn", po::value(&conf.bosphorus_every_n)->default_value(conf.bosphorus_every_n)
832 , "Execute bosphorus only every Nth iteration -- starting at Nth iter.")
833 ;
834 #endif
835
836 #ifdef USE_GAUSS
837 po::options_description gaussOptions("Gauss options");
838 gaussOptions.add_options()
839 ("maxmatrixrows", po::value(&conf.gaussconf.max_matrix_rows)->default_value(conf.gaussconf.max_matrix_rows)
840 , "Set maximum no. of rows for gaussian matrix. Too large matrices"
841 "should bee discarded for reasons of efficiency")
842 ("autodisablegauss", po::value(&conf.gaussconf.autodisable)->default_value(conf.gaussconf.autodisable)
843 , "Automatically disable gauss when performing badly")
844 ("minmatrixrows", po::value(&conf.gaussconf.min_matrix_rows)->default_value(conf.gaussconf.min_matrix_rows)
845 , "Set minimum no. of rows for gaussian matrix. Normally, too small"
846 " matrices are discarded for reasons of efficiency")
847 ("maxnummatrices", po::value(&conf.gaussconf.max_num_matrices)->default_value(conf.gaussconf.max_num_matrices)
848 , "Maximum number of matrices to treat.")
849 ("detachxor", po::value(&conf.xor_detach_reattach)->default_value(conf.xor_detach_reattach)
850 , "Detach and reattach XORs")
851 ("useallmatrixes", po::value(&conf.force_use_all_matrixes)->default_value(conf.force_use_all_matrixes)
852 , "Force using all matrices")
853 ("detachverb", po::value(&conf.xor_detach_verb)->default_value(conf.xor_detach_verb)
854 , "If set, verbosity for XOR detach code is upped, ignoring normal verbosity")
855 ("gaussusefulcutoff", po::value(&conf.gaussconf.min_usefulness_cutoff)->default_value(conf.gaussconf.min_usefulness_cutoff)
856 , "Turn off Gauss if less than this many usefulenss ratio is recorded")
857 ;
858 #endif //USE_GAUSS
859
860 help_options_complicated
861 .add(generalOptions)
862 .add(polar_options)
863 #if defined(USE_SQLITE3)
864 .add(sqlOptions)
865 #endif
866 .add(restartOptions)
867 #if defined(FINAL_PREDICTOR)
868 .add(predictOptions)
869 #endif
870 .add(printOptions)
871 .add(propOptions)
872 .add(chrono_bt_opts)
873 .add(reduceDBOptions)
874 .add(red_cl_dump_opts)
875 .add(varPickOptions)
876 .add(conflOptions)
877 .add(iterativeOptions)
878 .add(probeOptions)
879 .add(sls_options)
880 #ifdef USE_BREAKID
881 .add(breakid_options)
882 #endif
883 #ifdef USE_BOSPHORUS
884 .add(bosph_options)
885 #endif
886 .add(simp_schedules)
887 .add(occ_mem_limits)
888 .add(tern_res_options)
889 .add(sub_str_time_limits)
890 .add(bve_options)
891 .add(bva_options)
892 .add(eqLitOpts)
893 .add(componentOptions)
894 .add(mem_save_opts)
895 .add(xorOptions)
896 .add(gateOptions)
897 #ifdef USE_GAUSS
898 .add(gaussOptions)
899 #endif
900 .add(distillOptions)
901 .add(reconfOptions)
902 .add(miscOptions)
903 ;
904 }
905 /* clang-format on */
906
remove_last_comma_if_exists(std::string s)907 string remove_last_comma_if_exists(std::string s)
908 {
909 std::string s2 = s;
910 if (s[s.length()-1] == ',')
911 s2.resize(s2.length()-1);
912 return s2;
913 }
914
check_options_correctness()915 void Main::check_options_correctness()
916 {
917 try {
918 po::store(po::command_line_parser(argc, argv).options(all_options).positional(p).run(), vm);
919 if (vm.count("hhelp"))
920 {
921 cout
922 << "A universal, fast SAT solver with XOR and Gaussian Elimination support. " << endl
923 << "Input "
924 #ifndef USE_ZLIB
925 << "must be plain"
926 #else
927 << "can be either plain or gzipped"
928 #endif
929 << " DIMACS with XOR extension" << endl << endl;
930
931 cout
932 << "cryptominisat5 [options] inputfile [drat-trim-file]" << endl << endl;
933
934 cout << "Preprocessor usage:" << endl
935 << " cryptominisat5 --preproc 1 [options] inputfile simplified-cnf-file" << endl << endl
936 << " cryptominisat5 --preproc 2 [options] solution-file" << endl;
937
938 cout << help_options_complicated << endl;
939 cout << "Normal run schedules:" << endl;
940 cout << " Default schedule: "
941 << remove_last_comma_if_exists(conf.simplify_schedule_nonstartup) << endl<< endl;
942 cout << " Schedule at startup: "
943 << remove_last_comma_if_exists(conf.simplify_schedule_startup) << endl << endl;
944
945 cout << "Preproc run schedule:" << endl;
946 cout << " "
947 << remove_last_comma_if_exists(conf.simplify_schedule_preproc) << endl;
948 std::exit(0);
949 }
950
951 if (vm.count("help"))
952 {
953 cout
954 << "USAGE 1: " << argv[0] << " [options] inputfile [drat-trim-file]" << endl
955 << "USAGE 2: " << argv[0] << " --preproc 1 [options] inputfile simplified-cnf-file" << endl
956 << "USAGE 2: " << argv[0] << " --preproc 2 [options] solution-file" << endl
957
958 << " where input is "
959 #ifndef USE_ZLIB
960 << "plain"
961 #else
962 << "plain or gzipped"
963 #endif
964 << " DIMACS." << endl;
965
966 cout << help_options_simple << endl;
967 std::exit(0);
968 }
969
970 po::notify(vm);
971 } catch (boost::exception_detail::clone_impl<
972 boost::exception_detail::error_info_injector<po::unknown_option> >& c
973 ) {
974 cerr
975 << "ERROR: Some option you gave was wrong. Please give '--help' to get help" << endl
976 << " Unknown option: " << c.what() << endl;
977 std::exit(-1);
978 } catch (boost::bad_any_cast &e) {
979 std::cerr
980 << "ERROR! You probably gave a wrong argument type" << endl
981 << " Bad cast: " << e.what()
982 << endl;
983
984 std::exit(-1);
985 } catch (boost::exception_detail::clone_impl<
986 boost::exception_detail::error_info_injector<po::invalid_option_value> >& what
987 ) {
988 cerr
989 << "ERROR: Invalid value '" << what.what() << "'" << endl
990 << " given to option '" << what.get_option_name() << "'"
991 << endl;
992
993 std::exit(-1);
994 } catch (boost::exception_detail::clone_impl<
995 boost::exception_detail::error_info_injector<po::multiple_occurrences> >& what
996 ) {
997 cerr
998 << "ERROR: " << what.what() << " of option '"
999 << what.get_option_name() << "'"
1000 << endl;
1001
1002 std::exit(-1);
1003 } catch (boost::exception_detail::clone_impl<
1004 boost::exception_detail::error_info_injector<po::required_option> >& what
1005 ) {
1006 cerr
1007 << "ERROR: You forgot to give a required option '"
1008 << what.get_option_name() << "'"
1009 << endl;
1010
1011 std::exit(-1);
1012 } catch (boost::exception_detail::clone_impl<
1013 boost::exception_detail::error_info_injector<po::too_many_positional_options_error> >& what
1014 ) {
1015 cerr
1016 << "ERROR: You gave too many positional arguments. Only at most two can be given:" << endl
1017 << " the 1st the CNF file input, and optionally, the 2nd the DRAT file output" << endl
1018 << " OR (pre-processing) 1st for the input CNF, 2nd for the simplified CNF" << endl
1019 << " OR (post-processing) 1st for the solution file" << endl
1020 ;
1021
1022 std::exit(-1);
1023 } catch (boost::exception_detail::clone_impl<
1024 boost::exception_detail::error_info_injector<po::ambiguous_option> >& what
1025 ) {
1026 cerr
1027 << "ERROR: The option you gave was not fully written and matches" << endl
1028 << " more than one option. Please give the full option name." << endl
1029 << " The option you gave: '" << what.get_option_name() << "'" <<endl
1030 << " The alternatives are: ";
1031 for(size_t i = 0; i < what.alternatives().size(); i++) {
1032 cout << what.alternatives()[i];
1033 if (i+1 < what.alternatives().size()) {
1034 cout << ", ";
1035 }
1036 }
1037 cout << endl;
1038
1039 std::exit(-1);
1040 } catch (boost::exception_detail::clone_impl<
1041 boost::exception_detail::error_info_injector<po::invalid_command_line_syntax> >& what
1042 ) {
1043 cerr
1044 << "ERROR: The option you gave is missing the argument or the" << endl
1045 << " argument is given with space between the equal sign." << endl
1046 << " detailed error message: " << what.what() << endl
1047 ;
1048 std::exit(-1);
1049 }
1050 }
1051
parse_restart_type()1052 void Main::parse_restart_type()
1053 {
1054 if (vm.count("restart")) {
1055 string type = vm["restart"].as<string>();
1056 if (type == "geom")
1057 conf.restartType = Restart::geom;
1058 else if (type == "luby")
1059 conf.restartType = Restart::luby;
1060 else if (type == "glue")
1061 conf.restartType = Restart::glue;
1062 else if (type == "glue-geom")
1063 conf.restartType = Restart::glue_geom;
1064 else throw WrongParam("restart", "unknown restart type");
1065 }
1066 }
1067
parse_polarity_type()1068 void Main::parse_polarity_type()
1069 {
1070 if (vm.count("polar")) {
1071 string mode = vm["polar"].as<string>();
1072
1073 if (mode == "true") conf.polarity_mode = PolarityMode::polarmode_pos;
1074 else if (mode == "false") conf.polarity_mode = PolarityMode::polarmode_neg;
1075 else if (mode == "rnd") conf.polarity_mode = PolarityMode::polarmode_rnd;
1076 else if (mode == "auto") conf.polarity_mode = PolarityMode::polarmode_automatic;
1077 else if (mode == "weight") conf.polarity_mode = PolarityMode::polarmode_weighted;
1078 else throw WrongParam(mode, "unknown polarity-mode");
1079 }
1080 }
1081
manually_parse_some_options()1082 void Main::manually_parse_some_options()
1083 {
1084 #ifndef USE_BREAKID
1085 if (conf.doBreakid) {
1086 if (conf.verbosity) {
1087 cout << "c BreakID not compiled in, disabling" << endl;
1088 }
1089 conf.doBreakid = false;
1090 }
1091 #endif
1092
1093 if (conf.max_glue_cutoff_gluehistltlimited > 100000) {
1094 cout << "ERROR: 'Maximum supported glue size is currently 100000" << endl;
1095 exit(-1);
1096 }
1097
1098 if (conf.which_sls != "yalsat" &&
1099 conf.which_sls != "walksat" &&
1100 conf.which_sls != "ccnr_yalsat" &&
1101 conf.which_sls != "ccnr")
1102 {
1103 cout << "ERROR: you gave '" << conf.which_sls << " for SLS with the option '--slstype'."
1104 << " This is incorrect, we only accept 'yalsat' and 'walksat'"
1105 << endl;
1106 }
1107
1108
1109 if (conf.yalsat_max_mems < 1) {
1110 cout << "ERROR: '--walkmems' must be at least 1" << endl;
1111 exit(-1);
1112 }
1113
1114 if (conf.sls_every_n < 1) {
1115 cout << "ERROR: '--walkeveryn' must be at least 1" << endl;
1116 exit(-1);
1117 }
1118
1119 if (conf.maxXorToFind > MAX_XOR_RECOVER_SIZE) {
1120 cout << "ERROR: The '--maxxorsize' parameter cannot be larger than " << MAX_XOR_RECOVER_SIZE << endl;
1121 exit(-1);
1122 }
1123
1124 if (conf.shortTermHistorySize <= 0) {
1125 cout
1126 << "You MUST give a short term history size (\"--gluehist\")" << endl
1127 << " greater than 0!"
1128 << endl;
1129
1130 std::exit(-1);
1131 }
1132
1133 if (conf.preprocess != 0) {
1134 conf.simplify_at_startup = 1;
1135 conf.varelim_time_limitM *= 5;
1136 conf.orig_global_timeout_multiplier *= 1.5;
1137 if (conf.doCompHandler) {
1138 conf.doCompHandler = false;
1139 if (conf.verbosity) {
1140 cout << "c Cannot handle components when preprocessing. Turning it off." << endl;
1141 }
1142 }
1143
1144 if (num_threads > 1) {
1145 num_threads = 1;
1146 cout << "c Cannot handle multiple threads for preprocessing. Setting to 1." << endl;
1147 }
1148
1149
1150 if (!redDumpFname.empty()
1151 || !irredDumpFname.empty()
1152 ) {
1153 std::cerr << "ERROR: dumping clauses with preprocessing makes no sense. Exiting" << endl;
1154 std::exit(-1);
1155 }
1156
1157 if (max_nr_of_solutions > 1) {
1158 std::cerr << "ERROR: multi-solutions make no sense with preprocessing. Exiting." << endl;
1159 std::exit(-1);
1160 }
1161
1162 if (!filesToRead.empty()) {
1163 assert(false && "we should never reach this place, filesToRead has not been populated yet");
1164 exit(-1);
1165 }
1166
1167 if (!debugLib.empty()) {
1168 std::cerr << "ERROR: debugLib makes no sense with preprocessing. Exiting." << endl;
1169 std::exit(-1);
1170 }
1171
1172 if (vm.count("schedule")) {
1173 std::cerr << "ERROR: Please adjust the --preschedule not the --schedule when preprocessing. Exiting." << endl;
1174 std::exit(-1);
1175 }
1176
1177 if (vm.count("occschedule")) {
1178 std::cerr << "ERROR: Please adjust the --preoccschedule not the --occschedule when preprocessing. Exiting." << endl;
1179 std::exit(-1);
1180 }
1181
1182 if (!vm.count("preschedule")) {
1183 conf.simplify_schedule_startup = conf.simplify_schedule_preproc;
1184 }
1185
1186 if (!vm.count("eratio")) {
1187 conf.varElimRatioPerIter = 2.0;
1188 }
1189 } else {
1190 if (!vm["savedstate"].defaulted()) {
1191 cout << "ERROR: It does not make sense to have --savedstate passed and not use preprocessing" << endl;
1192 exit(-1);
1193 }
1194 }
1195
1196 if (vm.count("dumpresult")) {
1197 resultfile = new std::ofstream;
1198 resultfile->open(resultFilename.c_str());
1199 if (!(*resultfile)) {
1200 cout
1201 << "ERROR: Couldn't open file '"
1202 << resultFilename
1203 << "' for writing result!"
1204 << endl;
1205 std::exit(-1);
1206 }
1207 }
1208
1209 parse_polarity_type();
1210
1211 //Conflict
1212 if (vm.count("maxdump") && redDumpFname.empty()) {
1213 throw WrongParam("maxdump", "--dumpred <filename> must be activated if issuing --maxdump <size>");
1214 }
1215
1216 parse_restart_type();
1217
1218 if (conf.preprocess == 2) {
1219 if (vm.count("input") == 0) {
1220 cout << "ERROR: When post-processing you must give the solution as the positional argument"
1221 << endl;
1222 std::exit(-1);
1223 }
1224
1225 vector<string> solution = vm["input"].as<vector<string> >();
1226 if (solution.size() > 1) {
1227 cout << "ERROR: When post-processing you must give only the solution as the positional argument."
1228 << endl
1229 << "The saved state must be given as the argument '--savedsate X'"
1230 << endl;
1231 std::exit(-1);
1232 }
1233 conf.solution_file = solution[0];
1234 } else if (vm.count("input")) {
1235 filesToRead = vm["input"].as<vector<string> >();
1236 if (conf.preprocess == 1) {
1237 filesToRead.resize(1);
1238 }
1239
1240 if (!vm.count("sqlitedb")) {
1241 sqlite_filename = filesToRead[0] + ".sqlite";
1242 } else {
1243 sqlite_filename = vm["sqlitedb"].as<string>();
1244 }
1245 fileNamePresent = true;
1246 } else {
1247 fileNamePresent = false;
1248 }
1249
1250 if (conf.preprocess == 1) {
1251 if (vm["input"].as<vector<string> >().size() + vm.count("drat") > 2) {
1252 cout << "ERROR: When preprocessing, you must give the simplified file name as 2nd argument" << endl;
1253 cout << "You gave this many inputs: "
1254 << vm["input"].as<vector<string> >().size()+vm.count("drat")
1255 << endl;
1256
1257 for(const string& s: vm["input"].as<vector<string> >()) {
1258 cout << " --> " << s << endl;
1259 }
1260 if (vm.count("drat")) {
1261 cout << " --> " << vm["drat"].as<string>() << endl;
1262 }
1263 exit(-1);
1264 }
1265 if (vm["input"].as<vector<string> >().size() > 1) {
1266 conf.simplified_cnf = vm["input"].as<vector<string> >()[1];
1267 } else {
1268 try {
1269 conf.simplified_cnf = vm["drat"].as<string>();
1270 } catch (boost::bad_any_cast &e) {
1271 std::cerr
1272 << "ERROR! Did you give a simplified CNF as a 2nd argument? You are preprocessing! So you must (and it must be a string)" << endl;
1273 exit(-1);
1274 }
1275 }
1276 }
1277
1278 if (conf.preprocess == 2) {
1279 if (vm.count("drat")) {
1280 cout << "ERROR: When postprocessing, you must NOT give a 2nd argument" << endl;
1281 std::exit(-1);
1282 }
1283 }
1284
1285 if (conf.preprocess == 0 &&
1286 (vm.count("drat") || conf.simulate_drat)
1287 ) {
1288 handle_drat_option();
1289 }
1290
1291 if (conf.verbosity >= 3) {
1292 cout << "c Outputting solution to console" << endl;
1293 }
1294 }
1295
parseCommandLine()1296 void Main::parseCommandLine()
1297 {
1298 need_clean_exit = 0;
1299
1300 //Reconstruct the command line so we can emit it later if needed
1301 for(int i = 0; i < argc; i++) {
1302 commandLine += string(argv[i]);
1303 if (i+1 < argc) {
1304 commandLine += " ";
1305 }
1306 }
1307
1308 add_supported_options();
1309 p.add("input", 1);
1310 p.add("drat", 1);
1311 all_options.add(help_options_complicated);
1312 all_options.add(hiddenOptions);
1313
1314 help_options_simple
1315 .add(generalOptions)
1316 ;
1317
1318 check_options_correctness();
1319 if (vm.count("version")) {
1320 printVersionInfo();
1321 std::exit(0);
1322 }
1323
1324 try {
1325 manually_parse_some_options();
1326 } catch(WrongParam& wp) {
1327 cerr << "ERROR: " << wp.getMsg() << endl;
1328 exit(-1);
1329 }
1330 }
1331
check_num_threads_sanity(const unsigned thread_num) const1332 void Main::check_num_threads_sanity(const unsigned thread_num) const
1333 {
1334 const unsigned num_cores = std::thread::hardware_concurrency();
1335 if (num_cores == 0) {
1336 //Library doesn't know much, we can't do any checks.
1337 return;
1338 }
1339
1340 if (thread_num > num_cores && conf.verbosity) {
1341 std::cout
1342 << "c WARNING: Number of threads requested is more than the number of"
1343 << " cores reported by the system.\n"
1344 << "c WARNING: This is not a good idea in general. It's best to set the"
1345 << " number of threads to the number of real cores" << endl;
1346 }
1347 }
1348
dump_red_file()1349 void Main::dump_red_file()
1350 {
1351 if (dump_red_fname.length() == 0)
1352 return;
1353
1354 std::ofstream* dumpfile = new std::ofstream;
1355 dumpfile->open(dump_red_fname.c_str());
1356 if (!(*dumpfile)) {
1357 cout
1358 << "ERROR: Couldn't open file '"
1359 << resultFilename
1360 << "' for writing redundant clauses!"
1361 << endl;
1362 std::exit(-1);
1363 }
1364
1365 bool ret = true;
1366 vector<Lit> lits;
1367 solver->start_getting_small_clauses(dump_red_max_len, dump_red_max_glue);
1368 while(ret) {
1369 ret = solver->get_next_small_clause(lits);
1370 if (ret) {
1371 *dumpfile << lits << " " << 0 << endl;
1372 }
1373 }
1374 solver->end_getting_small_clauses();
1375
1376 delete dumpfile;
1377 }
1378
solve()1379 int Main::solve()
1380 {
1381 solver = new SATSolver((void*)&conf);
1382 solverToInterrupt = solver;
1383 if (dratf) {
1384 solver->set_drat(dratf, clause_ID_needed);
1385 }
1386 if (vm.count("maxtime")) {
1387 solver->set_max_time(maxtime);
1388 }
1389 if (vm.count("maxconfl")) {
1390 solver->set_max_confl(maxconfl);
1391 }
1392
1393 check_num_threads_sanity(num_threads);
1394 solver->set_num_threads(num_threads);
1395 if (sql != 0) {
1396 solver->set_sqlite(sqlite_filename);
1397 }
1398
1399 //Print command line used to execute the solver: for options and inputs
1400 if (conf.verbosity) {
1401 printVersionInfo();
1402 cout
1403 << "c Executed with command line: "
1404 << commandLine
1405 << endl;
1406 }
1407
1408 solver->add_sql_tag("commandline", commandLine);
1409 solver->add_sql_tag("verbosity", lexical_cast<string>(conf.verbosity));
1410 solver->add_sql_tag("threads", lexical_cast<string>(num_threads));
1411 solver->add_sql_tag("version", solver->get_version());
1412 solver->add_sql_tag("SHA-revision", solver->get_version_sha1());
1413 solver->add_sql_tag("env", solver->get_compilation_env());
1414 #ifdef __GNUC__
1415 solver->add_sql_tag("compiler", "gcc-" __VERSION__);
1416 #else
1417 solver->add_sql_tag("compiler", "non-gcc");
1418 #endif
1419
1420 //Parse in DIMACS (maybe gzipped) files
1421 //solver->log_to_file("mydump.cnf");
1422 if (conf.preprocess != 2) {
1423 parseInAllFiles(solver);
1424 }
1425 if (!assump_filename.empty()) {
1426 std::ifstream* tmp = new std::ifstream;
1427 tmp->open(assump_filename.c_str());
1428 std::string temp;
1429 while(std::getline(*tmp, temp)) {
1430 //Do with temp
1431 int x = std::stoi(temp);
1432 cout << "Assume: " << x << endl;
1433 Lit l = Lit(std::abs(x)-1, x < 0);
1434 assumps.push_back(l);
1435 }
1436
1437 delete tmp;
1438 }
1439
1440 lbool ret = multi_solutions();
1441
1442 if (conf.preprocess != 1) {
1443 if (ret == l_Undef && conf.verbosity) {
1444 cout
1445 << "c Not finished running -- signal caught or some maximum reached"
1446 << endl;
1447 }
1448 if (conf.verbosity) {
1449 solver->print_stats();
1450 }
1451 if (ret == l_True) {
1452 dump_red_file();
1453 }
1454 }
1455 printResultFunc(&cout, false, ret);
1456 if (resultfile) {
1457 printResultFunc(resultfile, true, ret);
1458 }
1459
1460 return correctReturnValue(ret);
1461 }
1462
multi_solutions()1463 lbool Main::multi_solutions()
1464 {
1465 if (max_nr_of_solutions == 1
1466 && conf.preprocess == 0
1467 && dratf == NULL
1468 && !conf.simulate_drat
1469 && debugLib.empty()
1470 ) {
1471 solver->set_single_run();
1472 }
1473
1474 unsigned long current_nr_of_solutions = 0;
1475 lbool ret = l_True;
1476 while(current_nr_of_solutions < max_nr_of_solutions && ret == l_True) {
1477 ret = solver->solve(&assumps, only_sampling_solution);
1478 current_nr_of_solutions++;
1479
1480 if (ret == l_True && current_nr_of_solutions < max_nr_of_solutions) {
1481 printResultFunc(&cout, false, ret);
1482 if (resultfile) {
1483 printResultFunc(resultfile, true, ret);
1484 }
1485
1486 if (conf.verbosity) {
1487 cout
1488 << "c Number of solutions found until now: "
1489 << std::setw(6) << current_nr_of_solutions
1490 << endl;
1491 }
1492 #ifdef VERBOSE_DEBUG_RECONSTRUCT
1493 solver->print_removed_vars();
1494 #endif
1495
1496 if (!dont_ban_solutions) {
1497 ban_found_solution();
1498 }
1499 }
1500 }
1501 return ret;
1502 }
1503
ban_found_solution()1504 void Main::ban_found_solution()
1505 {
1506 vector<Lit> lits;
1507 if (sampling_vars.empty()) {
1508 //all of the solution
1509 for (uint32_t var = 0; var < solver->nVars(); var++) {
1510 if (solver->get_model()[var] != l_Undef) {
1511 lits.push_back( Lit(var, (solver->get_model()[var] == l_True)? true : false) );
1512 }
1513 }
1514 } else {
1515 for (const uint32_t var: sampling_vars) {
1516 if (solver->get_model()[var] != l_Undef) {
1517 lits.push_back( Lit(var, (solver->get_model()[var] == l_True)? true : false) );
1518 }
1519 }
1520 }
1521 solver->add_clause(lits);
1522 }
1523
1524 ///////////
1525 // Useful helper functions
1526 ///////////
1527
printVersionInfo()1528 void Main::printVersionInfo()
1529 {
1530 cout << solver->get_text_version_info();
1531 }
1532
correctReturnValue(const lbool ret) const1533 int Main::correctReturnValue(const lbool ret) const
1534 {
1535 int retval = -1;
1536 if (ret == l_True) {
1537 retval = 10;
1538 } else if (ret == l_False) {
1539 retval = 20;
1540 } else if (ret == l_Undef) {
1541 retval = 15;
1542 } else {
1543 std::cerr << "Something is very wrong, output is neither l_Undef, nor l_False, nor l_True" << endl;
1544 exit(-1);
1545 }
1546
1547 if (zero_exit_status) {
1548 return 0;
1549 } else {
1550 return retval;
1551 }
1552 }
1553