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