ABC: A System for Sequential Synthesis and Verification
 
Loading...
Searching...
No Matches
cadical_solver.cpp
Go to the documentation of this file.
1#include "global.h"
2
3#include "internal.hpp"
4
6
7/*------------------------------------------------------------------------*/
8
9namespace CaDiCaL {
10
11/*------------------------------------------------------------------------*/
12
13// See corresponding header file 'cadical.hpp' (!) for more information.
14//
15// Again, to avoid confusion, note that, 'cadical.hpp' is the header file of
16// this file 'solver.cpp', since we want to call the application and main
17// file 'cadical.cpp', while at the same time using 'cadical.hpp' as the
18// main header file of the library (and not 'solver.hpp').
19
20/*------------------------------------------------------------------------*/
21#ifdef LOGGING
22
23// Needs to be kept in sync with the color schemes used in 'logging.cpp'.
24//
25#define api_code blue_code // API call color
26#define log_code magenta_code // standard/default logging color
27#define emph_code bright_magenta_code // emphasized logging color
28
29#endif
30/*------------------------------------------------------------------------*/
31
32// Log state transitions.
33
34#define STATE(S) \
35 do { \
36 CADICAL_assert (is_power_of_two (S)); \
37 if (_state == S) \
38 break; \
39 _state = S; \
40 LOG ("API enters state %s" #S "%s", tout.emph_code (), \
41 tout.normal_code ()); \
42 } while (0)
43
44void Solver::transition_to_steady_state () {
45 if (state () == CONFIGURING) {
46 LOG ("API leaves state %sCONFIGURING%s", tout.emph_code (),
47 tout.normal_code ());
48 if (internal->opts.check && internal->opts.checkproof) {
49 internal->check ();
50 }
51 } else if (state () == SATISFIED) {
52 LOG ("API leaves state %sSATISFIED%s", tout.emph_code (),
53 tout.normal_code ());
54 external->reset_assumptions ();
55 external->reset_concluded ();
56 external->reset_constraint ();
57 } else if (state () == UNSATISFIED) {
58 LOG ("API leaves state %sUNSATISFIED%s", tout.emph_code (),
59 tout.normal_code ());
60 external->reset_assumptions ();
61 external->reset_concluded ();
62 external->reset_constraint ();
63 } else if (state() == INCONCLUSIVE) {
64 external->reset_assumptions ();
65 external->reset_concluded ();
66 external->reset_constraint ();
67 }
68 if (state () != STEADY)
69 STATE (STEADY);
70}
71
72/*------------------------------------------------------------------------*/
73#ifdef LOGGING
74/*------------------------------------------------------------------------*/
75
76// The following logging code is useful for debugging mostly (or trying to
77// understand what the solver is actually doing). It needs to be enabled
78// during configuration using the '-l' option for './configure', which
79// forces 'LOGGING' to be defined during compilation. This includes all the
80// logging code, which then still needs to enabled during run-time with the
81// '-l' or 'log' option.
82
83static void log_api_call (Internal *internal, const char *name,
84 const char *suffix) {
85 Logger::log (internal, "API call %s'%s ()'%s %s", tout.api_code (), name,
86 tout.log_code (), suffix);
87}
88
89static void log_api_call (Internal *internal, const char *name, int arg,
90 const char *suffix) {
91 Logger::log (internal, "API call %s'%s (%d)'%s %s", tout.api_code (),
92 name, arg, tout.log_code (), suffix);
93}
94
95static void log_api_call (Internal *internal, const char *name,
96 const char *arg, const char *suffix) {
97 Logger::log (internal, "API call %s'%s (\"%s\")'%s %s", tout.api_code (),
98 name, arg, tout.log_code (), suffix);
99}
100
101static void log_api_call (Internal *internal, const char *name,
102 const char *a1, int a2, const char *s) {
103 Logger::log (internal, "API call %s'%s (\"%s\", %d)'%s %s",
104 tout.api_code (), name, a1, a2, tout.log_code (), s);
105}
106
107/*------------------------------------------------------------------------*/
108
109// We factored out API call begin/end logging and use overloaded functions.
110
111static void log_api_call_begin (Internal *internal, const char *name) {
112 Logger::log_empty_line (internal);
113 log_api_call (internal, name, "started");
114}
115
116static void log_api_call_begin (Internal *internal, const char *name,
117 int arg) {
118 Logger::log_empty_line (internal);
119 log_api_call (internal, name, arg, "started");
120}
121
122static void log_api_call_begin (Internal *internal, const char *name,
123 const char *arg) {
124 Logger::log_empty_line (internal);
125 log_api_call (internal, name, arg, "started");
126}
127
128static void log_api_call_begin (Internal *internal, const char *name,
129 const char *arg1, int arg2) {
130 Logger::log_empty_line (internal);
131 log_api_call (internal, name, arg1, arg2, "started");
132}
133
134/*------------------------------------------------------------------------*/
135
136static void log_api_call_end (Internal *internal, const char *name) {
137 log_api_call (internal, name, "succeeded");
138}
139
140static void log_api_call_end (Internal *internal, const char *name,
141 int lit) {
142 log_api_call (internal, name, lit, "succeeded");
143}
144
145static void log_api_call_end (Internal *internal, const char *name,
146 const char *arg) {
147 Logger::log_empty_line (internal);
148 log_api_call (internal, name, arg, "succeeded");
149}
150
151static void log_api_call_end (Internal *internal, const char *name,
152 const char *arg, bool res) {
153 log_api_call (internal, name, arg, res ? "succeeded" : "failed");
154}
155
156static void log_api_call_end (Internal *internal, const char *name,
157 const char *arg, int val, bool res) {
158 log_api_call (internal, name, arg, val, res ? "succeeded" : "failed");
159}
160
161static void log_api_call_returns (Internal *internal, const char *name,
162 bool res) {
163 log_api_call (internal, name, res ? "returns 'true'" : "returns 'false'");
164}
165
166static void log_api_call_returns (Internal *internal, const char *name,
167 int res) {
168 char fmt[32];
169 snprintf (fmt, sizeof fmt, "returns '%d'", res);
170 log_api_call (internal, name, fmt);
171}
172
173static void log_api_call_returns (Internal *internal, const char *name,
174 int64_t res) {
175 char fmt[32];
176 snprintf (fmt, sizeof fmt, "returns '%" PRId64 "'", res);
177 log_api_call (internal, name, fmt);
178}
179
180static void log_api_call_returns (Internal *internal, const char *name,
181 int lit, int res) {
182 char fmt[32];
183 snprintf (fmt, sizeof fmt, "returns '%d'", res);
184 log_api_call (internal, name, lit, fmt);
185}
186
187static void log_api_call_returns (Internal *internal, const char *name,
188 const char *arg, bool res) {
189 log_api_call (internal, name, arg,
190 res ? "returns 'true'" : "returns 'false'");
191}
192
193static void log_api_call_returns (Internal *internal, const char *name,
194 int lit, bool res) {
195 log_api_call (internal, name, lit,
196 res ? "returns 'true'" : "returns 'false'");
197}
198
199static void log_api_call_returns (Internal *internal, const char *name,
200 const char *arg, const char *res) {
201 Logger::log (internal, "API call %s'%s (\"%s\")'%s returns '%s'",
202 tout.api_code (), name, arg, tout.log_code (),
203 res ? res : "<null>");
204}
205
206static void log_api_call_returns (Internal *internal, const char *name,
207 const char *arg1, int arg2,
208 const char *res) {
209 Logger::log (internal, "API call %s'%s (\"%s\", %d)'%s returns '%s'",
210 tout.api_code (), name, arg1, arg2, tout.log_code (),
211 res ? res : "<null>");
212}
213
214/*------------------------------------------------------------------------*/
215
216#define LOG_API_CALL_BEGIN(...) \
217 do { \
218 if (!internal->opts.log) \
219 break; \
220 log_api_call_begin (internal, __VA_ARGS__); \
221 } while (0)
222
223#define LOG_API_CALL_END(...) \
224 do { \
225 if (!internal->opts.log) \
226 break; \
227 log_api_call_end (internal, __VA_ARGS__); \
228 } while (0)
229
230#define LOG_API_CALL_RETURNS(...) \
231 do { \
232 if (!internal->opts.log) \
233 break; \
234 log_api_call_returns (internal, __VA_ARGS__); \
235 } while (0)
236
237/*------------------------------------------------------------------------*/
238#else // end of 'then' part of 'ifdef LOGGING'
239/*------------------------------------------------------------------------*/
240
241#define LOG_API_CALL_BEGIN(...) \
242 do { \
243 } while (0)
244#define LOG_API_CALL_END(...) \
245 do { \
246 } while (0)
247#define LOG_API_CALL_RETURNS(...) \
248 do { \
249 } while (0)
250
251/*------------------------------------------------------------------------*/
252#endif // end of 'else' part of 'ifdef LOGGING'
253/*------------------------------------------------------------------------*/
254
255/*------------------------------------------------------------------------*/
256#ifndef CADICAL_NTRACING
257/*------------------------------------------------------------------------*/
258
259#define TRACE(...) \
260 do { \
261 /*if ((this == 0)) break; */ /* gcc-12 produces warning */ \
262 if ((internal == 0)) \
263 break; \
264 LOG_API_CALL_BEGIN (__VA_ARGS__); \
265 if (!trace_api_file) \
266 break; \
267 trace_api_call (__VA_ARGS__); \
268 } while (0)
269
270void Solver::trace_api_call (const char *s0) const {
271 CADICAL_assert (trace_api_file);
272 LOG ("TRACE %s", s0);
273 fprintf (trace_api_file, "%s\n", s0);
274 fflush (trace_api_file);
275}
276
277void Solver::trace_api_call (const char *s0, int i1) const {
278 CADICAL_assert (trace_api_file);
279 LOG ("TRACE %s %d", s0, i1);
280 fprintf (trace_api_file, "%s %d\n", s0, i1);
281 fflush (trace_api_file);
282}
283
284void Solver::trace_api_call (const char *s0, const char *s1) const {
285 CADICAL_assert (trace_api_file);
286 LOG ("TRACE %s %s", s0, s1);
287 fprintf (trace_api_file, "%s %s\n", s0, s1);
288 fflush (trace_api_file);
289}
290
291void Solver::trace_api_call (const char *s0, const char *s1, int i2) const {
292 CADICAL_assert (trace_api_file);
293 LOG ("TRACE %s %s %d", s0, s1, i2);
294 fprintf (trace_api_file, "%s %s %d\n", s0, s1, i2);
295 fflush (trace_api_file);
296}
297
298/*------------------------------------------------------------------------*/
299
300// The global 'tracing_api_calls_through_environment_variable_method' flag
301// is used to ensure that only one solver traces to a file. Otherwise the
302// method to use an environment variable to point to the trace file is
303// bogus, since those different solver instances would all write to the same
304// file producing garbage. A more sophisticated solution would use a
305// different mechanism to tell the solver to which file to trace to, but in
306// our experience it is quite convenient to get traces out of applications
307// which use the solver as library by just setting an environment variable
308// without requiring to change any application code.
309//
310static bool tracing_api_calls_through_environment_variable_method;
311
312/*------------------------------------------------------------------------*/
313#else // CADICAL_NTRACING
314/*------------------------------------------------------------------------*/
315
316#define TRACE(...) \
317 do { \
318 } while (0)
319
320/*------------------------------------------------------------------------*/
321#endif
322/*------------------------------------------------------------------------*/
323
324static bool tracing_nb_lidrup_env_var_method = false;
325
327
328#ifndef CADICAL_NTRACING
329 const char *path = getenv ("CADICAL_API_TRACE");
330 if (!path)
331 path = getenv ("CADICALAPITRACE");
332 if (path) {
333 if (tracing_api_calls_through_environment_variable_method)
334 FATAL ("can not trace API calls of two solver instances "
335 "using environment variable 'CADICAL_API_TRACE'");
336 if (!(trace_api_file = fopen (path, "w")))
337 FATAL ("failed to open file '%s' to trace API calls "
338 "using environment variable 'CADICAL_API_TRACE'",
339 path);
340 close_trace_api_file = true;
341 tracing_api_calls_through_environment_variable_method = true;
342 } else {
343 tracing_api_calls_through_environment_variable_method = false;
344 close_trace_api_file = false;
345 trace_api_file = 0;
346 }
347#endif
348
349 adding_clause = false;
350 adding_constraint = false;
351 _state = INITIALIZING;
352 internal = new Internal ();
353 DeferDeletePtr<Internal> delete_internal (internal);
354 TRACE ("init");
355 external = new External (internal);
356 DeferDeletePtr<External> delete_external (external);
358#ifndef CADICAL_NTRACING
359 if (tracing_api_calls_through_environment_variable_method)
360 message ("tracing API calls to '%s'", path);
361#endif
362
363 const char *lidrup_path = getenv ("CADICAL_LIDRUP_TRACE");
364 if (!lidrup_path)
365 lidrup_path = getenv ("CADICALLIDRUPTRACE");
366 if (lidrup_path) {
367
368 // if (tracing_nb_lidrup_env_var_method)
369 // FATAL ("can not trace LIDRUP of two solver instances "
370 // "using environment variable 'CADICAL_LIDRUP_TRACE'");
371 // Here we use the solver interface to setup non-binary IDRUP tracing to
372 // the defined file. Options set by the user can and will overwrite
373 // these settings if neeed be.
374 set ("lidrup", 1);
375 set ("binary", 0);
376 trace_proof (lidrup_path);
377 tracing_nb_lidrup_env_var_method = true;
378 } else {
379 tracing_nb_lidrup_env_var_method = false;
380 }
381
382 delete_internal.release ();
383 delete_external.release ();
384}
385
387
388 TRACE ("reset");
390 STATE (DELETING);
391
392 tracing_nb_lidrup_env_var_method = false;
393
394#ifdef LOGGING
395 //
396 // After deleting 'internal' logging does not work anymore.
397 //
398 bool logging = internal->opts.log;
399 int level = internal->level;
400 string prefix = internal->prefix;
401#endif
402
403 delete internal;
404 delete external;
405
406#ifndef CADICAL_NTRACING
407 if (close_trace_api_file) {
408 close_trace_api_file = false;
409 CADICAL_assert (trace_api_file);
410 CADICAL_assert (tracing_api_calls_through_environment_variable_method);
411 fclose (trace_api_file);
412 tracing_api_calls_through_environment_variable_method = false;
413 }
414#endif
415
416#ifdef LOGGING
417 //
418 // Need to log success of this API call manually.
419 //
420 if (logging) {
421 printf ("%s%sLOG %s%d%s API call %s'reset ()'%s succeeded%s\n",
422 prefix.c_str (), tout.log_code (), tout.emph_code (), level,
423 tout.log_code (), tout.api_code (), tout.log_code (),
424 tout.normal_code ());
425 fflush (stdout);
426 }
427#endif
428}
429
430/*------------------------------------------------------------------------*/
431
433 TRACE ("vars");
435 int res = external->max_var;
436 LOG_API_CALL_RETURNS ("vars", res);
437 return res;
438}
439
440void Solver::reserve (int min_max_var) {
441 TRACE ("reserve", min_max_var);
443 transition_to_steady_state ();
444 external->reset_extended ();
445 external->init (min_max_var);
446 LOG_API_CALL_END ("reserve", min_max_var);
447}
448
449int Solver::reserve_difference (int number_of_vars) {
450 TRACE ("reserve_difference", number_of_vars);
452 transition_to_steady_state ();
453 external->reset_extended ();
454 int new_max_var = external->max_var + number_of_vars;
455 external->init (new_max_var);
456 LOG_API_CALL_END ("reserve_difference", number_of_vars);
457 return new_max_var;
458}
459
460/*------------------------------------------------------------------------*/
461#ifndef CADICAL_NTRACING
462
463void Solver::trace_api_calls (FILE *file) {
464 LOG_API_CALL_BEGIN ("trace_api_calls");
466 REQUIRE (file != 0, "invalid zero file argument");
467 REQUIRE (!tracing_api_calls_through_environment_variable_method,
468 "already tracing API calls "
469 "using environment variable 'CADICAL_API_TRACE'");
470 REQUIRE (!trace_api_file, "called twice");
471 trace_api_file = file;
472 LOG_API_CALL_END ("trace_api_calls");
473 trace_api_call ("init");
474}
475
476#endif
477/*------------------------------------------------------------------------*/
478
479bool Solver::is_valid_option (const char *name) {
480 return Options::has (name);
481}
482
486
487bool Solver::is_valid_long_option (const char *arg) {
488 string name;
489 int tmp;
490 return Options::parse_long_option (arg, name, tmp);
491}
492
493int Solver::get (const char *arg) {
495 return internal->opts.get (arg);
496}
497
498bool Solver::set (const char *arg, int val) {
499 TRACE ("set", arg, val);
501 if (strcmp (arg, "log") && strcmp (arg, "quiet") &&
502 strcmp (arg, "report") && strcmp (arg, "verbose")) {
503 REQUIRE (
504 state () == CONFIGURING,
505 "can only set option 'set (\"%s\", %d)' right after initialization",
506 arg, val);
507 }
508 bool res = internal->opts.set (arg, val);
509 LOG_API_CALL_END ("set", arg, val, res);
510
511 return res;
512}
513
514bool Solver::set_long_option (const char *arg) {
515 LOG_API_CALL_BEGIN ("set", arg);
518 "can only set option '%s' right after initialization", arg);
519 bool res;
520 if (arg[0] != '-' || arg[1] != '-')
521 res = false;
522 else {
523 int val;
524 string name;
525 res = Options::parse_long_option (arg, name, val);
526 if (res)
527 set (name.c_str (), val);
528 }
529 LOG_API_CALL_END ("set", arg, res);
530 return res;
531}
532
533void Solver::optimize (int arg) {
534 LOG_API_CALL_BEGIN ("optimize", arg);
536 internal->opts.optimize (arg);
537 LOG_API_CALL_END ("optimize", arg);
538}
539
540bool Solver::limit (const char *arg, int val) {
541 TRACE ("limit", arg, val);
543 bool res = internal->limit (arg, val);
544 LOG_API_CALL_END ("limit", arg, val, res);
545 return res;
546}
547
548bool Solver::is_valid_limit (const char *arg) {
549 return Internal::is_valid_limit (arg);
550}
551
552void Solver::prefix (const char *str) {
553 LOG_API_CALL_BEGIN ("prefix", str);
555 internal->prefix = str;
556 LOG_API_CALL_END ("prefix", str);
557}
558
560 return Config::has (name);
561}
562
563bool Solver::configure (const char *name) {
564 TRACE ("configure", name);
565 LOG_API_CALL_BEGIN ("configure", name);
568 "can only set configuration '%s' right after initialization",
569 name);
570 bool res = Config::set (internal->opts, name);
571 LOG_API_CALL_END ("configure", name, res);
572 return res;
573}
574
575/*===== IPASIR BEGIN =====================================================*/
576
577void Solver::add (int lit) {
578 TRACE ("add", lit);
580 if (lit)
582 transition_to_steady_state ();
583 external->add (lit);
584 adding_clause = lit;
585 if (adding_clause)
586 STATE (ADDING);
587 else if (!adding_constraint)
588 STATE (STEADY);
589 LOG_API_CALL_END ("add", lit);
590}
591
592void Solver::clause (int a) {
594 add (a), add (0);
595}
596
597void Solver::clause (int a, int b) {
600 add (a), add (b), add (0);
601}
602
603void Solver::clause (int a, int b, int c) {
607 add (a), add (b), add (c), add (0);
608}
609
610void Solver::clause (int a, int b, int c, int d) {
615 add (a), add (b), add (c), add (d), add (0);
616}
617
618void Solver::clause (int a, int b, int c, int d, int e) {
624 add (a), add (b), add (c), add (d), add (e), add (0);
625}
626
627void Solver::clause (const int *lits, size_t size) {
628 REQUIRE (!size || lits,
629 "first argument 'lits' zero while second argument 'size' not");
630 const int *end = lits + size;
631 for (const int *p = lits; p != end; p++) {
632 const int lit = *p;
634 add (lit);
635 }
636 add (0);
637}
638
639void Solver::clause (const std::vector<int> &lits) {
640 for (auto lit : lits) {
642 add (lit);
643 }
644 add (0);
645}
646
647bool Solver::inconsistent () { return internal->unsat; }
648
650 TRACE ("constrain", lit);
652 if (lit)
654 transition_to_steady_state ();
655 external->constrain (lit);
656 adding_constraint = lit;
657 if (adding_constraint)
658 STATE (ADDING);
659 else if (!adding_clause)
660 STATE (STEADY);
661 LOG_API_CALL_END ("constrain", lit);
662}
663
664void Solver::assume (int lit) {
665 TRACE ("assume", lit);
668 transition_to_steady_state ();
669 external->assume (lit);
670 LOG_API_CALL_END ("assume", lit);
671}
672
674 TRACE ("lookahead");
676 int lit = external->lookahead ();
677 TRACE ("lookahead");
678 return lit;
679}
680
682 TRACE ("lookahead_cubes");
684 auto cubes = external->generate_cubes (depth, min_depth);
685 TRACE ("lookahead_cubes");
686
687 CubesWithStatus cubes2;
688 cubes2.status = cubes.status;
689 cubes2.cubes = cubes.cubes;
690 return cubes2;
691}
692
694 TRACE ("reset_assumptions");
696 transition_to_steady_state ();
697 external->reset_assumptions ();
698 external->reset_concluded ();
699 LOG_API_CALL_END ("reset_assumptions");
700}
701
703 TRACE ("reset_constraint");
705 transition_to_steady_state ();
706 external->reset_constraint ();
707 external->reset_concluded ();
708 LOG_API_CALL_END ("reset_constraint");
709}
710
711/*------------------------------------------------------------------------*/
712
714 TRACE ("propagate_assumptions");
716 transition_to_steady_state ();
717 const int res = external->propagate_assumptions ();
718 if (tracing_nb_lidrup_env_var_method)
719 flush_proof_trace (true);
720 LOG_API_CALL_RETURNS ("propagate_assumptions", res);
721 if (res == 10)
723 else if (res == 20)
725 else
727 return res;
728}
729
730void Solver::implied (std::vector<int> &entrailed) {
731 TRACE ("implied");
734 "can only get implied literals only in unknown state");
735 external->conclude_unknown ();
736 external->implied (entrailed);
737 if (tracing_nb_lidrup_env_var_method)
738 flush_proof_trace (true);
739 LOG_API_CALL_RETURNS ("implied", (int) entrailed.size ());
740}
741
742/*------------------------------------------------------------------------*/
743
744int Solver::call_external_solve_and_check_results (bool preprocess_only) {
745 transition_to_steady_state ();
747 STATE (SOLVING);
748 const int res = external->solve (preprocess_only);
749 if (res == 10)
751 else if (res == 20)
753 else
755#if 0 // EXPENSIVE ALTERNATIVE ASSUMPTION CHECKING
756 // This checks that the set of failed assumptions form a core using the
757 // external 'copy (...)' function to copy the solver, which can be trusted
758 // less, since it involves copying the extension stack too. The
759 // 'External::check_assumptions_failing' is a better alternative and can
760 // be enabled by options too. We keep this code though to have an
761 // alternative failed assumption checking available for debugging.
762 //
763 if (res == 20 && !external->assumptions.empty ()) {
764 Solver checker;
765 // checking restored clauses does not work (because the clauses are not added)
766 checker.set("checkproof", 1);
767 checker.set("lrat", 0);
768 checker.prefix ("checker ");
769 copy (checker);
770 checker.set("log", 1);
771 for (const auto & lit : external->assumptions)
772 if (failed (lit))
773 checker.add (lit), checker.add (0);
774 if (checker.solve () != 20)
775 FATAL ("copying assumption checker failed");
776 }
777#endif
778 if (!res) {
779 external->reset_assumptions ();
780 external->reset_constraint ();
781 external->reset_concluded ();
782 }
783 return res;
784}
785
787 TRACE ("solve");
789 const int res = call_external_solve_and_check_results (false);
790 LOG_API_CALL_RETURNS ("solve", res);
791 if (tracing_nb_lidrup_env_var_method)
792 flush_proof_trace (true);
793 return res;
794}
795
796int Solver::simplify (int rounds) {
797 TRACE ("simplify", rounds);
799 REQUIRE (rounds >= 0, "negative number of simplification rounds '%d'",
800 rounds);
801 internal->limit ("preprocessing", rounds);
802 const int res = call_external_solve_and_check_results (true);
803 LOG_API_CALL_RETURNS ("simplify", rounds, res);
804 return res;
805}
806
807/*------------------------------------------------------------------------*/
808
809int Solver::val (int lit) {
810 TRACE ("val", lit);
813 REQUIRE (state () == SATISFIED, "can only get value in satisfied state");
814 if (!external->extended)
815 external->extend ();
816 external->conclude_sat ();
817 int res = external->ival (lit);
818 LOG_API_CALL_RETURNS ("val", lit, res);
820 CADICAL_assert (res == lit || res == -lit);
821 return res;
822}
823
824bool Solver::flip (int lit) {
825 TRACE ("flip", lit);
828 REQUIRE (state () == SATISFIED, "can only flip value in satisfied state");
829 REQUIRE (!external->propagator,
830 "can only flip when no external propagator is present");
831 bool res = external->flip (lit);
832 LOG_API_CALL_RETURNS ("flip", lit, res);
834 return res;
835}
836
838 TRACE ("flippable", lit);
841 REQUIRE (state () == SATISFIED, "can only flip value in satisfied state");
842 REQUIRE (!external->propagator,
843 "can only flip when no external propagator is present");
844 bool res = external->flippable (lit);
845 LOG_API_CALL_RETURNS ("flippable", lit, res);
847 return res;
848}
849
850bool Solver::failed (int lit) {
851 TRACE ("failed", lit);
855 "can only get failed assumptions in unsatisfied state");
856 bool res = external->failed (lit);
857 LOG_API_CALL_RETURNS ("failed", lit, res);
859 return res;
860}
861
863 TRACE ("constraint_failed");
866 "can only determine if constraint failed in unsatisfied state");
867 bool res = external->failed_constraint ();
868 LOG_API_CALL_RETURNS ("constraint_failed", res);
870 return res;
871}
872
873int Solver::fixed (int lit) const {
874 TRACE ("fixed", lit);
877 int res = external->fixed (lit);
878 LOG_API_CALL_RETURNS ("fixed", lit, res);
879 return res;
880}
881
882void Solver::phase (int lit) {
883 TRACE ("phase", lit);
886 external->phase (lit);
887 LOG_API_CALL_END ("phase", lit);
888}
889
891 TRACE ("unphase", lit);
894 external->unphase (lit);
895 LOG_API_CALL_END ("unphase", lit);
896}
897
898/*------------------------------------------------------------------------*/
899
901 LOG_API_CALL_BEGIN ("terminate");
903 external->terminate ();
904 LOG_API_CALL_END ("terminate");
905}
906
908 LOG_API_CALL_BEGIN ("connect_terminator");
910 REQUIRE (terminator, "can not connect zero terminator");
911#ifdef LOGGING
912 if (external->terminator)
913 LOG ("connecting new terminator (disconnecting previous one)");
914 else
915 LOG ("connecting new terminator (no previous one)");
916#endif
917 external->terminator = terminator;
918 LOG_API_CALL_END ("connect_terminator");
919}
920
922 LOG_API_CALL_BEGIN ("disconnect_terminator");
924#ifdef LOGGING
925 if (external->terminator)
926 LOG ("disconnecting previous terminator");
927 else
928 LOG ("ignoring to disconnect terminator (no previous one)");
929#endif
930 external->terminator = 0;
931 LOG_API_CALL_END ("disconnect_terminator");
932}
933
934/*------------------------------------------------------------------------*/
935
937 LOG_API_CALL_BEGIN ("connect_learner");
939 REQUIRE (learner, "can not connect zero learner");
940#ifdef LOGGING
941 if (external->learner)
942 LOG ("connecting new learner (disconnecting previous one)");
943 else
944 LOG ("connecting new learner (no previous one)");
945#endif
946 external->learner = learner;
947 LOG_API_CALL_END ("connect_learner");
948}
949
951 LOG_API_CALL_BEGIN ("disconnect_learner");
953#ifdef LOGGING
954 if (external->learner)
955 LOG ("disconnecting previous learner");
956 else
957 LOG ("ignoring to disconnect learner (no previous one)");
958#endif
959 external->learner = 0;
960 LOG_API_CALL_END ("disconnect_learner");
961}
962
963/*===== IPASIR END =======================================================*/
964
966 FixedAssignmentListener *fixed_listener) {
967 LOG_API_CALL_BEGIN ("connect_fixed_listener");
969 REQUIRE (fixed_listener, "can not connect zero fixed listener");
970
971#ifdef LOGGING
972 if (external->fixed_listener)
973 LOG ("connecting new listener of fixed assignments (disconnecting "
974 "previous one)");
975 else
976 LOG ("connecting new listener of fixed assigments (no previous one)");
977#endif
978 if (external->fixed_listener)
980 external->fixed_listener = fixed_listener;
981 // Listeners are treated as real-time listeners, thus previously found
982 // fixed assignments are not sent out (would be rather expensive to
983 // recover it retrospect, see external_propagate.cpp/get_fixed_literals ()
984 // function).
985 LOG_API_CALL_END ("connect_fixed_listener");
986}
987
989 LOG_API_CALL_BEGIN ("disconnect_fixed_listener");
991#ifdef LOGGING
992 if (external->fixed_listener)
993 LOG ("disconnecting previous listener of fixed assignments");
994 else
995 LOG ("ignoring to disconnect listener of fixed assignments (no "
996 "previous one)");
997#endif
998 external->fixed_listener = 0;
999 LOG_API_CALL_END ("disconnect_fixed_listener");
1000}
1001
1002/*===== IPASIR-UP BEGIN ==================================================*/
1003
1005 LOG_API_CALL_BEGIN ("connect_external_propagator");
1007 REQUIRE (propagator, "can not connect zero propagator");
1008#ifdef LOGGING
1009 if (external->propagator)
1010 LOG ("connecting new external propagator (disconnecting previous one)");
1011 else
1012 LOG ("connecting new external propagator (no previous one)");
1013#endif
1014 if (external->propagator)
1016
1017 external->propagator = propagator;
1018 internal->connect_propagator ();
1019 internal->external_prop = true;
1020 internal->external_prop_is_lazy = propagator->is_lazy;
1021 LOG_API_CALL_END ("connect_external_propagator");
1022}
1023
1025 LOG_API_CALL_BEGIN ("disconnect_external_propagator");
1027
1028#ifdef LOGGING
1029 if (external->propagator)
1030 LOG ("disconnecting previous external propagator");
1031 else
1032 LOG ("ignoring to disconnect external propagator (no previous one)");
1033#endif
1034 if (external->propagator)
1035 external->reset_observed_vars ();
1036
1037 external->propagator = 0;
1038 internal->set_tainted_literal ();
1039 internal->external_prop = false;
1040 internal->external_prop_is_lazy = true;
1041 LOG_API_CALL_END ("disconnect_external_propagator");
1042}
1043
1045 TRACE ("observe", idx);
1047 REQUIRE_VALID_LIT (idx);
1048 external->add_observed_var (idx);
1049 LOG_API_CALL_END ("observe", idx);
1050}
1051
1053 TRACE ("unobserve", idx);
1055 REQUIRE_VALID_LIT (idx);
1056 external->remove_observed_var (idx);
1057 LOG_API_CALL_END ("unobserve", idx);
1058}
1059
1061 TRACE ("reset_observed_vars");
1063 external->reset_observed_vars ();
1064 LOG_API_CALL_END ("reset_observed_vars");
1065}
1066
1067/*===== IPASIR-UP END ====================================================*/
1068
1069int Solver::active () const {
1070 TRACE ("active");
1072 int res = internal->active ();
1073 LOG_API_CALL_RETURNS ("active", res);
1074 return res;
1075}
1076
1077int64_t Solver::redundant () const {
1078 TRACE ("redundant");
1080 int64_t res = internal->redundant ();
1081 LOG_API_CALL_RETURNS ("redundant", res);
1082 return res;
1083}
1084
1085int64_t Solver::irredundant () const {
1086 TRACE ("irredundant");
1088 int64_t res = internal->irredundant ();
1089 LOG_API_CALL_RETURNS ("irredundant", res);
1090 return res;
1091}
1092
1093/*------------------------------------------------------------------------*/
1094
1096 TRACE ("freeze", lit);
1099 external->freeze (lit);
1100 LOG_API_CALL_END ("freeze", lit);
1101}
1102
1103void Solver::melt (int lit) {
1104 TRACE ("melt", lit);
1107 REQUIRE (external->frozen (lit),
1108 "can not melt completely melted literal '%d'", lit);
1109 external->melt (lit);
1110 LOG_API_CALL_END ("melt", lit);
1111}
1112
1113bool Solver::frozen (int lit) const {
1114 TRACE ("frozen", lit);
1117 bool res = external->frozen (lit);
1118 LOG_API_CALL_RETURNS ("frozen", lit, res);
1119 return res;
1120}
1121
1122/*------------------------------------------------------------------------*/
1123
1124bool Solver::trace_proof (FILE *external_file, const char *name) {
1125 TRACE ("trace_proof", name);
1127 REQUIRE (
1128 state () == CONFIGURING,
1129 "can only start proof tracing to '%s' right after initialization",
1130 name);
1131 File *internal_file = File::write (internal, external_file, name);
1132 CADICAL_assert (internal_file);
1133 internal->trace (internal_file);
1134 LOG_API_CALL_RETURNS ("trace_proof", name, true);
1135 return true;
1136}
1137
1138bool Solver::trace_proof (const char *path) {
1139 TRACE ("trace_proof", path);
1141 REQUIRE (
1142 state () == CONFIGURING,
1143 "can only start proof tracing to '%s' right after initialization",
1144 path);
1145 File *internal_file = File::write (internal, path);
1146 bool res = (internal_file != 0);
1147 internal->trace (internal_file);
1148 LOG_API_CALL_RETURNS ("trace_proof", path, res);
1149 return res;
1150}
1151
1152void Solver::flush_proof_trace (bool print_statistics_unless_quiet) {
1153 TRACE ("flush_proof_trace");
1155 REQUIRE (!internal->file_tracers.empty (), "proof is not traced");
1156 REQUIRE (!internal->file_tracers.back ()->closed (),
1157 "proof trace already closed");
1158 internal->flush_trace (print_statistics_unless_quiet);
1159 LOG_API_CALL_END ("flush_proof_trace");
1160}
1161
1162void Solver::close_proof_trace (bool print_statistics_unless_quiet) {
1163 TRACE ("close_proof_trace");
1165 REQUIRE (!internal->file_tracers.empty (), "proof is not traced");
1166 REQUIRE (!internal->file_tracers.back ()->closed (),
1167 "proof trace already closed");
1168 internal->close_trace (print_statistics_unless_quiet);
1169 LOG_API_CALL_END ("close_proof_trace");
1170}
1171
1172/*------------------------------------------------------------------------*/
1173
1174void Solver::connect_proof_tracer (Tracer *tracer, bool antecedents,
1175 bool finalize_clauses) {
1176 LOG_API_CALL_BEGIN ("connect proof tracer");
1178 REQUIRE (state () == CONFIGURING,
1179 "can only start proof tracing to right after initialization");
1180 REQUIRE (tracer, "can not connect zero tracer");
1181 internal->connect_proof_tracer (tracer, antecedents, finalize_clauses);
1182 LOG_API_CALL_END ("connect proof tracer");
1183}
1184
1185void Solver::connect_proof_tracer (InternalTracer *tracer, bool antecedents,
1186 bool finalize_clauses) {
1187 LOG_API_CALL_BEGIN ("connect proof tracer");
1189 REQUIRE (state () == CONFIGURING,
1190 "can only start proof tracing to right after initialization");
1191 REQUIRE (tracer, "can not connect zero tracer");
1192 internal->connect_proof_tracer (tracer, antecedents, finalize_clauses);
1193 LOG_API_CALL_END ("connect proof tracer");
1194}
1195
1196void Solver::connect_proof_tracer (StatTracer *tracer, bool antecedents,
1197 bool finalize_clauses) {
1198 LOG_API_CALL_BEGIN ("connect proof tracer with stats");
1200 REQUIRE (state () == CONFIGURING,
1201 "can only start proof tracing to right after initialization");
1202 REQUIRE (tracer, "can not connect zero tracer");
1203 internal->connect_proof_tracer (tracer, antecedents, finalize_clauses);
1204 LOG_API_CALL_END ("connect proof tracer with stats");
1205}
1206
1207void Solver::connect_proof_tracer (FileTracer *tracer, bool antecedents,
1208 bool finalize_clauses) {
1209 LOG_API_CALL_BEGIN ("connect proof tracer with file");
1211 REQUIRE (state () == CONFIGURING,
1212 "can only start proof tracing right after initialization");
1213 REQUIRE (tracer, "can not connect zero tracer");
1214 internal->connect_proof_tracer (tracer, antecedents, finalize_clauses);
1215 LOG_API_CALL_END ("connect proof tracer with file");
1216}
1217
1219 LOG_API_CALL_BEGIN ("disconnect proof tracer");
1221 REQUIRE (tracer, "can not disconnect zero tracer");
1222 bool res = internal->disconnect_proof_tracer (tracer);
1223 LOG_API_CALL_RETURNS ("connect proof tracer", res);
1224 return res;
1225}
1226
1228 LOG_API_CALL_BEGIN ("disconnect proof tracer");
1230 REQUIRE (tracer, "can not disconnect zero tracer");
1231 bool res = internal->disconnect_proof_tracer (tracer);
1232 LOG_API_CALL_RETURNS ("disconnect proof tracer", res);
1233 return res;
1234}
1235
1237 LOG_API_CALL_BEGIN ("disconnect proof tracer");
1239 REQUIRE (tracer, "can not disconnect zero tracer");
1240 bool res = internal->disconnect_proof_tracer (tracer);
1241 LOG_API_CALL_RETURNS ("disconnect proof tracer", res);
1242 return res;
1243}
1244
1245/*------------------------------------------------------------------------*/
1246
1248 TRACE ("conclude");
1250 REQUIRE (state () == UNSATISFIED || state () == SATISFIED ||
1251 state () == INCONCLUSIVE,
1252 "can only conclude in satisfied, unsatisfied or inconclusive state");
1253 if (state () == UNSATISFIED)
1254 internal->conclude_unsat ();
1255 else if (state () == SATISFIED)
1256 external->conclude_sat ();
1257 else if (state () == INCONCLUSIVE)
1258 external->conclude_unknown ();
1260 state () == INCONCLUSIVE);
1261 LOG_API_CALL_END ("conclude");
1262}
1263
1264/*------------------------------------------------------------------------*/
1265
1266void Solver::build (FILE *file, const char *prefix) {
1267
1268 CADICAL_assert (file == stdout || file == stderr);
1269
1270 Terminal *terminal;
1271
1272 if (file == stdout)
1273 terminal = &tout;
1274 else if (file == stderr)
1275 terminal = &terr;
1276 else
1277 terminal = 0;
1278
1279 const char *v = CaDiCaL::version ();
1280 const char *i = identifier ();
1281 const char *c = compiler ();
1282 const char *b = date ();
1283 const char *f = flags ();
1284
1285 CADICAL_assert (v);
1286
1287 fputs (prefix, file);
1288 if (terminal)
1289 terminal->magenta ();
1290 fputs ("Version ", file);
1291 if (terminal)
1292 terminal->normal ();
1293 fputs (v, file);
1294 if (i) {
1295 if (terminal)
1296 terminal->magenta ();
1297 fputc (' ', file);
1298 fputs (i, file);
1299 if (terminal)
1300 terminal->normal ();
1301 }
1302 fputc ('\n', file);
1303
1304 if (c) {
1305 fputs (prefix, file);
1306 if (terminal)
1307 terminal->magenta ();
1308 fputs (c, file);
1309 if (f) {
1310 fputc (' ', file);
1311 fputs (f, file);
1312 }
1313 if (terminal)
1314 terminal->normal ();
1315 fputc ('\n', file);
1316 }
1317
1318 if (b) {
1319 fputs (prefix, file);
1320 if (terminal)
1321 terminal->magenta ();
1322 fputs (b, file);
1323 if (terminal)
1324 terminal->normal ();
1325 fputc ('\n', file);
1326 }
1327
1328 fflush (file);
1329}
1330
1331const char *Solver::version () { return CaDiCaL::version (); }
1332
1333const char *Solver::signature () { return CaDiCaL::signature (); }
1334
1337 internal->opts.print ();
1338}
1339
1341
1343
1345 if (state () == DELETING)
1346 return;
1347 TRACE ("stats");
1349 internal->print_statistics ();
1350 LOG_API_CALL_END ("stats");
1351}
1352
1354 if (state () == DELETING)
1355 return;
1356 TRACE ("resources");
1358 internal->print_resource_usage ();
1359 LOG_API_CALL_END ("resources");
1360}
1361
1362/*------------------------------------------------------------------------*/
1363
1364const char *Solver::read_dimacs (File *file, int &vars, int strict,
1365 bool *incremental, vector<int> *cubes) {
1367 REQUIRE (state () == CONFIGURING,
1368 "can only read DIMACS file right after initialization");
1369 Parser *parser = new Parser (this, file, incremental, cubes);
1370 const char *err = parser->parse_dimacs (vars, strict);
1371 delete parser;
1372 return err;
1373}
1374
1375const char *Solver::read_dimacs (FILE *external_file, const char *name,
1376 int &vars, int strict) {
1377 LOG_API_CALL_BEGIN ("read_dimacs", name);
1379 REQUIRE (state () == CONFIGURING,
1380 "can only read DIMACS file right after initialization");
1381 File *file = File::read (internal, external_file, name);
1383 const char *err = read_dimacs (file, vars, strict);
1384 delete file;
1385 LOG_API_CALL_RETURNS ("read_dimacs", name, err);
1386 return err;
1387}
1388
1389const char *Solver::read_dimacs (const char *path, int &vars, int strict) {
1390 LOG_API_CALL_BEGIN ("read_dimacs", path);
1392 REQUIRE (state () == CONFIGURING,
1393 "can only read DIMACS file right after initialization");
1394 File *file = File::read (internal, path);
1395 if (!file)
1396 return internal->error_message.init ("failed to read DIMACS file '%s'",
1397 path);
1398 const char *err = read_dimacs (file, vars, strict);
1399 delete file;
1400 LOG_API_CALL_RETURNS ("read_dimacs", path, err);
1401 return err;
1402}
1403
1404const char *Solver::read_dimacs (FILE *external_file, const char *name,
1405 int &vars, int strict, bool &incremental,
1406 vector<int> &cubes) {
1407 LOG_API_CALL_BEGIN ("read_dimacs", name);
1409 REQUIRE (state () == CONFIGURING,
1410 "can only read DIMACS file right after initialization");
1411 File *file = File::read (internal, external_file, name);
1413 const char *err = read_dimacs (file, vars, strict, &incremental, &cubes);
1414 delete file;
1415 LOG_API_CALL_RETURNS ("read_dimacs", name, err);
1416 return err;
1417}
1418
1419const char *Solver::read_dimacs (const char *path, int &vars, int strict,
1420 bool &incremental, vector<int> &cubes) {
1421 LOG_API_CALL_BEGIN ("read_dimacs", path);
1423 REQUIRE (state () == CONFIGURING,
1424 "can only read DIMACS file right after initialization");
1425 File *file = File::read (internal, path);
1426 if (!file)
1427 return internal->error_message.init ("failed to read DIMACS file '%s'",
1428 path);
1429 const char *err = read_dimacs (file, vars, strict, &incremental, &cubes);
1430 delete file;
1431 LOG_API_CALL_RETURNS ("read_dimacs", path, err);
1432 return err;
1433}
1434
1435const char *Solver::read_solution (const char *path) {
1436 LOG_API_CALL_BEGIN ("solution", path);
1438 File *file = File::read (internal, path);
1439 if (!file)
1440 return internal->error_message.init (
1441 "failed to read solution file '%s'", path);
1442 Parser *parser = new Parser (this, file, 0, 0);
1443 const char *err = parser->parse_solution ();
1444 delete parser;
1445 delete file;
1446 if (!err)
1447 external->check_assignment (&External::sol);
1448 LOG_API_CALL_RETURNS ("read_solution", path, err);
1449 return err;
1450}
1451
1452/*------------------------------------------------------------------------*/
1453
1454void Solver::dump_cnf () {
1455 TRACE ("dump");
1457 internal->dump ();
1458 LOG_API_CALL_END ("dump");
1459}
1460
1461/*------------------------------------------------------------------------*/
1462
1463ExternalPropagator *Solver::get_propagator () {
1464 return external->propagator;
1465}
1466
1467bool Solver::observed (int lit) {
1468 TRACE ("observed", lit);
1471 bool res = external->observed (lit);
1472 LOG_API_CALL_RETURNS ("observed", lit, res);
1473 return res;
1474}
1475
1476bool Solver::is_witness (int lit) {
1477 TRACE ("is_witness", lit);
1480 bool res = external->is_witness (lit);
1481 LOG_API_CALL_RETURNS ("is_witness", lit, res);
1482 return res;
1483}
1484
1486 TRACE ("is_decision", lit);
1489 bool res = external->is_decision (lit);
1490 LOG_API_CALL_RETURNS ("is_decision", lit, res);
1491 return res;
1492}
1493
1494void Solver::force_backtrack (size_t new_level) {
1495 TRACE ("force_backtrack", new_level);
1497 external->force_backtrack (new_level);
1498}
1499
1500/*------------------------------------------------------------------------*/
1501
1503 LOG_API_CALL_BEGIN ("traverse_clauses");
1505 bool res = external->traverse_all_frozen_units_as_clauses (it) &&
1506 internal->traverse_clauses (it) &&
1507 internal->traverse_constraint (it);
1508 LOG_API_CALL_RETURNS ("traverse_clauses", res);
1509 return res;
1510}
1511
1513 LOG_API_CALL_BEGIN ("traverse_witnesses_backward");
1515 bool res = external->traverse_all_non_frozen_units_as_witnesses (it) &&
1516 external->traverse_witnesses_backward (it);
1517 LOG_API_CALL_RETURNS ("traverse_witnesses_backward", res);
1518 return res;
1519}
1520
1522 LOG_API_CALL_BEGIN ("traverse_witnesses_forward");
1524 bool res = external->traverse_witnesses_forward (it) &&
1525 external->traverse_all_non_frozen_units_as_witnesses (it);
1526 LOG_API_CALL_RETURNS ("traverse_witnesses_forward", res);
1527 return res;
1528}
1529
1530/*------------------------------------------------------------------------*/
1531
1533public:
1534 int vars;
1535 int64_t clauses;
1536 ClauseCounter () : vars (0), clauses (0) {}
1537 bool clause (const vector<int> &c) {
1538 for (const auto &lit : c) {
1539 CADICAL_assert (lit != INT_MIN);
1540 int idx = abs (lit);
1541 if (idx > vars)
1542 vars = idx;
1543 }
1544 clauses++;
1545 return true;
1546 }
1547};
1548
1550 File *file;
1551
1552public:
1553 ClauseWriter (File *f) : file (f) {}
1554 bool clause (const vector<int> &c) {
1555 for (const auto &lit : c) {
1556 if (!file->put (lit))
1557 return false;
1558 if (!file->put (' '))
1559 return false;
1560 }
1561 return file->put ("0\n");
1562 }
1563};
1564
1565const char *Solver::write_dimacs (const char *path, int min_max_var) {
1566 LOG_API_CALL_BEGIN ("write_dimacs", path, min_max_var);
1568#ifndef CADICAL_QUIET
1569 const double start = internal->time ();
1570#endif
1571 internal->restore_clauses ();
1573 (void) traverse_clauses (counter);
1574 LOG ("found maximal variable %d and %" PRId64 " clauses", counter.vars,
1575 counter.clauses);
1576 File *file = File::write (internal, path);
1577 const char *res = 0;
1578 if (file) {
1579 int actual_max_vars = max (min_max_var, counter.vars);
1580 MSG ("writing %s'p cnf %d %" PRId64 "'%s header", tout.green_code (),
1581 actual_max_vars, counter.clauses, tout.normal_code ());
1582 file->put ("p cnf ");
1583 file->put (actual_max_vars);
1584 file->put (' ');
1585 file->put (counter.clauses);
1586 file->put ('\n');
1587 ClauseWriter writer (file);
1588 if (!traverse_clauses (writer))
1589 res = internal->error_message.init (
1590 "writing to DIMACS file '%s' failed", path);
1591 delete file;
1592 } else
1593 res = internal->error_message.init (
1594 "failed to open DIMACS file '%s' for writing", path);
1595#ifndef CADICAL_QUIET
1596 if (!res) {
1597 const double end = internal->time ();
1598 MSG ("wrote %" PRId64 " clauses in %.2f seconds %s time",
1599 counter.clauses, end - start,
1600 internal->opts.realtime ? "real" : "process");
1601 }
1602#endif
1603 LOG_API_CALL_RETURNS ("write_dimacs", path, min_max_var, res);
1604 return res;
1605}
1606
1607/*------------------------------------------------------------------------*/
1608
1611 int64_t witnesses;
1613 bool write (const vector<int> &a) {
1614 for (const auto &lit : a) {
1615 if (!file->put (lit))
1616 return false;
1617 if (!file->put (' '))
1618 return false;
1619 }
1620 return file->put ('0');
1621 }
1622 bool witness (const vector<int> &c, const vector<int> &w, int64_t) {
1623 if (!write (c))
1624 return false;
1625 if (!file->put (' '))
1626 return false;
1627 if (!write (w))
1628 return false;
1629 if (!file->put ('\n'))
1630 return false;
1631 witnesses++;
1632 return true;
1633 }
1634};
1635
1636const char *Solver::write_extension (const char *path) {
1637 LOG_API_CALL_BEGIN ("write_extension", path);
1639 const char *res = 0;
1640#ifndef CADICAL_QUIET
1641 const double start = internal->time ();
1642#endif
1643 File *file = File::write (internal, path);
1644 WitnessWriter writer (file);
1645 if (file) {
1646 if (!traverse_witnesses_backward (writer))
1647 res = internal->error_message.init (
1648 "writing to DIMACS file '%s' failed", path);
1649 delete file;
1650 } else
1651 res = internal->error_message.init (
1652 "failed to open extension file '%s' for writing", path);
1653#ifndef CADICAL_QUIET
1654 if (!res) {
1655 const double end = internal->time ();
1656 MSG ("wrote %" PRId64 " witnesses in %.2f seconds %s time",
1657 writer.witnesses, end - start,
1658 internal->opts.realtime ? "real" : "process");
1659 }
1660#endif
1661 LOG_API_CALL_RETURNS ("write_extension", path, res);
1662 return res;
1663}
1664
1665/*------------------------------------------------------------------------*/
1666
1669
1670public:
1672 bool clause (const vector<int> &c) {
1673 for (const auto &lit : c)
1674 dst.add (lit);
1675 dst.add (0);
1676 return true;
1677 }
1678};
1679
1682
1683public:
1685 bool witness (const vector<int> &c, const vector<int> &w, int64_t id) {
1686 dst->push_external_clause_and_witness_on_extension_stack (c, w, id);
1687 return true;
1688 }
1689};
1690
1691void Solver::copy (Solver &other) const {
1693 REQUIRE (other.state () & CONFIGURING, "target solver already modified");
1694 internal->opts.copy (other.internal->opts);
1695 ClauseCopier clause_copier (other);
1696 traverse_clauses (clause_copier);
1697 WitnessCopier witness_copier (other.external);
1698 traverse_witnesses_forward (witness_copier);
1699 external->copy_flags (*other.external);
1700}
1701
1702/*------------------------------------------------------------------------*/
1703
1704void Solver::section (const char *title) {
1705 if (state () == DELETING)
1706 return;
1707#ifdef CADICAL_QUIET
1708 (void) title;
1709#endif
1711 SECTION (title);
1712}
1713
1714void Solver::message (const char *fmt, ...) {
1715 if (state () == DELETING)
1716 return;
1717#ifdef CADICAL_QUIET
1718 (void) fmt;
1719#else
1721 va_list ap;
1722 va_start (ap, fmt);
1723 internal->vmessage (fmt, ap);
1724 va_end (ap);
1725#endif
1726}
1727
1728void Solver::message () {
1729 if (state () == DELETING)
1730 return;
1732#ifndef CADICAL_QUIET
1733 internal->message ();
1734#endif
1735}
1736
1737void Solver::verbose (int level, const char *fmt, ...) {
1738 if (state () == DELETING)
1739 return;
1741#ifdef CADICAL_QUIET
1742 (void) level;
1743 (void) fmt;
1744#else
1745 va_list ap;
1746 va_start (ap, fmt);
1747 internal->vverbose (level, fmt, ap);
1748 va_end (ap);
1749#endif
1750}
1751
1752void Solver::error (const char *fmt, ...) {
1753 if (state () == DELETING)
1754 return;
1756 va_list ap;
1757 va_start (ap, fmt);
1758 internal->verror (fmt, ap);
1759 va_end (ap);
1760}
1761
1762} // namespace CaDiCaL
1763
#define ABC_NAMESPACE_IMPL_START
#define ABC_NAMESPACE_IMPL_END
#define CADICAL_assert(ignore)
Definition global.h:14
#define REQUIRE_INITIALIZED()
#define LOG(...)
#define LOG_API_CALL_END(...)
#define STATE(S)
#define TRACE(...)
#define LOG_API_CALL_RETURNS(...)
#define LOG_API_CALL_BEGIN(...)
bool clause(const vector< int > &c)
bool clause(const vector< int > &c)
static File * write(Internal *, FILE *, const char *name)
static File * read(Internal *, FILE *f, const char *name)
const char * init(const char *fmt,...) CADICAL_ATTRIBUTE_FORMAT(2
static Option * has(const char *name)
static bool is_preprocessing_option(const char *name)
static bool parse_long_option(const char *, string &, int &)
const char * parse_dimacs(int &vars, int strict)
bool failed(int lit)
int simplify(int rounds=3)
void connect_learner(Learner *learner)
const char * write_dimacs(const char *path, int min_max_var=0)
void unphase(int lit)
bool set_long_option(const char *arg)
void add_observed_var(int var)
bool is_decision(int lit)
int fixed(int lit) const
void connect_external_propagator(ExternalPropagator *propagator)
void implied(std::vector< int > &implicants)
void force_backtrack(size_t new_level)
CubesWithStatus generate_cubes(int, int min_depth=0)
bool is_valid_limit(const char *arg)
const State & state() const
Definition cadical.hpp:529
void add(int lit)
void phase(int lit)
static bool is_valid_option(const char *name)
void flush_proof_trace(bool print=false)
static void usage()
bool limit(const char *arg, int val)
void connect_proof_tracer(Tracer *tracer, bool antecedents, bool finalize_clauses=false)
int64_t redundant() const
void remove_observed_var(int var)
bool disconnect_proof_tracer(Tracer *tracer)
int64_t irredundant() const
void prefix(const char *verbose_message_prefix)
static bool is_preprocessing_option(const char *name)
void close_proof_trace(bool print=false)
void connect_fixed_listener(FixedAssignmentListener *fixed_listener)
const char * write_extension(const char *path)
void disconnect_external_propagator()
static void build(FILE *file, const char *prefix="c ")
void freeze(int lit)
int get(const char *name)
void optimize(int val)
bool configure(const char *)
int reserve_difference(int number_of_vars)
static const char * signature()
friend class Parser
Definition cadical.hpp:1070
static bool is_valid_long_option(const char *arg)
bool set(const char *name, int val)
void reserve(int min_max_var)
void constrain(int lit)
static void configurations()
bool flip(int lit)
bool trace_proof(FILE *file, const char *name)
static const char * version()
void assume(int lit)
bool frozen(int lit) const
void connect_terminator(Terminator *terminator)
bool traverse_witnesses_backward(WitnessIterator &) const
void copy(Solver &other) const
static bool is_valid_configuration(const char *)
bool flippable(int lit)
bool traverse_clauses(ClauseIterator &) const
bool traverse_witnesses_forward(WitnessIterator &) const
void disconnect_fixed_listener()
const char * read_dimacs(FILE *file, const char *name, int &vars, int strict=1)
const char * normal_code()
Definition terminal.hpp:80
void magenta(bool bright=false)
Definition terminal.hpp:59
#define REQUIRE_READY_STATE()
Definition contract.hpp:123
#define REQUIRE_VALID_LIT(...)
Definition contract.hpp:129
#define REQUIRE_VALID_STATE()
Definition contract.hpp:120
#define REQUIRE_VALID_OR_SOLVING_STATE()
Definition contract.hpp:126
#define REQUIRE(...)
Definition contract.hpp:114
Cube * p
Definition exorList.c:222
#define a1
Definition extraBdd.h:80
struct file file
Definition file.h:21
#define MSG(...)
Definition message.hpp:49
#define FATAL
Definition message.hpp:64
#define SECTION(...)
Definition message.hpp:55
char * name
Definition main.h:24
const char * version()
const char * signature()
const char * date()
@ SATISFIED
Definition cadical.hpp:192
@ INITIALIZING
Definition cadical.hpp:187
@ INCONCLUSIVE
Definition cadical.hpp:195
@ UNSATISFIED
Definition cadical.hpp:193
@ CONFIGURING
Definition cadical.hpp:188
const char * identifier()
Terminal terr(stderr)
Definition terminal.hpp:98
const char * flags()
Terminal tout(stdout)
Definition terminal.hpp:97
const char * compiler()
int lit
Definition satVec.h:130
bool clause(const vector< int > &c)
static void usage()
static bool has(const char *)
static bool set(Options &, const char *)
int solve(bool preprocess_only)
int sol(int elit) const
Definition external.hpp:446
vector< int > assumptions
Definition external.hpp:69
static bool is_valid_limit(const char *name)
std::vector< std::vector< int > > cubes
Definition cadical.hpp:519
bool witness(const vector< int > &c, const vector< int > &w, int64_t id)
bool witness(const vector< int > &c, const vector< int > &w, int64_t)
bool write(const vector< int > &a)
Definition walk.c:35
Definition file.h:23
int strcmp()
char * getenv()