diff --git a/Makefile b/Makefile index a546f65fd..2da81734b 100644 --- a/Makefile +++ b/Makefile @@ -28,7 +28,7 @@ MODULES := \ src/opt/cut src/opt/fxu src/opt/fxch src/opt/rwr src/opt/mfs src/opt/sim \ src/opt/ret src/opt/fret src/opt/res src/opt/lpk src/opt/nwk src/opt/rwt src/opt/rar \ src/opt/cgt src/opt/csw src/opt/dar src/opt/dau src/opt/dsc src/opt/sfm src/opt/sbd \ - src/sat/bsat src/sat/xsat src/sat/satoko src/sat/csat src/sat/msat src/sat/psat src/sat/cnf src/sat/bmc src/sat/glucose src/sat/glucose2 src/sat/kissat src/sat/cadical \ + src/sat/bsat src/sat/xsat src/sat/satoko src/sat/csat src/sat/msat src/sat/psat src/sat/cnf src/sat/bmc src/sat/glucose src/sat/glucose2 src/sat/kissat \ src/bool/bdc src/bool/deco src/bool/dec src/bool/kit src/bool/lucky \ src/bool/rsb src/bool/rpo \ src/proof/pdr src/proof/abs src/proof/live src/proof/ssc src/proof/int \ diff --git a/abclib.dsp b/abclib.dsp index 921030b34..7f6af6f81 100644 --- a/abclib.dsp +++ b/abclib.dsp @@ -2886,374 +2886,6 @@ SOURCE=.\src\sat\kissat\watch.c SOURCE=.\src\sat\kissat\weaken.c # End Source File # End Group -# Begin Group "cadical" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_kitten.c -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_analyze.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_arena.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_assume.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_averages.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_backtrack.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_backward.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_bins.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_block.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_ccadical.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_checker.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_clause.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_collect.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_compact.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_condition.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_config.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_congruence.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_constrain.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_contract.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_cover.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_decide.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_decompose.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_deduplicate.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_definition.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_drattracer.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_elim.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_elimfast.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_ema.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_extend.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_external.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_external_propagate.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_factor.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_file.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_flags.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_flip.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_format.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_frattracer.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_gates.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_idruptracer.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_instantiate.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_internal.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_ipasir.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_lidruptracer.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_limit.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_logging.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_lookahead.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_lratchecker.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_lrattracer.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_lucky.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_message.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_minimize.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_occs.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_options.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_parse.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_phases.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_probe.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_profile.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_proof.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_propagate.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_queue.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_random.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_reap.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_reduce.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_rephase.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_report.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_resources.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_restart.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_restore.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_score.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_shrink.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_signal.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_solution.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_solver.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_stable.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_stats.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_subsume.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_sweep.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_terminal.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_ternary.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_tier.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_transred.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_unstable.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_util.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_var.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_veripbtracer.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_version.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_vivify.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_walk.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadical_watch.cpp -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadicalSolver.c -# End Source File -# Begin Source File - -SOURCE=.\src\sat\cadical\cadicalTest.c -# End Source File -# End Group # End Group # Begin Group "opt" diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index c126df352..7ec94e2cb 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -56155,9 +56155,6 @@ int Abc_CommandAbc9Test( Abc_Frame_t * pAbc, int argc, char ** argv ) } } - extern void cadical_solver_test(); - cadical_solver_test(); - return 0; extern void kissat_solver_test(); kissat_solver_test(); return 0; diff --git a/src/sat/cadical/LICENSE b/src/sat/cadical/LICENSE deleted file mode 100644 index ead29d7a3..000000000 --- a/src/sat/cadical/LICENSE +++ /dev/null @@ -1,28 +0,0 @@ -MIT License - -Copyright (c) 2016-2021 Armin Biere, Johannes Kepler University Linz, Austria -Copyright (c) 2020-2021 Mathias Fleury, Johannes Kepler University Linz, Austria -Copyright (c) 2020-2021 Nils Froleyks, Johannes Kepler University Linz, Austria -Copyright (c) 2022-2024 Katalin Fazekas, Vienna University of Technology, Austria -Copyright (c) 2021-2024 Armin Biere, University of Freiburg, Germany -Copyright (c) 2021-2024 Mathias Fleury, University of Freiburg, Germany -Copyright (c) 2023-2024 Florian Pollitt, University of Freiburg, Germany -Copyright (c) 2024-2024 Tobias Faller, University of Freiburg, Germany - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/src/sat/cadical/VERSION b/src/sat/cadical/VERSION deleted file mode 100644 index a1bba8921..000000000 --- a/src/sat/cadical/VERSION +++ /dev/null @@ -1 +0,0 @@ -2.2.0-rc1 diff --git a/src/sat/cadical/arena.hpp b/src/sat/cadical/arena.hpp deleted file mode 100644 index 522fce36e..000000000 --- a/src/sat/cadical/arena.hpp +++ /dev/null @@ -1,111 +0,0 @@ -#ifndef _arena_hpp_INCLUDED -#define _arena_hpp_INCLUDED - -#include "global.h" - -ABC_NAMESPACE_CXX_HEADER_START - -namespace CaDiCaL { - -// This memory allocation arena provides fixed size pre-allocated memory for -// the moving garbage collector 'copy_non_garbage_clauses' in 'collect.cpp' -// to hold clauses which should survive garbage collection. - -// The advantage of using a pre-allocated arena is that the allocation order -// of the clauses can be adapted in such a way that clauses watched by the -// same literal are allocated consecutively. This improves locality during -// propagation and thus is more cache friendly. A similar technique is -// implemented in MiniSAT and Glucose and gives substantial speed-up in -// propagations per second even though it might even almost double peek -// memory usage. Note that in MiniSAT this arena is actually required for -// MiniSAT to be able to use 32 bit clauses references instead of 64 bit -// pointers. This would restrict the maximum number of clauses and thus is -// a restriction we do not want to use anymore. - -// New learned clauses are allocated in CaDiCaL outside of this arena and -// moved to the arena during garbage collection. The additional 'to' space -// required for such a moving garbage collector is only allocated for those -// clauses surviving garbage collection, which usually needs much less -// memory than all clauses. The net effect is that in our implementation -// the moving garbage collector using this arena only needs roughly 50% more -// memory than allocating the clauses directly. Both implementations can be -// compared by varying the 'opts.arenatype' option (which also controls the -// allocation order of clauses during moving them). - -// The standard sequence of using the arena is as follows: -// -// Arena arena; -// ... -// arena.prepare (bytes); -// q1 = arena.copy (p1, bytes1); -// ... -// qn = arena.copy (pn, bytesn); -// CADICAL_assert (bytes1 + ... + bytesn <= bytes); -// arena.swap (); -// ... -// if (!arena.contains (q)) delete q; -// ... -// arena.prepare (bytes); -// q1 = arena.copy (p1, bytes1); -// ... -// qn = arena.copy (pn, bytesn); -// CADICAL_assert (bytes1 + ... + bytesn <= bytes); -// arena.swap (); -// ... -// -// One has to be really careful with 'qi' references to arena memory. - -struct Internal; - -class Arena { - - Internal *internal; - - struct { - char *start, *top, *end; - } from, to; - -public: - Arena (Internal *); - ~Arena (); - - // Prepare 'to' space to hold that amount of memory. Precondition is that - // the 'to' space is empty. The following sequence of 'copy' operations - // can use as much memory in sum as pre-allocated here. - // - void prepare (size_t bytes); - - // Does the memory pointed to by 'p' belong to this arena? More precisely - // to the 'from' space, since that is the only one remaining after 'swap'. - // - bool contains (void *p) const { - char *c = (char *) p; - return (from.start <= c && c < from.top) || - (to.start <= c && c < to.top); - } - - // Allocate that amount of memory in 'to' space. This assumes the 'to' - // space has been prepared to hold enough memory with 'prepare'. Then - // copy the memory pointed to by 'p' of size 'bytes'. Note that it does - // not matter whether 'p' is in 'from' or allocated outside of the arena. - // - char *copy (const char *p, size_t bytes) { - char *res = to.top; - to.top += bytes; - CADICAL_assert (to.top <= to.end); - memcpy (res, p, bytes); - return res; - } - - // Completely delete 'from' space and then replace 'from' by 'to' (by - // pointer swapping). Everything previously allocated (in 'from') and not - // explicitly copied to 'to' with 'copy' becomes invalid. - // - void swap (); -}; - -} // namespace CaDiCaL - -ABC_NAMESPACE_CXX_HEADER_END - -#endif diff --git a/src/sat/cadical/averages.hpp b/src/sat/cadical/averages.hpp deleted file mode 100644 index 3ebdcddfa..000000000 --- a/src/sat/cadical/averages.hpp +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef _averages_hpp_INCLUDED -#define _averages_hpp_INCLUDED - -#include "global.h" - -#include "ema.hpp" // alphabetically after 'averages.hpp' - -ABC_NAMESPACE_CXX_HEADER_START - -namespace CaDiCaL { - -struct Averages { - - int64_t swapped; - - struct { - - struct { - EMA fast; // average fast (small window) moving glucose level - EMA slow; // average slow (large window) moving glucose level - } glue; - - struct { - EMA fast; // average fast (small window) moving trail level - EMA slow; // average slow (large window) moving trail level - } trail; - - EMA decisions; - - EMA size; // average learned clause size - EMA jump; // average (potential non-chronological) back-jump level - EMA level; // average back track level after conflict - - } current, saved; - - Averages () : swapped (0) {} -}; - -} // namespace CaDiCaL - -ABC_NAMESPACE_CXX_HEADER_END - -#endif diff --git a/src/sat/cadical/bins.hpp b/src/sat/cadical/bins.hpp deleted file mode 100644 index aeefeceeb..000000000 --- a/src/sat/cadical/bins.hpp +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef _bins_hpp_INCLUDED -#define _bins_hpp_INCLUDED - -#include "global.h" - -#include "util.hpp" // Alphabetically after 'bins'. - -ABC_NAMESPACE_CXX_HEADER_START - -namespace CaDiCaL { - -using namespace std; - -struct Bin { - int lit; - int64_t id; -}; - -typedef vector Bins; - -inline void shrink_bins (Bins &bs) { shrink_vector (bs); } -inline void erase_bins (Bins &bs) { erase_vector (bs); } - -} // namespace CaDiCaL - -ABC_NAMESPACE_CXX_HEADER_END - -#endif diff --git a/src/sat/cadical/block.hpp b/src/sat/cadical/block.hpp deleted file mode 100644 index 202355f82..000000000 --- a/src/sat/cadical/block.hpp +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef _block_hpp_INCLUDED -#define _block_hpp_INCLUDED - -#include "global.h" - -#include "heap.hpp" // Alphabetically after 'block.hpp'. - -ABC_NAMESPACE_CXX_HEADER_START - -namespace CaDiCaL { - -struct Internal; - -struct block_more_occs_size { - Internal *internal; - block_more_occs_size (Internal *i) : internal (i) {} - bool operator() (unsigned a, unsigned b); -}; - -typedef heap BlockSchedule; - -class Blocker { - - friend struct Internal; - - vector candidates; - vector reschedule; - BlockSchedule schedule; - - Blocker (Internal *i) : schedule (block_more_occs_size (i)) {} - - void erase () { - erase_vector (candidates); - erase_vector (reschedule); - schedule.erase (); - } -}; - -} // namespace CaDiCaL - -ABC_NAMESPACE_CXX_HEADER_END - -#endif diff --git a/src/sat/cadical/cadical.hpp b/src/sat/cadical/cadical.hpp deleted file mode 100644 index c9ed41332..000000000 --- a/src/sat/cadical/cadical.hpp +++ /dev/null @@ -1,1351 +0,0 @@ -#ifndef _cadical_hpp_INCLUDED -#define _cadical_hpp_INCLUDED - -#include "global.h" - -#include -#include -#include - -ABC_NAMESPACE_CXX_HEADER_START - -namespace CaDiCaL { - -/*========================================================================*/ - -// This provides the actual API of the CaDiCaL solver, which is implemented -// in the class 'Solver' below. Beside its constructor and destructor most -// important is the IPASIR part which you can find between 'BEGIN IPASIR' -// and 'END IPASIR' comments below. The following '[Example]' below might -// also be a good starting point to understand the API. - -/*========================================================================*/ - -// The SAT competition standardized the exit code of SAT solvers to the -// following which then is also used return code for 'solve' functions. -// In the following example we use those constants for brevity though. - -enum Status { - SATISFIABLE = 10, - UNSATISFIABLE = 20, - UNKNOWN = 0, -}; - -/*========================================================================*/ - -// [Example] -// -// The internal solver state follows the IPASIR API model used in the -// incremental track of the SAT competition. State transitions are -// triggered by member function calls, declared and described below. -// -// Consider the following code (from 'test/api/example.cpp') of API usage: -// -// CaDiCaL::Solver * solver = new CaDiCaL::Solver; -// -// // ------------------------------------------------------------------ -// // Encode Problem and check without assumptions. -// -// enum { TIE = 1, SHIRT = 2 }; -// -// solver->add (-TIE), solver->add (SHIRT), solver->add (0); -// solver->add (TIE), solver->add (SHIRT), solver->add (0); -// solver->add (-TIE), solver->add (-SHIRT), solver->add (0); -// -// int res = solver->solve (); // Solve instance. -// CADICAL_assert (res == 10); // Check it is 'SATISFIABLE'. -// -// res = solver->val (TIE); // Obtain assignment of 'TIE'. -// CADICAL_assert (res < 0); // Check 'TIE' assigned to 'false'. -// -// res = solver->val (SHIRT); // Obtain assignment of 'SHIRT'. -// CADICAL_assert (res > 0); // Check 'SHIRT' assigned to 'true'. -// -// // ------------------------------------------------------------------ -// // Incrementally solve again under one assumption. -// -// solver->assume (TIE); // Now force 'TIE' to true. -// -// res = solver->solve (); // Solve again incrementally. -// CADICAL_assert (res == 20); // Check it is 'UNSATISFIABLE'. -// -// res = solver->failed (TIE); // Check 'TIE' responsible. -// CADICAL_assert (res); // Yes, 'TIE' in core. -// -// res = solver->failed (SHIRT); // Check 'SHIRT' responsible. -// CADICAL_assert (!res); // No, 'SHIRT' not in core. -// -// // ------------------------------------------------------------------ -// // Incrementally solve once more under another assumption. -// -// solver->assume (-SHIRT); // Now force 'SHIRT' to false. -// -// res = solver->solve (); // Solve again incrementally. -// CADICAL_assert (res == 20); // Check it is 'UNSATISFIABLE'. -// -// res = solver->failed (TIE); // Check 'TIE' responsible. -// CADICAL_assert (!res); // No, 'TIE' not in core. -// -// res = solver->failed (-SHIRT); // Check '!SHIRT' responsible. -// CADICAL_assert (res); // Yes, '!SHIRT' in core. -// -// // ------------------------------------------------------------------ -// -// delete solver; - -/*========================================================================*/ - -// [States and Transitions] -// -// Compared to IPASIR we also use an 'ADDING' state in which the solver -// stays while adding non-zero literals until the clause is completed -// through adding a zero literal. The additional 'INITIALIZING', -// 'CONFIGURING' and 'DELETING' states are also not part of IPASIR but also -// useful for testing and debugging. -// -// We have the following transitions which are all synchronous except for -// the reentrant 'terminate' call: -// -// new -// INITIALIZING --------------------------> CONFIGURING -// -// set / trace -// CONFIGURING --------------------------> CONFIGURING -// -// add (non zero literal) -// VALID --------------------------> ADDING -// -// add (zero literal) -// VALID --------------------------> STEADY -// -// assume (non zero literal) -// READY --------------------------> STEADY -// -// solve -// READY --------------------------> SOLVING -// -// (internal) -// SOLVING --------------------------> SOLVED -// -// val (non zero literal) -// SATISFIED --------------------------> SATISFIED -// -// failed (non zero literal) -// UNSATISFIED --------------------------> UNSATISFIED -// -// implied (non zero literal) -// INCONCLUSIVE --------------------------> INCONCLUSIVE -// -// delete -// VALID --------------------------> DELETING -// -// where -// -// SOLVED = SATISFIED | UNSATISFIED | INCONCLUSIVE -// READY = CONFIGURING | STEADY | SOLVED -// VALID = READY | ADDING -// INVALID = INITIALIZING | DELETING -// -// The 'SOLVING' state is only visible in different contexts, i.e., from -// another thread or from a signal handler. It is used to implement -// 'terminate'. Here is the only asynchronous transition: -// -// terminate (asynchronously) -// SOLVING -------------------------> STEADY -// -// The important behaviour to remember is that adding, assuming or -// constraining a literal (immediately) destroys the satisfying assignment -// in the 'SATISFIED' state and vice versa resets all assumptions in the -// 'UNSATISFIED' state. This is exactly the behaviour required by the IPASIR -// interface. -// -// Furthermore, the model can only be queried through 'val' in the -// 'SATISFIED' state, while extracting failed assumptions with 'failed' only -// in the 'UNSATISFIED' state. Solving can only be started in the 'STEADY ' -// or 'CONFIGURING' state or after the previous call to 'solve' yielded an -// 'INCONCLUSIVE , 'SATISFIED' or 'UNSATISFIED' state. -// -// All literals have to be valid literals too, i.e., 32-bit integers -// different from 'INT_MIN'. If any of these requirements is violated the -// solver aborts with an 'API contract violation' message. -// -// HINT: If you do not understand why a contract is violated you can run -// 'mobical' on the failing API call trace. Point the environment variable -// 'CADICAL_API_TRACE' to the file where you want to save the trace during -// execution of your program linking against the library. You probably need -// for 'mobical' to use the option '--do-not-enforce-contracts' though to -// force running into the same contract violation. -// -// Additional API calls (like 'freeze' and 'melt') do not change the state -// of the solver and are all described below. - -/*========================================================================*/ - -// States are represented by a bit-set in order to combine them. - -enum State { - INITIALIZING = 1, // during initialization (invalid) - CONFIGURING = 2, // configure options (with 'set') - STEADY = 4, // ready to call 'solve' - ADDING = 8, // adding clause literals (zero missing) - SOLVING = 16, // while solving (within 'solve') - SATISFIED = 32, // satisfiable allows 'val' - UNSATISFIED = 64, // unsatisfiable allows 'failed' - DELETING = 128, // during and after deletion (invalid) - INCONCLUSIVE = 256, // unknown allows 'implied' - - // These combined states are used to check contracts. - - READY = CONFIGURING | STEADY | SATISFIED | UNSATISFIED | INCONCLUSIVE, - VALID = READY | ADDING, - INVALID = INITIALIZING | DELETING -}; - -/*------------------------------------------------------------------------*/ - -// Opaque classes needed in the API and declared in the same namespace. - -class File; -class Testing; -struct Internal; -struct External; - -/*------------------------------------------------------------------------*/ - -// Forward declaration of call-back classes. See bottom of this file. - -class Learner; -class FixedAssignmentListener; -class Terminator; -class ClauseIterator; -class WitnessIterator; -class ExternalPropagator; -class Tracer; -struct InternalTracer; -class FileTracer; -class StatTracer; - -/*------------------------------------------------------------------------*/ - -class Solver { - -public: - // ====== BEGIN IPASIR =================================================== - - // This section implements the corresponding IPASIR functionality. - - Solver (); - ~Solver (); - - static const char *signature (); // name of this library - - // Core functionality as in the IPASIR incremental SAT solver interface. - // (recall 'READY = CONFIGURING | STEADY | SATISFIED | UNSATISFIED'). - // Further note that 'lit' is required to be different from 'INT_MIN' and - // different from '0' except for 'add'. - - // Add valid literal to clause or zero to terminate clause. - // - // require (VALID) // recall 'VALID = READY | ADDING' - // if (lit) ensure (ADDING) // and thus VALID but not READY - // if (!lit) ensure (STEADY ) // and thus READY - // - void add (int lit); - - // Here are functions simplifying clause addition. The given literals - // should all be valid (different from 'INT_MIN' and different from '0'). - // - // require (VALID) - // ensure (STEADY ) - // - void clause (int); // Add unit clause. - void clause (int, int); // Add binary clause. - void clause (int, int, int); // Add ternary clause. - void clause (int, int, int, int); // Add quaternary clause. - void clause (int, int, int, int, int); // Add quinternary clause. - void clause (const std::vector &); // Add literal vector as clause. - void clause (const int *, size_t); // Add literal array as clause. - - // This function can be used to check if the formula is already - // inconsistent (contains the empty clause or was proven to be - // root-level unsatisfiable). - - bool inconsistent (); - - // Assume valid non zero literal for next call to 'solve'. These - // assumptions are reset after the call to 'solve' as well as after - // returning from 'simplify' and 'lookahead. - // - // require (READY) - // ensure (STEADY ) - // - void assume (int lit); - - // Try to solve the current formula. Returns - // - // 0 = UNKNOWN (limit reached or interrupted through 'terminate') - // 10 = SATISFIABLE - // 20 = UNSATISFIABLE - // - // require (READY) - // ensure (INCONCLUSIVE | SATISFIED | UNSATISFIED) - // - // Note, that while in this call the solver actually transitions to state - // 'SOLVING', which however is only visible from a different context, - // i.e., from a different thread or from a signal handler. Only right - // before returning from this call it goes into a 'READY' state. - // - int solve (); - - // Get value (-lit=false, lit=true) of valid non-zero literal. - // - // require (SATISFIED) - // ensure (SATISFIED) - // - int val (int lit); - - // Try to flip the value of the given literal without falsifying the - // formula. Returns 'true' if this was successful. Otherwise the model is - // not changed and 'false' is returned. If a literal was eliminated or - // substituted flipping will fail on that literal and in particular the - // solver will not taint it nor restore any clauses. - // - // The 'flip' function can only flip the value of a variables not acting - // as witness on the reconstruction stack. - // - // As a side effect of calling this function first all assigned variables - // are propagated again without using blocking literal. Thus the first - // call to this function after obtaining a model adds a substantial - // overhead. Subsequent calls will not need to properly propagate again. - // - // Furthermore if the reconstruction stack is non-empty and has been - // traversed to reconstruct a full extended model for eliminated - // variables (and to satisfy removed blocked clauses), the values of these - // witness variables obtained via 'val' before become invalid. The user - // thus will need to call 'val' again after calling 'flip' which will - // trigger then a traversal of the reconstruction stack. - // - // So try to avoid mixing 'flip' and 'val' (for efficiency only). - // Further, this functionality is currently not supported in the presence - // of an external propagator. - // - // require (SATISFIED) - // ensure (SATISFIED) - // - bool flip (int lit); - - // Same as 'flip' without actually flipping it. This functionality is - // currently not supported in the presence of an external propagator. - // - // require (SATISFIED) - // ensure (SATISFIED) - // - bool flippable (int lit); - - // Determine whether the valid non-zero literal is in the core. - // Returns 'true' if the literal is in the core and 'false' otherwise. - // Note that the core does not have to be minimal. - // - // require (UNSATISFIED) - // ensure (UNSATISFIED) - // - bool failed (int lit); - - // Add call-back which is checked regularly for termination. There can - // only be one terminator connected. If a second (non-zero) one is added - // the first one is implicitly disconnected. - // - // require (VALID) - // ensure (VALID) - // - void connect_terminator (Terminator *terminator); - void disconnect_terminator (); - - // Add call-back which allows to export learned clauses. - // - // require (VALID) - // ensure (VALID) - // - void connect_learner (Learner *learner); - void disconnect_learner (); - - // ====== END IPASIR ===================================================== - - // Add call-back which allows to observe when a variable is fixed. - // - // require (VALID) - // ensure (VALID) - // - void connect_fixed_listener (FixedAssignmentListener *fixed_listener); - void disconnect_fixed_listener (); - - // ====== BEGIN IPASIR-UP ================================================ - - // Add call-back which allows to learn, propagate and backtrack based on - // external constraints. Only one external propagator can be connected - // and after connection every related variables must be 'observed' (use - // 'add_observed_var' function). - // Disconnection of the external propagator resets all the observed - // variables. - // - // require (VALID) - // ensure (VALID) - // - void connect_external_propagator (ExternalPropagator *propagator); - void disconnect_external_propagator (); - - // Mark as 'observed' those variables that are relevant to the external - // propagator. External propagation, clause addition during search and - // notifications are all over these observed variables. - // A variable can not be observed without having an external propagator - // connected. Observed variables are "frozen" internally, and so - // inprocessing will not consider them as candidates for elimination. - // An observed variable is allowed to be a fresh variable and it can be - // added also during solving. - // - // require (VALID_OR_SOLVING) - // ensure (VALID_OR_SOLVING) - // - void add_observed_var (int var); - - // Removes the 'observed' flag from the given variable. A variable can be - // set unobserved only between solve calls, not during it (to guarantee - // that no yet unexplained external propagation involves it). - // - // require (VALID) - // ensure (VALID) - // - void remove_observed_var (int var); - - // Removes all the 'observed' flags from the variables. Disconnecting the - // propagator invokes this step as well. - // - // require (VALID) - // ensure (VALID) - // - void reset_observed_vars (); - - // Get reason of valid observed literal (true = it is an observed variable - // and it got assigned by a decision during the CDCL loop. Otherwise: - // false. - // - // require (VALID_OR_SOLVING) - // ensure (VALID_OR_SOLVING) - // - bool is_decision (int lit); - - // Force solve to backtrack to certain decision level. Can be called only - // during 'cb_decide' of a connected External Propagator. - // Invoking in any other time will not have an effect. - // If the call had an effect, the External Propagator will be notified - // about the backtrack via 'notify_backtrack'. - // - // require (SOLVING) - // ensure (SOLVING) - // - void force_backtrack (size_t new_level); - - // ====== END IPASIR-UP ================================================== - - //------------------------------------------------------------------------ - // Adds a literal to the constraint clause. Same functionality as 'add' - // but the clause only exists for the next call to solve (same lifetime as - // assumptions). Only one constraint may exists at a time. A new - // constraint replaces the old. The main application of this functionality - // is the model checking algorithm IC3. See our FMCAD'21 paper - // [FroleyksBiere-FMCAD'19] for more details. - // - // Add valid literal to the constraint clause or zero to terminate it. - // - // require (VALID) // recall 'VALID = READY | - // ADDING' if (lit) ensure (ADDING) // and thus VALID but not - // READY if (!lit) && !adding_clause ensure (STEADY ) // and thus READY - // - void constrain (int lit); - - // Determine whether the constraint was used to proof the - // unsatisfiability. Note that the formula might still be unsatisfiable - // without the constraint. - // - // require (UNSATISFIED) - // ensure (UNSATISFIED) - // - bool constraint_failed (); - - // Collects a subset of those literals that are implied by unit - // propagation by assuming the currently defined (potentially empty) set - // of assumptions (see IPASIR assume(lit)) function. In case unit - // propgation over the defined set of assumptions (or over the clause - // database on its own) leads to conflict, the function returns 20 and the - // content of 'implicants' is undefined. In case unit propagation happens - // to satisfy all the clauses (not probable, but not impossible), the - // function returns 10 and 'implicants' is a solution of the current - // formula under the current assumptions (after solution reconstruction). - // In any other case, the function returns 0 (indicating 'UNKNOWN') and - // 'implicants' lists the non-conflicting current value of the trail. - - // Returns - // - // 0 = UNKNOWN (unit propagation did not lead to a conflict nor to a - // complete assignment, or limit reached or interrupted - // through 'terminate') - // 10 = SATISFIABLE - // 20 = UNSATISFIABLE - - // require (READY) - // ensure (INCONCLUSIVE | SATISFIED | UNSATISFIED) - int propagate (); - - // - // require (INCONCLUSIVE) - // ensure (INCONCLUSIVE) - // - void implied (std::vector &implicants); - - //------------------------------------------------------------------------ - // This function determines a good splitting literal. The result can be - // zero if the formula is proven to be satisfiable or unsatisfiable. This - // can then be checked by 'state ()'. If the formula is empty and - // the function is not able to determine satisfiability also zero is - // returned but the state remains steady. - // - // require (READY) - // ensure (INCONCLUSIVE |SATISFIED|UNSATISFIED) - // - int lookahead (void); - - struct CubesWithStatus { - int status; - std::vector> cubes; - }; - - CubesWithStatus generate_cubes (int, int min_depth = 0); - - void reset_assumptions (); - void reset_constraint (); - - // Return the current state of the solver as defined above. - // - const State &state () const { return _state; } - - // Similar to 'state ()' but using the standard competition exit codes of - // '10' for 'SATISFIABLE', '20' for 'UNSATISFIABLE' and '0' otherwise. - // - int status () const { - if (_state == SATISFIED) - return 10; - else if (_state == UNSATISFIED) - return 20; - else - return 0; - } - - /*----------------------------------------------------------------------*/ - - static const char *version (); // return version string - - /*----------------------------------------------------------------------*/ - // Copy 'this' into a fresh 'other'. The copy procedure is not a deep - // clone, but only copies irredundant clauses and units. It also makes - // sure that witness reconstruction works with the copy as with the - // original formula such that both solvers have the same models. - // Assumptions are not copied. Options however are copied as well as - // flags which remember the current state of variables in preprocessing. - // - // require (READY) // for 'this' - // ensure (READY) // for 'this' - // - // other.require (CONFIGURING) - // other.ensure (CONFIGURING | STEADY ) - // - void copy (Solver &other) const; - - /*----------------------------------------------------------------------*/ - // Variables are usually added and initialized implicitly whenever a - // literal is used as an argument except for the functions 'val', 'fixed', - // 'failed' and 'frozen'. However, the library internally keeps a maximum - // variable index, which can be queried. - // With factor (BVA) the solver might also add new variables. In that case - // the user is required to use this to check which variables are currently - // free before adding new variables of their own. - // The alternative is to reserve variables in batches with - // 'reserve_difference'. Using 'reserve' in combination with any technique - // that could add variables (currently only factor) is not advised. - // - // require (VALID | SOLVING) - // ensure (VALID | SOLVING) - // - int vars (); - - // Increase the maximum variable index explicitly. This function makes - // sure that at least 'min_max_var' variables are initialized. Since it - // might need to reallocate tables, it destroys a satisfying assignment - // and has the same state transition and conditions as 'assume' etc. - // - // require (READY) - // ensure (STEADY ) - // - void reserve (int min_max_var); - - // Increase the maximum variable index by a number of new variables. - // initializes 'number_of_vars' new variables and protects them from - // being used by the solver as extension variables (BVA). - // It returns the new maximum variable index which is the highest - // variable name of the consecutive range of newly reserved variables. - // It has the same state transition and conditions as 'reserve' above. - // - // require (READY) - // ensure (STEADY ) - // - int reserve_difference (int number_of_vars); - -#ifndef CADICAL_NTRACING - //------------------------------------------------------------------------ - // This function can be used to write API calls to a file. The same - // format is used which 'mobical' can read, execute and also shrink - // through delta debugging. - // - // Tracing API calls can also be achieved by using the environment - // variable 'CADICAL_API_TRACE'. That alternative is useful if you do not - // want to change the source code using the solver, e.g., if you only have - // a binary with the solver linked in. However, that method only allows - // to trace one solver instance, while with the following function API - // tracing can be enabled for different solver instances individually. - // - // The solver will flush the file after every trace API call but does not - // close it during deletion. It remains owned by the user of the library. - // - // require (VALID) - // ensure (VALID) - // - void trace_api_calls (FILE *file); -#endif - - //------------------------------------------------------------------------ - // Option handling. - - // Determine whether 'name' is a valid option name. - // - static bool is_valid_option (const char *name); - - // Determine whether 'name' enables a specific preprocessing technique. - // - static bool is_preprocessing_option (const char *name); - - // Determine whether 'arg' is a valid long option of the form '--', - // '--=' or '--no-' similar to 'set_long_option' below. - // Legal values are 'true', 'false', or '[-][e]'. - - static bool is_valid_long_option (const char *arg); - - // Get the current value of the option 'name'. If 'name' is invalid then - // zero is returned. Here '--...' arguments as invalid options. - // - int get (const char *name); - - // Set the default verbose message prefix (default "c "). - // - void prefix (const char *verbose_message_prefix); - - // Explicit version of setting an option. If the option '' exists - // and '' can be parsed then 'true' is returned. If the option value - // is out of range the actual value is computed as the closest (minimum or - // maximum) value possible, but still 'true' is returned. - // - // require (CONFIGURING) - // ensure (CONFIGURING) - // - // Thus options can only bet set right after initialization. - // - bool set (const char *name, int val); - - // This function accepts options in command line syntax: - // - // '--=', '--', or '--no-' - // - // It actually calls the previous 'set' function after parsing 'arg'. The - // same values are expected as for 'is_valid_long_option' above and as - // with 'set' any value outside of the range of legal values for a - // particular option are set to either the minimum or maximum depending on - // which side of the valid interval they lie. - // - // require (CONFIGURING) - // ensure (CONFIGURING) - // - bool set_long_option (const char *arg); - - // Determine whether 'name' is a valid configuration. - // - static bool is_valid_configuration (const char *); - - // Overwrite (some) options with the forced values of the configuration. - // The result is 'true' iff the 'name' is a valid configuration. - // - // require (CONFIGURING) - // ensure (CONFIGURING) - // - bool configure (const char *); - - // Increase preprocessing and inprocessing limits by '10^'. Values - // below '0' are ignored and values above '9' are reduced to '9'. - // - // require (READY) - // ensure (READY) - // - void optimize (int val); - - // Specify search limits, where currently 'name' can be "conflicts", - // "decisions", "preprocessing", or "localsearch". The first two limits - // are unbounded by default. Thus using a negative limit for conflicts or - // decisions switches back to the default of unlimited search (for that - // particular limit). The preprocessing limit determines the number of - // preprocessing rounds, which is zero by default. Similarly, the local - // search limit determines the number of local search rounds (also zero by - // default). As with 'set', the return value denotes whether the limit - // 'name' is valid. These limits are only valid for the next 'solve' or - // 'simplify' call and reset to their default after 'solve' returns (as - // well as overwritten and reset during calls to 'simplify' and - // 'lookahead'). We actually also have an internal "terminate" limit - // which however should only be used for testing and debugging. - // - // require (READY) - // ensure (READY) - // - bool limit (const char *arg, int val); - bool is_valid_limit (const char *arg); - - // The number of currently active variables and clauses can be queried by - // these functions. Variables become active if a clause is added with it. - // They become inactive if they are eliminated or fixed at the root level - // Clauses become inactive if they are satisfied, subsumed, eliminated. - // Redundant clauses are reduced regularly and thus the 'redundant' - // function is less useful. - // - // require (VALID) - // ensure (VALID) - // - int active () const; // Number of active variables. - int64_t redundant () const; // Number of active redundant clauses. - int64_t irredundant () const; // Number of active irredundant clauses. - - //------------------------------------------------------------------------ - // This function executes the given number of preprocessing rounds. It is - // similar to 'solve' with 'limits ("preprocessing", rounds)' except that - // no CDCL nor local search, nor lucky phases are executed. The result - // values are also the same: 0=UNKNOWN, 10=SATISFIABLE, 20=UNSATISFIABLE. - // As 'solve' it resets current assumptions and limits before returning. - // The numbers of rounds should not be negative. If the number of rounds - // is zero only clauses are restored (if necessary) and top level unit - // propagation is performed, which both take some time. - // - // require (READY) - // ensure (INCONCLUSIVE | SATISFIED | UNSATISFIED) - // - int simplify (int rounds = 3); - - //------------------------------------------------------------------------ - // Force termination of 'solve' asynchronously. - // - // require (SOLVING | READY) - // ensure (INCONCLUSIVE ) // actually not immediately (synchronously) - // - void terminate (); - - //------------------------------------------------------------------------ - - // We have the following common reference counting functions, which avoid - // to restore clauses but require substantial user guidance. This was the - // only way to use inprocessing in incremental SAT solving in Lingeling - // (and before in MiniSAT's 'freeze' / 'thaw') and which did not use - // automatic clause restoring. In general this is slower than - // restoring clauses and should not be used. - // - // In essence the user freezes variables which potentially are still - // needed in clauses added or assumptions used after the next 'solve' - // call. As in Lingeling you can freeze a variable multiple times, but - // then have to melt it the same number of times again in order to enable - // variable eliminating on it etc. The arguments can be literals - // (negative indices) but conceptually variables are frozen. - // - // In the old way of doing things without restore you should not use a - // variable incrementally (in 'add' or 'assume'), which was used before - // and potentially could have been eliminated in a previous 'solve' call. - // This can lead to spurious satisfying assignment. In order to check - // this API contract one can use the 'checkfrozen' option. This has the - // drawback that restoring clauses implicitly would fail with a fatal - // error message even if in principle the solver could just restore - // clauses. Thus this option is disabled by default. - // - // See our SAT'19 paper [FazekasBiereScholl-SAT'19] for more details. - // - // require (VALID) - // ensure (VALID) - // - bool frozen (int lit) const; - void freeze (int lit); - void melt (int lit); // Also needs 'require (frozen (lit))'. - - //------------------------------------------------------------------------ - - // Root level assigned variables can be queried with this function. - // It returns '1' if the literal is implied by the formula, '-1' if its - // negation is implied, or '0' if this is unclear at this point. - // - // require (VALID) - // ensure (VALID) - // - int fixed (int lit) const; - - //------------------------------------------------------------------------ - // Force the default decision phase of a variable to a certain value. - // - void phase (int lit); - void unphase (int lit); - - //------------------------------------------------------------------------ - - // Enables clausal proof tracing in DRAT format and returns 'true' if - // successfully opened for writing. Writing proofs has to be enabled - // before calling 'solve', 'add' and 'dimacs', that is in state - // 'CONFIGURING'. Otherwise only partial proofs would be written. - // - // require (CONFIGURING) - // ensure (CONFIGURING) - // - bool trace_proof (FILE *file, const char *name); // Write DRAT proof. - bool trace_proof (const char *path); // Open & write proof. - - // Flushing the proof trace file eventually calls 'fflush' on the actual - // file or pipe and thus if this function returns all the proof steps - // should have been written (with the same guarantees as 'fflush'). - // - // The additional optional argument forces to print the number of addition - // and deletion steps in the proof even if the verbosity level is zero but - // not if quiet is set as well. The default for the stand-alone solver is - // to print this information (in the 'closing proof' section) but for API - // usage of the library we want to stay silent unless explicitly requested - // or verbosity is non-zero (and as explained quiet is not set). - // - // This function can be called multiple times. - // - // require (VALID) - // ensure (VALID) - // - void flush_proof_trace (bool print = false); - - // Close proof trace early. Similar to 'flush' we allow the user to - // control with 'print' in a more fine-grained way whether statistics - // about the size of the written proof file and if compressed on-the-fly - // the number of actual bytes written (including deflation percentage) are - // printed. Before actually closing (or detaching in case of writing to - // '') we check whether 'flush_proof_trace' was called since the - // last time a proof step (addition or deletion) was traced. If this is - // not the case we would call 'flush_proof_trace' with the same 'print' - // argument. - // - // require (VALID) - // ensure (VALID) - // - void close_proof_trace (bool print = false); - - // Enables clausal proof tracing with or without antecedents using - // the Tracer interface defined in 'tracer.hpp' - // - // InternalTracer, StatTracer and FileTracer for internal use - // - // require (CONFIGURING) - // ensure (CONFIGURING) - // - void connect_proof_tracer (Tracer *tracer, bool antecedents, - bool finalize_clauses = false); - void connect_proof_tracer (InternalTracer *tracer, bool antecedents, - bool finalize_clauses = false); - void connect_proof_tracer (StatTracer *tracer, bool antecedents, - bool finalize_clauses = false); - void connect_proof_tracer (FileTracer *tracer, bool antecedents, - bool finalize_clauses = false); - - // Triggers the conclusion of incremental proofs. - // if the solver is SATISFIED it will trigger extend () - // and give the model to the proof tracer through conclude_sat () - // if the solver is UNSATISFIED it will trigger failing () - // which will learn new clauses as explained below: - // In case of failed assumptions will provide a core negated - // as a clause through the proof tracer interface. - // With a failing constraint these can be multiple clauses. - // Then it will trigger a conclude_unsat event with the id(s) - // of the newly learnt clauses or the id of the global conflict. - // In case the solver is in UNKNOWN, it will collect the currently - // entrailed literals and add them to the proof. - // - // require (SATISFIED || UNSATISFIED || UNKNOWN) - // ensure (SATISFIED || UNSATISFIED || UNKNOWN) - // - void conclude (); - - // Disconnect proof tracer. If this is not done before deleting - // the tracer will be deleted. Returns true if successful. - // - // require (VALID) - // ensure (VALID) - // - bool disconnect_proof_tracer (Tracer *tracer); - bool disconnect_proof_tracer (StatTracer *tracer); - bool disconnect_proof_tracer (FileTracer *tracer); - - //------------------------------------------------------------------------ - - static void usage (); // print usage information for long options - - static void configurations (); // print configuration usage options - - // require (!DELETING) - // ensure (!DELETING) - // - void statistics (); // print statistics - void resources (); // print resource usage (time and memory) - - // require (VALID) - // ensure (VALID) - // - void options (); // print current option and value list - - //------------------------------------------------------------------------ - // Traverse irredundant clauses or the extension stack in reverse order. - // - // The return value is false if traversal is aborted early due to one of - // the visitor functions returning false. See description of the - // iterators below for more details on how to use these functions. - // - // require (VALID) - // ensure (VALID) - // - bool traverse_clauses (ClauseIterator &) const; - bool traverse_witnesses_backward (WitnessIterator &) const; - bool traverse_witnesses_forward (WitnessIterator &) const; - - //------------------------------------------------------------------------ - // Files with explicit path argument support compressed input and output - // if appropriate helper functions 'gzip' etc. are available. They are - // called through opening a pipe to an external command. - // - // If the 'strict' argument is zero then the number of variables and - // clauses specified in the DIMACS headers are ignored, i.e., the header - // 'p cnf 0 0' is always legal. If the 'strict' argument is larger '1' - // strict formatting of the header is required, i.e., single spaces - // everywhere and no trailing white space. - // - // Returns zero if successful and otherwise an error message. - // - // require (VALID) - // ensure (VALID) - // - const char *read_dimacs (FILE *file, const char *name, int &vars, - int strict = 1); - - const char *read_dimacs (const char *path, int &vars, int strict = 1); - - // The following routines work the same way but parse both DIMACS and - // INCCNF files (with 'p inccnf' header and 'a ' lines). If the - // parser finds and 'p inccnf' header or cubes then '*incremental' is set - // to true and the cubes are stored in the given vector (each cube - // terminated by a zero). - - const char *read_dimacs (FILE *file, const char *name, int &vars, - int strict, bool &incremental, - std::vector &cubes); - - const char *read_dimacs (const char *path, int &vars, int strict, - bool &incremental, std::vector &cubes); - - //------------------------------------------------------------------------ - // Write current irredundant clauses and all derived unit clauses - // to a file in DIMACS format. Clauses on the extension stack are - // not included, nor any redundant clauses. - // - // The 'min_max_var' parameter gives a lower bound on the number '' - // of variables used in the DIMACS 'p cnf ...' header. - // - // Returns zero if successful and otherwise an error message. - // - // require (VALID) - // ensure (VALID) - // - const char *write_dimacs (const char *path, int min_max_var = 0); - - // The extension stack for reconstruction a solution can be written too. - // - const char *write_extension (const char *path); - - // Print build configuration to a file with prefix 'c '. If the file - // is '' or '' then terminal color codes might be used. - // - static void build (FILE *file, const char *prefix = "c "); - -private: - //==== start of state ==================================================== - - // The solver is in the state ADDING if either the current clause or the - // constraint (or both) is not yet terminated. - bool adding_clause; - bool adding_constraint; - - State _state; // API states as discussed above. - - /*----------------------------------------------------------------------*/ - - // The 'Solver' class is a 'facade' object for 'External'. It exposes the - // public API of 'External' but hides everything else (except for the some - // private functions). It is supposed to make it easier to understand the - // API and use the solver through the API. - - // This approach has the benefit of decoupling this header file from all - // internal data structures, which is particularly useful if the rest of - // the source is not available. For instance if only a CaDiCaL library is - // installed in a system, then only this header file has to be installed - // too, and still allows to compile and link against the library. - - /*----------------------------------------------------------------------*/ - - // More precisely the CaDiCaL code is split into three layers: - // - // Solver: facade object providing the actual API of the solver - // External: communication layer between 'Solver' and 'Internal' - // Internal: the actual solver code - // - // The 'External' and 'Internal' layers are declared and implemented in - // the corresponding '{external,internal}.{hpp,cpp}' files (as expected), - // while the 'Solver' facade class is defined in 'cadical.hpp' (here) but - // implemented in 'solver.cpp'. The reason for this naming mismatch is, - // that we want to use 'cadical.hpp' for the library header (this header - // file) and call the binary of the stand alone SAT also 'cadical', which - // is more naturally implemented in 'cadical.cpp'. - // - // Separating 'External' from 'Internal' also allows us to map external - // literals to internal literals, which is useful with many fixed or - // eliminated variables (during 'compact' the internal variable range is - // reduced and external variables are remapped). Such an approach is also - // necessary, if we want to use extended resolution in the future (such as - // bounded variable addition). - // - Internal *internal; // Hidden internal solver. - External *external; // Hidden API to internal solver mapping. - - friend class Testing; // Access to 'internal' for testing only! - -#ifndef CADICAL_NTRACING - // The API calls to the solver can be traced by setting the environment - // variable 'CADICAL_API_TRACE' to point to the path of a file to which - // API calls are written. The same format is used which 'mobical' can - // read, execute and also shrink through delta debugging. - // - // The environment variable is read in the constructor and the trace is - // opened for writing and then closed again in the destructor. - // - // Alternatively one case use 'trace_api_calls'. Both - // - bool close_trace_api_file; // Close file if owned by solver it. - FILE *trace_api_file; // Also acts as flag that we are tracing. - - static bool tracing_api_through_environment; - - //===== end of state ==================================================== - - void trace_api_call (const char *) const; - void trace_api_call (const char *, int) const; - void trace_api_call (const char *, const char *) const; - void trace_api_call (const char *, const char *, int) const; -#endif - - void transition_to_steady_state (); - - //------------------------------------------------------------------------ - // Used in the stand alone solver application 'App' and the model based - // tester 'Mobical'. So only these two classes need direct access to the - // otherwise more application specific functions listed here together with - // the internal DIMACS parser. - - friend class App; - friend class Mobical; - friend class Parser; - - // Read solution in competition format for debugging and testing. - // - // require (VALID) - // ensure (VALID) - // - const char *read_solution (const char *path); - - // Cross-compilation with 'MinGW' needs some work-around for 'printf' - // style printing of 64-bit numbers including warning messages. The - // followings lines are copies of similar code in 'inttypes.hpp' but we - // want to keep the 'cadical.hpp' header file stand-alone. - -#ifndef PRINTF_FORMAT -#ifdef __MINGW32__ -#define __USE_MINGW_ANSI_STDIO 1 -#define PRINTF_FORMAT __MINGW_PRINTF_FORMAT -#else -#define PRINTF_FORMAT printf -#endif -#endif - - // This gives warning messages for wrong 'printf' style format string - // usage. Apparently (on 'gcc 9' at least) the first argument is 'this' - // here. - // - // TODO: support for other compilers (beside 'gcc' and 'clang'). - - /* -#define CADICAL_ATTRIBUTE_FORMAT(FORMAT_POSITION, \ - VARIADIC_ARGUMENT_POSITION) \ - __attribute__ ((format (PRINTF_FORMAT, FORMAT_POSITION, \ - VARIADIC_ARGUMENT_POSITION))) - */ -#define CADICAL_ATTRIBUTE_FORMAT(FORMAT_POSITION, VARIADIC_ARGUMENT_POSITION) - - // Messages in a common style. - // - // require (VALID | DELETING) - // ensure (VALID | DELETING) - // - void section (const char *); // print section header - void message (const char *, ...) // ordinary message - CADICAL_ATTRIBUTE_FORMAT (2, 3); - - void message (); // empty line - only prefix - void error (const char *, ...) // produce error message - CADICAL_ATTRIBUTE_FORMAT (2, 3); - - // Explicit verbose level ('section' and 'message' use '0'). - // - // require (VALID | DELETING) - // ensure (VALID | DELETING) - // - void verbose (int level, const char *, ...) - CADICAL_ATTRIBUTE_FORMAT (3, 4); - - // Factoring out common code to both 'read_dimacs' functions above. - // - // require (VALID) - // ensure (VALID) - // - const char *read_dimacs (File *, int &, int strict, bool *incremental = 0, - std::vector * = 0); - - // Factored out common code for 'solve', 'simplify' and 'lookahead'. - // - int call_external_solve_and_check_results (bool preprocess_only); - - //------------------------------------------------------------------------ - // Print DIMACS file to '' for debugging and testing purposes, - // including derived units and assumptions. Since it will print in terms - // of internal literals it is otherwise not really useful. To write a - // DIMACS formula in terms of external variables use 'write_dimacs'. - // - // require (!INITIALIZING) - // ensure (!INITIALIZING) - // - void dump_cnf (); - friend struct DumpCall; // Mobical calls 'dump_cnf' in 'DumpCall::execute' - - /*----------------------------------------------------------------------*/ - - // Used in mobical to test external propagation internally. - // These functions should not be called for any other purposes. - // - ExternalPropagator *get_propagator (); - bool observed (int lit); - bool is_witness (int lit); - - friend struct LemmaCall; - friend struct ObserveCall; - friend struct DisconnectCall; - friend class MockPropagator; -}; - -/*========================================================================*/ - -// Connected terminators are checked for termination regularly. If the -// 'terminate' function of the terminator returns true the solver is -// terminated synchronously as soon it calls this function. - -class Terminator { -public: - virtual ~Terminator () {} - virtual bool terminate () = 0; -}; - -// Connected learners which can be used to export learned clauses. -// The 'learning' can check the size of the learn clause and only if it -// returns true then the individual literals of the learned clause are given -// to the learn through 'learn' one by one terminated by a zero literal. - -class Learner { -public: - virtual ~Learner () {} - virtual bool learning (int size) = 0; - virtual void learn (int lit) = 0; -}; - -// Connected listener gets notified whenever the truth value of a variable -// is fixed (for example during inprocessing or due to some derived unit -// clauses). - -class FixedAssignmentListener { -public: - virtual ~FixedAssignmentListener () {} - - virtual void notify_fixed_assignment (int) = 0; -}; - -/*------------------------------------------------------------------------*/ - -// Allows to connect an external propagator to propagate values to variables -// with an external clause as a reason or to learn new clauses during the -// CDCL loop (without restart). - -class ExternalPropagator { - -public: - bool is_lazy = false; // lazy propagator only checks complete assignments - bool are_reasons_forgettable = - false; // Reason external clauses can be deleted - - virtual ~ExternalPropagator () {} - - // Notify the propagator about assignments to observed variables. - // The notification is not necessarily eager. It usually happens before - // the call of propagator callbacks and when a driving clause is leading - // to an assignment. - // - // virtual void notify_assignment (int lit, bool is_fixed) = 0; - virtual void notify_assignment (const std::vector &lits) = 0; - virtual void notify_new_decision_level () = 0; - virtual void notify_backtrack (size_t new_level) = 0; - - // Check by the external propagator the found complete solution (after - // solution reconstruction). If it returns false, the propagator should - // provide an external clause during the next callback or introduce new - // observed variables during this callback. - // - virtual bool cb_check_found_model (const std::vector &model) = 0; - - // Ask the external propagator for the next decision literal. If it - // returns 0, the solver makes its own choice. - // - virtual int cb_decide () { return 0; }; - - // Ask the external propagator if there is an external propagation to make - // under the current assignment. It returns either a literal to be - // propagated or 0, indicating that there is no external propagation under - // the current assignment. - // - virtual int cb_propagate () { return 0; }; - - // Ask the external propagator for the reason clause of a previous - // external propagation step (done by cb_propagate). The clause must be - // added literal-by-literal closed with a 0. Further, the clause must - // contain the propagated literal. - // - // The clause will be learned as an Irredundant Non-Forgettable Clause - // (see below at 'cb_has_external_clause' more details about it). - // - virtual int cb_add_reason_clause_lit (int propagated_lit) { - (void) propagated_lit; - return 0; - }; - - // The following two functions are used to add external clauses to the - // solver during the CDCL loop. The external clause is added - // literal-by-literal and learned by the solver as an irredundant - // (original) input clause. The clause can be arbitrary, but if it is - // root-satisfied or tautology, the solver will ignore it without learning - // it. Root-falsified literals are eagerly removed from the clause. - // Falsified clauses trigger conflict analysis, propagating clauses - // trigger propagation. In case chrono is 0, the solver backtracks to - // propagate the new literal on the right decision level, otherwise it - // potentially will be an out-of-order assignment on the current level. - // Unit clauses always (unless root-satisfied, see above) trigger - // backtracking (independently from the value of the chrono option and - // independently from being falsified or satisfied or unassigned) to level - // 0. Empty clause (or root falsified clause, see above) makes the problem - // unsat and stops the search immediately. A literal 0 must close the - // clause. - // - // The external propagator indicates that there is a clause to add. - // The parameter of the function allows the user to indicate that how - // 'forgettable' is the external clause. Forgettable clauses are allowed - // to be removed by the SAT solver during clause database reduction. - // However, it is up to the solver to decide when actually the clause is - // deleted. For example, unit clauses, even forgettable ones, will not be - // deleted. In case the clause is not 'forgettable' (the parameter is - // false), the solver considers the clause to be irredundant. - // - // In case the solver produces incremental proofs, these external clauses - // are added to the proof during solving at real-time, i.e., the proof - // checker can ignore them until that point (so added as input clause, but - // input after the query line). - // - // Reason clauses of external propagation steps are assumed to be - // forgettable, parameter 'reason_forgettable' can be used to change it. - // - // Currently, every external clause is expected to be over observed - // (therefore frozen) variables, hence no tainting or restore steps - // are performed upon their addition. This will be changed in later - // versions probably. - // - virtual bool cb_has_external_clause (bool &is_forgettable) = 0; - - // The actual function called to add the external clause. - // - virtual int cb_add_external_clause_lit () = 0; -}; - -/*------------------------------------------------------------------------*/ - -// Allows to traverse all remaining irredundant clauses. Satisfied and -// eliminated clauses are not included, nor any derived units unless such -// a unit literal is frozen. Falsified literals are skipped. If the solver -// is inconsistent only the empty clause is traversed. -// -// If 'clause' returns false traversal aborts early. - -class ClauseIterator { -public: - virtual ~ClauseIterator () {} - virtual bool clause (const std::vector &) = 0; -}; - -/*------------------------------------------------------------------------*/ - -// Allows to traverse all clauses on the extension stack together with their -// witness cubes. If the solver is inconsistent, i.e., an empty clause is -// found and the formula is unsatisfiable, then nothing is traversed. -// -// The clauses traversed in 'traverse_clauses' together with the clauses on -// the extension stack are logically equivalent to the original clauses. -// See our SAT'19 paper for more details. -// -// The witness literals can be used to extend and fix an assignment on the -// remaining clauses to satisfy the clauses on the extension stack too. -// -// All derived units of non-frozen variables are included too. -// -// If 'witness' returns false traversal aborts early. - -class WitnessIterator { -public: - virtual ~WitnessIterator () {} - virtual bool witness (const std::vector &clause, - const std::vector &witness, - int64_t id = 0) = 0; -}; - -/*------------------------------------------------------------------------*/ - -} // namespace CaDiCaL - -ABC_NAMESPACE_CXX_HEADER_END - -#endif diff --git a/src/sat/cadical/cadicalSolver.c b/src/sat/cadical/cadicalSolver.c deleted file mode 100644 index 9caea6605..000000000 --- a/src/sat/cadical/cadicalSolver.c +++ /dev/null @@ -1,305 +0,0 @@ -/**CFile**************************************************************** - - FileName [cadicalSolver.c] - - SystemName [ABC: Logic synthesis and verification system.] - - PackageName [SAT solver CaDiCaL by Armin Biere, University of Freiburg] - - Synopsis [https://github.com/arminbiere/cadical] - - Author [Integrated into ABC by Yukio Miyasaka] - - Affiliation [UC Berkeley] - - Date [Ver. 1.0. Started - June 20, 2005.] - - Revision [$Id: cadicalSolver.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] - -***********************************************************************/ - -#include "ccadical.h" -#include "cadicalSolver.h" - -ABC_NAMESPACE_IMPL_START - -//////////////////////////////////////////////////////////////////////// -/// DECLARATIONS /// -//////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////// -/// FUNCTION DEFINITIONS /// -//////////////////////////////////////////////////////////////////////// - -/**Function************************************************************* - - Synopsis [allocate solver] - - Description [] - - SideEffects [] - - SeeAlso [] - -***********************************************************************/ -cadical_solver* cadical_solver_new(void) { - cadical_solver* s = (cadical_solver*)malloc(sizeof(cadical_solver)); - s->p = (void*)ccadical_init(); - s->nVars = 0; - s->vAssumptions = NULL; - s->vCore = NULL; - return s; -} - -/**Function************************************************************* - - Synopsis [delete solver] - - Description [] - - SideEffects [] - - SeeAlso [] - -***********************************************************************/ -void cadical_solver_delete(cadical_solver* s) { - ccadical_release((CCaDiCaL*)s->p); - if(s->vAssumptions) { - Vec_IntFree(s->vAssumptions); - } - if(s->vCore) { - Vec_IntFree(s->vCore); - } - free(s); -} - -/**Function************************************************************* - - Synopsis [add clause] - - Description [cadical takes x and -x as a literal for a variable x > 0, - where 0 is an indicator of the end of a clause. - since variables start from 0 in abc, a variable v is - translated into v + 1 in cadical.] - - SideEffects [] - - SeeAlso [] - -***********************************************************************/ -int cadical_solver_addclause(cadical_solver* s, int* begin, int* end) { - for(;begin != end; begin++) { - if(*begin & 1) { - ccadical_add((CCaDiCaL*)s->p, -(1 + ((*begin) >> 1))); - } else { - ccadical_add((CCaDiCaL*)s->p, 1 + ((*begin) >> 1) ); - } - } - ccadical_add((CCaDiCaL*)s->p, 0); - return !ccadical_is_inconsistent((CCaDiCaL*)s->p); -} - -/**Function************************************************************* - - Synopsis [solve with resource limits] - - Description [assumptions and inspection limits are not supported.] - - SideEffects [] - - SeeAlso [] - -***********************************************************************/ -int cadical_solver_solve(cadical_solver* s, int* begin, int* end, ABC_INT64_T nConfLimit, ABC_INT64_T nInsLimit, ABC_INT64_T nConfLimitGlobal, ABC_INT64_T nInsLimitGlobal) { - // inspection limits are not supported - assert(nInsLimit == 0); - assert(nInsLimitGlobal == 0); - // set conflict limits - if(nConfLimit) - ccadical_limit((CCaDiCaL*)s->p, "conflicts", nConfLimit); - if(nConfLimitGlobal && (nConfLimit == 0 || nConfLimit > nConfLimitGlobal)) - ccadical_limit((CCaDiCaL*)s->p, "conflicts", nConfLimitGlobal); - // assumptions - if(begin != end) { - // save - if(s->vAssumptions == NULL) { - s->vAssumptions = Vec_IntAllocArrayCopy(begin, end - begin); - } else { - Vec_IntClear(s->vAssumptions); - Vec_IntGrow(s->vAssumptions, end - begin); - Vec_IntPushArray(s->vAssumptions, begin, end - begin); - } - // assume - for(;begin != end; begin++) { - if(*begin & 1) { - ccadical_assume((CCaDiCaL*)s->p, -(1 + ((*begin) >> 1))); - } else { - ccadical_assume((CCaDiCaL*)s->p, 1 + ((*begin) >> 1) ); - } - } - } - // solve - int res = ccadical_solve((CCaDiCaL*)s->p); - // translate this cadical return value into a corresponding ABC status value - switch(res) { - case 0: // UNDETERMINED - return 0; - case 10: // SATISFIABLE - return 1; - case 20: // UNSATISFIABLE - return -1; - default: - assert(0); - } - return 0; -} - -/**Function************************************************************* - - Synopsis [get unsat core] - - Description [following minisat, return number of literals in core, - which consists of responsible assumptions, negated. - array will be freed by solver.] - - SideEffects [] - - SeeAlso [] - -***********************************************************************/ -int cadical_solver_final(cadical_solver* s, int** ppArray) { - int v, i; - if(s->vCore == NULL) { - s->vCore = Vec_IntAlloc(Vec_IntSize(s->vAssumptions)); - } else { - Vec_IntClear(s->vCore); - } - Vec_IntForEachEntry(s->vAssumptions, v, i) { - int failed; - if(v & 1) { - failed = ccadical_failed((CCaDiCaL*)s->p, -(1 + (v >> 1))); - } else { - failed = ccadical_failed((CCaDiCaL*)s->p, 1 + (v >> 1) ); - } - if(failed) { - Vec_IntPush(s->vCore, Abc_LitNot(v)); - } - } - *ppArray = Vec_IntArray(s->vCore); - return Vec_IntSize(s->vCore); -} - -/**Function************************************************************* - - Synopsis [get number of variables] - - Description [emulated using "nVars".] - - SideEffects [] - - SeeAlso [] - -***********************************************************************/ -int cadical_solver_nvars(cadical_solver* s) { - return s->nVars; -} - -/**Function************************************************************* - - Synopsis [add new variable] - - Description [emulated using "nVars".] - - SideEffects [] - - SeeAlso [] - -***********************************************************************/ -int cadical_solver_addvar(cadical_solver* s) { - return s->nVars++; -} - -/**Function************************************************************* - - Synopsis [set number of variables] - - Description [not only emulate with "nVars" but also reserve memory.] - - SideEffects [] - - SeeAlso [] - -***********************************************************************/ -void cadical_solver_setnvars(cadical_solver* s,int n) { - s->nVars = n; - ccadical_reserve((CCaDiCaL*)s->p, n); -} - -/**Function************************************************************* - - Synopsis [get value of variable] - - Description [cadical returns x (true) or -x (false) for a variable x. - note a variable v was translated into v + 1 in cadical.] - - SideEffects [] - - SeeAlso [] - -***********************************************************************/ -int cadical_solver_get_var_value(cadical_solver* s, int v) { - return ccadical_val((CCaDiCaL*)s->p, v + 1) > 0; -} - - -/**Function************************************************************* - - Synopsis [Solves the given CNF using cadical.] - - Description [] - - SideEffects [] - - SeeAlso [] - -***********************************************************************/ -Vec_Int_t * cadical_solve_cnf( Cnf_Dat_t * pCnf, char * pArgs, int nConfs, int nTimeLimit, int fSat, int fUnsat, int fPrintCex, int fVerbose ) -{ - abctime clk = Abc_Clock(); - Vec_Int_t * vRes = NULL; - int i, * pBeg, * pEnd, RetValue; - if ( fVerbose ) - printf( "CNF stats: Vars = %6d. Clauses = %7d. Literals = %8d. ", pCnf->nVars, pCnf->nClauses, pCnf->nLiterals ); - cadical_solver *pSat = cadical_solver_new(); - cadical_solver_setnvars(pSat, pCnf->nVars); - assert(cadical_solver_nvars(pSat) == pCnf->nVars); - Cnf_CnfForClause( pCnf, pBeg, pEnd, i ) { - if ( !cadical_solver_addclause(pSat, pBeg, pEnd) ) - { - assert( 0 ); // if it happens, can return 1 (unsatisfiable) - return NULL; - } - } - RetValue = cadical_solver_solve(pSat, NULL, NULL, 0, 0, 0, 0); - if ( RetValue == 1 ) - printf( "Result: Satisfiable. " ); - else if ( RetValue == -1 ) - printf( "Result: Unsatisfiable. " ); - else - printf( "Result: Undecided. " ); - if ( RetValue == 1 ) { - vRes = Vec_IntAlloc( pCnf->nVars ); - for ( i = 0; i < pCnf->nVars; i++ ) - Vec_IntPush( vRes, cadical_solver_get_var_value(pSat, i) ); - } - cadical_solver_delete(pSat); - Abc_PrintTime( 1, "Time", Abc_Clock() - clk ); - return vRes; -} - - -//////////////////////////////////////////////////////////////////////// -/// END OF FILE /// -//////////////////////////////////////////////////////////////////////// - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadicalSolver.h b/src/sat/cadical/cadicalSolver.h deleted file mode 100644 index 0192ada3c..000000000 --- a/src/sat/cadical/cadicalSolver.h +++ /dev/null @@ -1,76 +0,0 @@ -/**CFile**************************************************************** - - FileName [cadicalSolver.h] - - SystemName [ABC: Logic synthesis and verification system.] - - PackageName [SAT solver CaDiCaL by Armin Biere, University of Freiburg] - - Synopsis [https://github.com/arminbiere/cadical] - - Author [Integrated into ABC by Yukio Miyasaka] - - Affiliation [UC Berkeley] - - Date [Ver. 1.0. Started - June 20, 2005.] - - Revision [$Id: cadicalSolver.h,v 1.00 2005/06/20 00:00:00 alanmi Exp $] - -***********************************************************************/ - -#ifndef ABC_SAT_CADICAL_SOLVER_H_ -#define ABC_SAT_CADICAL_SOLVER_H_ - -//////////////////////////////////////////////////////////////////////// -/// INCLUDES /// -//////////////////////////////////////////////////////////////////////// - -#include "aig/gia/gia.h" -#include "sat/cnf/cnf.h" - -//////////////////////////////////////////////////////////////////////// -/// PARAMETERS /// -//////////////////////////////////////////////////////////////////////// - -ABC_NAMESPACE_HEADER_START - -//////////////////////////////////////////////////////////////////////// -/// BASIC TYPES /// -//////////////////////////////////////////////////////////////////////// - -typedef struct cadical_solver_ cadical_solver; -struct cadical_solver_ -{ - void* p; - int nVars; - Vec_Int_t* vAssumptions; - Vec_Int_t* vCore; -}; - - -//////////////////////////////////////////////////////////////////////// -/// MACRO DEFINITIONS /// -//////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////// -/// FUNCTION DECLARATIONS /// -//////////////////////////////////////////////////////////////////////// - -extern cadical_solver* cadical_solver_new(void); -extern void cadical_solver_delete(cadical_solver* s); -extern int cadical_solver_addclause(cadical_solver* s, int* begin, int* end); -extern int cadical_solver_solve(cadical_solver* s, int* begin, int* end, ABC_INT64_T nConfLimit, ABC_INT64_T nInsLimit, ABC_INT64_T nConfLimitGlobal, ABC_INT64_T nInsLimitGlobal); -extern int cadical_solver_final(cadical_solver* s, int** ppArray); -extern int cadical_solver_nvars(cadical_solver* s); -extern int cadical_solver_addvar(cadical_solver* s); -extern void cadical_solver_setnvars(cadical_solver* s,int n); -extern int cadical_solver_get_var_value(cadical_solver* s, int v); -extern Vec_Int_t * cadical_solve_cnf( Cnf_Dat_t * pCnf, char * pArgs, int nConfs, int nTimeLimit, int fSat, int fUnsat, int fPrintCex, int fVerbose ); - -ABC_NAMESPACE_HEADER_END - -#endif - -//////////////////////////////////////////////////////////////////////// -/// END OF FILE /// -//////////////////////////////////////////////////////////////////////// diff --git a/src/sat/cadical/cadicalTest.c b/src/sat/cadical/cadicalTest.c deleted file mode 100644 index f3919160b..000000000 --- a/src/sat/cadical/cadicalTest.c +++ /dev/null @@ -1,210 +0,0 @@ -/**CFile**************************************************************** - - FileName [cadicalTest.c] - - SystemName [ABC: Logic synthesis and verification system.] - - PackageName [] - - Synopsis [] - - Author [Alan Mishchenko] - - Affiliation [UC Berkeley] - - Date [Ver. 1.0. Started - June 20, 2005.] - - Revision [$Id: cadicalTest.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] - -***********************************************************************/ - -#include "cadicalSolver.h" - -ABC_NAMESPACE_IMPL_START - -//////////////////////////////////////////////////////////////////////// -/// DECLARATIONS /// -//////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////// -/// FUNCTION DEFINITIONS /// -//////////////////////////////////////////////////////////////////////// -void cadical_solver_test() { - int RetValue; - int Lits[3]; - // test 1 - { - cadical_solver *pSat = cadical_solver_new(); - int a = cadical_solver_addvar(pSat); - int b = cadical_solver_addvar(pSat); - int c = cadical_solver_addvar(pSat); - assert(cadical_solver_nvars(pSat) == 3); - Lits[0] = Abc_Var2Lit(a, 0); - Lits[1] = Abc_Var2Lit(b, 0); - Lits[2] = Abc_Var2Lit(c, 0); - printf("adding (a, b, c)\n"); - RetValue = cadical_solver_addclause(pSat, Lits, Lits + 3); - assert(RetValue); - Lits[0] = Abc_Var2Lit(a, 0); - Lits[1] = Abc_Var2Lit(b, 1); - printf("adding (a, !b)\n"); - RetValue = cadical_solver_addclause(pSat, Lits, Lits + 2); - assert(RetValue); - Lits[0] = Abc_Var2Lit(a, 1); - printf("adding (!a)\n"); - RetValue = cadical_solver_addclause(pSat, Lits, Lits + 1); - assert(RetValue); - RetValue = cadical_solver_solve(pSat, NULL, NULL, 0, 0, 0, 0); - printf("solved: %d\n", RetValue); - assert(RetValue == 1); - int a_val = cadical_solver_get_var_value(pSat, a); - int b_val = cadical_solver_get_var_value(pSat, b); - int c_val = cadical_solver_get_var_value(pSat, c); - printf("a = %d, b = %d, c = %d\n", a_val, b_val, c_val); - assert(a_val == 0); - assert(b_val == 0); - assert(c_val == 1); - cadical_solver_delete(pSat); - printf("test 1 passed\n"); - } - // test 2 - { - cadical_solver *pSat = cadical_solver_new(); - cadical_solver_setnvars(pSat, 2); - assert(cadical_solver_nvars(pSat) == 2); - Lits[0] = Abc_Var2Lit(0, 0); - Lits[1] = Abc_Var2Lit(1, 0); - printf("adding (x0, x1)\n"); - RetValue = cadical_solver_addclause(pSat, Lits, Lits + 2); - assert(RetValue); - Lits[0] = Abc_Var2Lit(0, 0); - Lits[1] = Abc_Var2Lit(1, 1); - printf("adding (x0, !x1)\n"); - RetValue = cadical_solver_addclause(pSat, Lits, Lits + 2); - assert(RetValue); - Lits[0] = Abc_Var2Lit(0, 1); - Lits[1] = Abc_Var2Lit(1, 1); - printf("adding (!x0, !x1)\n"); - RetValue = cadical_solver_addclause(pSat, Lits, Lits + 2); - assert(RetValue); - RetValue = cadical_solver_solve(pSat, NULL, NULL, 0, 0, 0, 0); - printf("solved: %d\n", RetValue); - assert(RetValue == 1); - printf("x0 = %d, x1 = %d\n", cadical_solver_get_var_value(pSat, 0), cadical_solver_get_var_value(pSat, 1)); - assert(cadical_solver_get_var_value(pSat, 0) == 1); - assert(cadical_solver_get_var_value(pSat, 1) == 0); - cadical_solver_delete(pSat); - printf("test 2 passed\n"); - } - // test 3 - { - cadical_solver *pSat = cadical_solver_new(); - cadical_solver_setnvars(pSat, 3); - assert(cadical_solver_nvars(pSat) == 3); - Lits[0] = Abc_Var2Lit(0, 1); - Lits[1] = Abc_Var2Lit(1, 0); - Lits[2] = Abc_Var2Lit(2, 1); - printf("adding (!x0, x1, !x2)\n"); - RetValue = cadical_solver_addclause(pSat, Lits, Lits + 3); - assert(RetValue); - Lits[0] = Abc_Var2Lit(0, 0); - printf("adding (x0)\n"); - RetValue = cadical_solver_addclause(pSat, Lits, Lits + 1); - assert(RetValue); - Lits[0] = Abc_Var2Lit(1, 1); - printf("adding (!x1)\n"); - RetValue = cadical_solver_addclause(pSat, Lits, Lits + 1); - assert(RetValue); - Lits[0] = Abc_Var2Lit(2, 0); - printf("adding (x2)\n"); - RetValue = cadical_solver_addclause(pSat, Lits, Lits + 1); - RetValue = cadical_solver_solve(pSat, NULL, NULL, 0, 0, 0, 0); - printf("solved: %d\n", RetValue); - assert(RetValue == -1); - cadical_solver_delete(pSat); - printf("test 3 passed\n"); - } - // test 4 - { - cadical_solver *pSat = cadical_solver_new(); - cadical_solver_setnvars(pSat, 3); - assert(cadical_solver_nvars(pSat) == 3); - Lits[0] = Abc_Var2Lit(0, 1); - Lits[1] = Abc_Var2Lit(1, 0); - Lits[2] = Abc_Var2Lit(2, 1); - printf("adding (!x0, x1, !x2)\n"); - RetValue = cadical_solver_addclause(pSat, Lits, Lits + 3); - assert(RetValue); - Lits[0] = Abc_Var2Lit(0, 0); - printf("adding (x0)\n"); - RetValue = cadical_solver_addclause(pSat, Lits, Lits + 1); - assert(RetValue); - Lits[0] = Abc_Var2Lit(1, 1); - printf("assume (!x1)\n"); - RetValue = cadical_solver_solve(pSat, Lits, Lits + 1, 0, 0, 0, 0); - printf("solved: %d\n", RetValue); - assert(RetValue == 1); - printf("x0 = %d, x1 = %d, x2 = %d\n", cadical_solver_get_var_value(pSat, 0), cadical_solver_get_var_value(pSat, 1), cadical_solver_get_var_value(pSat, 2)); - assert(cadical_solver_get_var_value(pSat, 0) == 1); - assert(cadical_solver_get_var_value(pSat, 1) == 0); - assert(cadical_solver_get_var_value(pSat, 2) == 0); - cadical_solver_delete(pSat); - printf("test 4 passed\n"); - } - // test 5 - { - cadical_solver *pSat = cadical_solver_new(); - cadical_solver_setnvars(pSat, 3); - assert(cadical_solver_nvars(pSat) == 3); - Lits[0] = Abc_Var2Lit(0, 1); - Lits[1] = Abc_Var2Lit(1, 0); - Lits[2] = Abc_Var2Lit(2, 1); - printf("adding (!x0, x1, !x2)\n"); - RetValue = cadical_solver_addclause(pSat, Lits, Lits + 3); - assert(RetValue); - Lits[0] = Abc_Var2Lit(0, 1); - Lits[1] = Abc_Var2Lit(1, 1); - Lits[2] = Abc_Var2Lit(2, 1); - printf("adding (!x0, !x1, !x2)\n"); - RetValue = cadical_solver_addclause(pSat, Lits, Lits + 3); - assert(RetValue); - Lits[0] = Abc_Var2Lit(0, 0); - printf("adding (x0)\n"); - RetValue = cadical_solver_addclause(pSat, Lits, Lits + 1); - assert(RetValue); - Lits[0] = Abc_Var2Lit(1, 0); - Lits[1] = Abc_Var2Lit(2, 0); - printf("assume (x1, x2)\n"); - RetValue = cadical_solver_solve(pSat, Lits, Lits + 2, 0, 0, 0, 0); - printf("solved: %d\n", RetValue); - assert(RetValue == -1); - int *pCore; - int nSize = cadical_solver_final(pSat, &pCore); - printf("core: "); - for(int i = 0; i < nSize; i++) { - if(i) { - printf(", "); - } - if(Abc_LitIsCompl(pCore[i])) { - printf("!"); - } - printf("x%d", Abc_Lit2Var(pCore[i])); - } - printf("\n"); - int neg_x2_in_core = 0; - for(int i = 0; i < nSize; i++) { - if(Abc_LitIsCompl(pCore[i]) && Abc_Lit2Var(pCore[i]) == 2) { - neg_x2_in_core = 1; - } - } - assert(neg_x2_in_core); - cadical_solver_delete(pSat); - printf("test 5 passed\n"); - } -} - -//////////////////////////////////////////////////////////////////////// -/// END OF FILE /// -//////////////////////////////////////////////////////////////////////// - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_analyze.cpp b/src/sat/cadical/cadical_analyze.cpp deleted file mode 100644 index 74b67fb06..000000000 --- a/src/sat/cadical/cadical_analyze.cpp +++ /dev/null @@ -1,1285 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -/*------------------------------------------------------------------------*/ - -// Code for conflict analysis, i.e., to generate the first UIP clause. The -// main function is 'analyze' below. It further uses 'minimize' to minimize -// the first UIP clause, which is in 'minimize.cpp'. An important side -// effect of conflict analysis is to update the decision queue by bumping -// variables. Similarly analyzed clauses are bumped to mark them as active. - -/*------------------------------------------------------------------------*/ - -void Internal::learn_empty_clause () { - CADICAL_assert (!unsat); - build_chain_for_empty (); - LOG ("learned empty clause"); - external->check_learned_empty_clause (); - int64_t id = ++clause_id; - if (proof) { - proof->add_derived_empty_clause (id, lrat_chain); - } - unsat = true; - conflict_id = id; - marked_failed = true; - conclusion.push_back (id); - lrat_chain.clear (); -} - -void Internal::learn_unit_clause (int lit) { - CADICAL_assert (!unsat); - LOG ("learned unit clause %d, stored at position %d", lit, vlit (lit)); - external->check_learned_unit_clause (lit); - int64_t id = ++clause_id; - if (lrat || frat) { - const unsigned uidx = vlit (lit); - unit_clauses (uidx) = id; - } - if (proof) { - proof->add_derived_unit_clause (id, lit, lrat_chain); - } - mark_fixed (lit); -} - -/*------------------------------------------------------------------------*/ - -// Move bumped variables to the front of the (VMTF) decision queue. The -// 'bumped' time stamp is updated accordingly. It is used to determine -// whether the 'queue.assigned' pointer has to be moved in 'unassign'. - -void Internal::bump_queue (int lit) { - CADICAL_assert (opts.bump); - const int idx = vidx (lit); - if (!links[idx].next) - return; - queue.dequeue (links, idx); - queue.enqueue (links, idx); - CADICAL_assert (stats.bumped != INT64_MAX); - btab[idx] = ++stats.bumped; - LOG ("moved to front variable %d and bumped to %" PRId64 "", idx, - btab[idx]); - if (!vals[idx]) - update_queue_unassigned (idx); -} - -/*------------------------------------------------------------------------*/ - -// It would be better to use 'isinf' but there are some historical issues -// with this function. On some platforms it is a macro and even for C++ it -// changed the scope (in pre 5.0 gcc) from '::isinf' to 'std::isinf'. I do -// not want to worry about these strange incompatibilities and thus use the -// same trick as in older solvers (since the MiniSAT team invented EVSIDS) -// and simply put a hard limit here. It is less elegant but easy to port. - -static inline bool evsids_limit_hit (double score) { - CADICAL_assert (sizeof (score) == 8); // assume IEEE 754 64-bit double - return score > 1e150; // MAX_DOUBLE is around 1.8e308 -} - -/*------------------------------------------------------------------------*/ - -// Classical exponential VSIDS as pioneered by MiniSAT. - -void Internal::rescale_variable_scores () { - stats.rescored++; - double divider = score_inc; - for (auto idx : vars) { - const double tmp = stab[idx]; - if (tmp > divider) - divider = tmp; - } - PHASE ("rescore", stats.rescored, "rescoring %d variable scores by 1/%g", - max_var, divider); - CADICAL_assert (divider > 0); - double factor = 1.0 / divider; - for (auto idx : vars) - stab[idx] *= factor; - score_inc *= factor; - PHASE ("rescore", stats.rescored, - "new score increment %g after %" PRId64 " conflicts", score_inc, - stats.conflicts); -} - -void Internal::bump_variable_score (int lit) { - CADICAL_assert (opts.bump); - int idx = vidx (lit); - double old_score = score (idx); - CADICAL_assert (!evsids_limit_hit (old_score)); - double new_score = old_score + score_inc; - if (evsids_limit_hit (new_score)) { - LOG ("bumping %g score of %d hits EVSIDS score limit", old_score, idx); - rescale_variable_scores (); - old_score = score (idx); - CADICAL_assert (!evsids_limit_hit (old_score)); - new_score = old_score + score_inc; - } - CADICAL_assert (!evsids_limit_hit (new_score)); - LOG ("new %g score of %d", new_score, idx); - score (idx) = new_score; - if (scores.contains (idx)) - scores.update (idx); -} - -// Important variables recently used in conflict analysis are 'bumped', - -void Internal::bump_variable (int lit) { - if (use_scores ()) - bump_variable_score (lit); - else - bump_queue (lit); -} - -// After every conflict the variable score increment is increased by a -// factor (if we are currently using scores). - -void Internal::bump_variable_score_inc () { - CADICAL_assert (use_scores ()); - CADICAL_assert (!evsids_limit_hit (score_inc)); - double f = 1e3 / opts.scorefactor; - double new_score_inc = score_inc * f; - if (evsids_limit_hit (new_score_inc)) { - LOG ("bumping %g increment by %g hits EVSIDS score limit", score_inc, - f); - rescale_variable_scores (); - new_score_inc = score_inc * f; - } - CADICAL_assert (!evsids_limit_hit (new_score_inc)); - LOG ("bumped score increment from %g to %g with factor %g", score_inc, - new_score_inc, f); - score_inc = new_score_inc; -} - -/*------------------------------------------------------------------------*/ - -struct analyze_bumped_rank { - Internal *internal; - analyze_bumped_rank (Internal *i) : internal (i) {} - typedef uint64_t Type; - Type operator() (const int &a) const { return internal->bumped (a); } -}; - -struct analyze_bumped_smaller { - Internal *internal; - analyze_bumped_smaller (Internal *i) : internal (i) {} - bool operator() (const int &a, const int &b) const { - const auto s = analyze_bumped_rank (internal) (a); - const auto t = analyze_bumped_rank (internal) (b); - return s < t; - } -}; - -/*------------------------------------------------------------------------*/ - -void Internal::bump_variables () { - - CADICAL_assert (opts.bump); - - START (bump); - - if (!use_scores ()) { - - // Variables are bumped in the order they are in the current decision - // queue. This maintains relative order between bumped variables in - // the queue and seems to work best. We also experimented with - // focusing on variables of the last decision level, but results were - // mixed. - - MSORT (opts.radixsortlim, analyzed.begin (), analyzed.end (), - analyze_bumped_rank (this), analyze_bumped_smaller (this)); - } - - for (const auto &lit : analyzed) - bump_variable (lit); - - if (use_scores ()) - bump_variable_score_inc (); - - STOP (bump); -} - -/*------------------------------------------------------------------------*/ - -// We use the glue time stamp table 'gtab' for fast glue computation. - -int Internal::recompute_glue (Clause *c) { - int res = 0; - const int64_t stamp = ++stats.recomputed; - for (const auto &lit : *c) { - int level = var (lit).level; - CADICAL_assert (gtab[level] <= stamp); - if (gtab[level] == stamp) - continue; - gtab[level] = stamp; - res++; - } - return res; -} - -// Clauses resolved since the last reduction are marked as 'used', their -// glue is recomputed and they are promoted if the glue shrinks. Note that -// promotion from 'tier3' to 'tier2' will set 'used' to '2'. - -inline void Internal::bump_clause (Clause *c) { - LOG (c, "bumping"); - c->used = max_used; - if (c->hyper) - return; - if (!c->redundant) - return; - int new_glue = recompute_glue (c); - if (new_glue < c->glue) - promote_clause (c, new_glue); - - const size_t glue = - std::min ((size_t) c->glue, stats.used[stable].size () - 1); - ++stats.used[stable][glue]; - ++stats.bump_used[stable]; -} - -void Internal::bump_clause2 (Clause *c) { bump_clause (c); } -/*------------------------------------------------------------------------*/ - -// During conflict analysis literals not seen yet either become part of the -// first unique implication point (UIP) clause (if on lower decision level), -// are dropped (if fixed), or are resolved away (if on the current decision -// level and different from the first UIP). At the same time we update the -// number of seen literals on a decision level. This helps conflict clause -// minimization. The number of seen levels is the glucose level (also -// called 'glue', or 'LBD'). - -inline void Internal::analyze_literal (int lit, int &open, - int &resolvent_size, - int &antecedent_size) { - CADICAL_assert (lit); - Var &v = var (lit); - Flags &f = flags (lit); - - if (!v.level) { - if (f.seen || !lrat) - return; - f.seen = true; - unit_analyzed.push_back (lit); - CADICAL_assert (val (lit) < 0); - int64_t id = unit_id (-lit); - unit_chain.push_back (id); - return; - } - ++antecedent_size; - if (f.seen) - return; - - // before marking as seen, get reason and check for missed unit - - CADICAL_assert (val (lit) < 0); - CADICAL_assert (v.level <= level); - if (v.reason == external_reason) { - CADICAL_assert (!opts.exteagerreasons); - v.reason = learn_external_reason_clause (-lit, 0, true); - if (!v.reason) { // actually a unit - --antecedent_size; - LOG ("%d unit after explanation", -lit); - if (f.seen || !lrat) - return; - f.seen = true; - unit_analyzed.push_back (lit); - CADICAL_assert (val (lit) < 0); - const unsigned uidx = vlit (-lit); - int64_t id = unit_clauses (uidx); - CADICAL_assert (id); - unit_chain.push_back (id); - return; - } - } - - f.seen = true; - analyzed.push_back (lit); - - CADICAL_assert (v.reason != external_reason); - if (v.level < level) - clause.push_back (lit); - Level &l = control[v.level]; - if (!l.seen.count++) { - LOG ("found new level %d contributing to conflict", v.level); - levels.push_back (v.level); - } - if (v.trail < l.seen.trail) - l.seen.trail = v.trail; - ++resolvent_size; - LOG ("analyzed literal %d assigned at level %d", lit, v.level); - if (v.level == level) - open++; -} - -inline void Internal::analyze_reason (int lit, Clause *reason, int &open, - int &resolvent_size, - int &antecedent_size) { - CADICAL_assert (reason); - CADICAL_assert (reason != external_reason); - bump_clause (reason); - if (lrat) - lrat_chain.push_back (reason->id); - for (const auto &other : *reason) - if (other != lit) - analyze_literal (other, open, resolvent_size, antecedent_size); -} - -/*------------------------------------------------------------------------*/ - -// This is an idea which was implicit in MapleCOMSPS 2016 for 'limit = 1'. -// See also the paragraph on 'bumping reason side literals' in their SAT'16 -// paper [LiangGaneshPoupartCzarnecki-SAT'16]. Reason side bumping was -// performed exactly when 'LRB' based decision heuristics was used, which in -// the original version was enabled after 10000 conflicts until a time limit -// of 2500 seconds was reached (half of the competition time limit). The -// Maple / Glucose / MiniSAT evolution winning the SAT race in 2019 made -// the schedule of reason side bumping deterministic, i.e., avoiding a time -// limit, by switching between 'LRB' and 'VSIDS' in an interval of initially -// 30 million propagations, which then is increased geometrically by 10%. - -inline bool Internal::bump_also_reason_literal (int lit) { - CADICAL_assert (lit); - CADICAL_assert (val (lit) < 0); - Flags &f = flags (lit); - if (f.seen) - return false; - const Var &v = var (lit); - if (!v.level) - return false; - f.seen = true; - analyzed.push_back (lit); - LOG ("bumping also reason literal %d assigned at level %d", lit, v.level); - return true; -} - -// We experimented with deeper reason bumping without much success though. - -inline void Internal::bump_also_reason_literals (int lit, int depth_limit, - size_t analyzed_limit) { - CADICAL_assert (lit); - CADICAL_assert (depth_limit > 0); - const Var &v = var (lit); - CADICAL_assert (val (lit)); - if (!v.level) - return; - Clause *reason = v.reason; - if (!reason || reason == external_reason) - return; - stats.ticks.search[stable]++; - for (const auto &other : *reason) { - if (other == lit) - continue; - if (!bump_also_reason_literal (other)) - continue; - if (depth_limit < 2) - continue; - bump_also_reason_literals (-other, depth_limit - 1, analyzed_limit); - if (analyzed.size () > analyzed_limit) - break; - } -} - -inline void Internal::bump_also_all_reason_literals () { - CADICAL_assert (opts.bump); - if (!opts.bumpreason) - return; - if (averages.current.decisions > opts.bumpreasonrate) { - LOG ("decisions per conflict rate %g > limit %d", - (double) averages.current.decisions, opts.bumpreasonrate); - return; - } - if (delay[stable].bumpreasons.limit) { - LOG ("delaying reason bumping %" PRId64 " more times", - delay[stable].bumpreasons.limit); - delay[stable].bumpreasons.limit--; - return; - } - CADICAL_assert (opts.bumpreasondepth > 0); - const int depth_limit = opts.bumpreasondepth + stable; - size_t saved_analyzed = analyzed.size (); - size_t analyzed_limit = saved_analyzed * opts.bumpreasonlimit; - for (const auto &lit : clause) - if (analyzed.size () <= analyzed_limit) - bump_also_reason_literals (-lit, depth_limit, analyzed_limit); - else - break; - if (analyzed.size () > analyzed_limit) { - LOG ("not bumping reason side literals as limit exhausted"); - for (size_t i = saved_analyzed; i != analyzed.size (); i++) { - const int lit = analyzed[i]; - Flags &f = flags (lit); - CADICAL_assert (f.seen); - f.seen = false; - } - delay[stable].bumpreasons.interval++; - analyzed.resize (saved_analyzed); - } else { - LOG ("bumping reasons up to depth %d", opts.bumpreasondepth); - delay[stable].bumpreasons.interval /= 2; - } - LOG ("delay internal %" PRId64, delay[stable].bumpreasons.interval); - delay[stable].bumpreasons.limit = delay[stable].bumpreasons.interval; -} - -/*------------------------------------------------------------------------*/ - -void Internal::clear_unit_analyzed_literals () { - LOG ("clearing %zd unit analyzed literals", unit_analyzed.size ()); - for (const auto &lit : unit_analyzed) { - Flags &f = flags (lit); - CADICAL_assert (f.seen); - CADICAL_assert (!var (lit).level); - f.seen = false; - CADICAL_assert (!f.keep); - CADICAL_assert (!f.poison); - CADICAL_assert (!f.removable); - } - unit_analyzed.clear (); -} - -void Internal::clear_analyzed_literals () { - LOG ("clearing %zd analyzed literals", analyzed.size ()); - for (const auto &lit : analyzed) { - Flags &f = flags (lit); - CADICAL_assert (f.seen); - f.seen = false; - CADICAL_assert (!f.keep); - CADICAL_assert (!f.poison); - CADICAL_assert (!f.removable); - } - analyzed.clear (); -#if 0 // to expensive, even for debugging mode - if (unit_analyzed.size ()) - return; - for (auto idx : vars) { - Flags &f = flags (idx); - CADICAL_assert (!f.seen); - } -#endif -} - -void Internal::clear_analyzed_levels () { - LOG ("clearing %zd analyzed levels", levels.size ()); - for (const auto &l : levels) - if (l < (int) control.size ()) - control[l].reset (); - levels.clear (); -} - -/*------------------------------------------------------------------------*/ - -// Smaller level and trail. Comparing literals on their level is necessary -// for chronological backtracking, since trail order might in this case not -// respect level order. - -struct analyze_trail_negative_rank { - Internal *internal; - analyze_trail_negative_rank (Internal *s) : internal (s) {} - typedef uint64_t Type; - Type operator() (int a) { - Var &v = internal->var (a); - uint64_t res = v.level; - res <<= 32; - res |= v.trail; - return ~res; - } -}; - -struct analyze_trail_larger { - Internal *internal; - analyze_trail_larger (Internal *s) : internal (s) {} - bool operator() (const int &a, const int &b) const { - return analyze_trail_negative_rank (internal) (a) < - analyze_trail_negative_rank (internal) (b); - } -}; - -/*------------------------------------------------------------------------*/ - -// Generate new driving clause and compute jump level. - -Clause *Internal::new_driving_clause (const int glue, int &jump) { - - const size_t size = clause.size (); - Clause *res; - - if (!size) { - - jump = 0; - res = 0; - - } else if (size == 1) { - - iterating = true; - jump = 0; - res = 0; - - } else { - - CADICAL_assert (clause.size () > 1); - - // We have to get the last assigned literals into the watch position. - // Sorting all literals with respect to reverse assignment order is - // overkill but seems to get slightly faster run-time. For 'minimize' - // we sort the literals too heuristically along the trail order (so in - // the opposite order) with the hope to hit the recursion limit less - // frequently. Thus sorting effort is doubled here. - // - MSORT (opts.radixsortlim, clause.begin (), clause.end (), - analyze_trail_negative_rank (this), analyze_trail_larger (this)); - - jump = var (clause[1]).level; - res = new_learned_redundant_clause (glue); - res->used = 1 + (glue <= opts.reducetier2glue); - } - - LOG ("jump level %d", jump); - - return res; -} - -/*------------------------------------------------------------------------*/ - -// determine the OTFS level for OTFS. Unlike the find_conflict_level, we do -// not have to fix the clause - -inline int Internal::otfs_find_backtrack_level (int &forced) { - CADICAL_assert (opts.otfs); - int res = 0; - - for (const auto &lit : *conflict) { - const int tmp = var (lit).level; - if (tmp == level) { - forced = lit; - } else if (tmp > res) { - res = tmp; - LOG ("bt level is now %d due to %d", res, lit); - } - } - return res; -} - -/*------------------------------------------------------------------------*/ - -// If chronological backtracking is enabled we need to find the actual -// conflict level and then potentially can also reuse the conflict clause -// as driving clause instead of deriving a redundant new driving clause -// (forcing 'forced') if the number 'count' of literals in conflict assigned -// at the conflict level is exactly one. - -inline int Internal::find_conflict_level (int &forced) { - - CADICAL_assert (conflict); - CADICAL_assert (opts.chrono || opts.otfs || external_prop); - - int res = 0, count = 0; - - forced = 0; - - for (const auto &lit : *conflict) { - const int tmp = var (lit).level; - if (tmp > res) { - res = tmp; - forced = lit; - count = 1; - } else if (tmp == res) { - count++; - if (res == level && count > 1) - break; - } - } - - LOG ("%d literals on actual conflict level %d", count, res); - - const int size = conflict->size; - int *lits = conflict->literals; - - // Move the two highest level literals to the front. - // - for (int i = 0; i < 2; i++) { - - const int lit = lits[i]; - - int highest_position = i; - int highest_literal = lit; - int highest_level = var (highest_literal).level; - - for (int j = i + 1; j < size; j++) { - const int other = lits[j]; - const int tmp = var (other).level; - if (highest_level >= tmp) - continue; - highest_literal = other; - highest_position = j; - highest_level = tmp; - if (highest_level == res) - break; - } - - // No unwatched higher assignment level literal. - // - if (highest_position == i) - continue; - - if (highest_position > 1) { - LOG (conflict, "unwatch %d in", lit); - remove_watch (watches (lit), conflict); - } - - lits[highest_position] = lit; - lits[i] = highest_literal; - - if (highest_position > 1) - watch_literal (highest_literal, lits[!i], conflict); - } - - // Only if the number of highest level literals in the conflict is one - // then we can reuse the conflict clause as driving clause for 'forced'. - // - if (count != 1) - forced = 0; - - return res; -} - -/*------------------------------------------------------------------------*/ - -inline int Internal::determine_actual_backtrack_level (int jump) { - - int res; - - CADICAL_assert (level > jump); - - if (!opts.chrono) { - res = jump; - LOG ("chronological backtracking disabled using jump level %d", res); - } else if (opts.chronoalways) { - stats.chrono++; - res = level - 1; - LOG ("forced chronological backtracking to level %d", res); - } else if (jump >= level - 1) { - res = jump; - LOG ("jump level identical to chronological backtrack level %d", res); - } else if ((size_t) jump < assumptions.size ()) { - res = jump; - LOG ("using jump level %d since it is lower than assumption level %zd", - res, assumptions.size ()); - } else if (level - jump > opts.chronolevelim) { - stats.chrono++; - res = level - 1; - LOG ("back-jumping over %d > %d levels prohibited" - "thus backtracking chronologically to level %d", - level - jump, opts.chronolevelim, res); - } else if (opts.chronoreusetrail) { - int best_idx = 0, best_pos = 0; - - if (use_scores ()) { - for (size_t i = control[jump + 1].trail; i < trail.size (); i++) { - const int idx = abs (trail[i]); - if (best_idx && !score_smaller (this) (best_idx, idx)) - continue; - best_idx = idx; - best_pos = i; - } - LOG ("best variable score %g", score (best_idx)); - } else { - for (size_t i = control[jump + 1].trail; i < trail.size (); i++) { - const int idx = abs (trail[i]); - if (best_idx && bumped (best_idx) >= bumped (idx)) - continue; - best_idx = idx; - best_pos = i; - } - LOG ("best variable bumped %" PRId64 "", bumped (best_idx)); - } - CADICAL_assert (best_idx); - LOG ("best variable %d at trail position %d", best_idx, best_pos); - - // Now find the frame and decision level in the control stack of that - // best variable index. Note that, as in 'reuse_trail', the frame - // 'control[i]' for decision level 'i' contains the trail before that - // decision level, i.e., the decision 'control[i].decision' sits at - // 'control[i].trail' in the trail and we thus have to check the level - // of the control frame one higher than at the result level. - // - res = jump; - while (res < level - 1 && control[res + 1].trail <= best_pos) - res++; - - if (res == jump) - LOG ("default non-chronological back-jumping to level %d", res); - else { - stats.chrono++; - LOG ("chronological backtracking to level %d to reuse trail", res); - } - - } else { - res = jump; - LOG ("non-chronological back-jumping to level %d", res); - } - - return res; -} - -/*------------------------------------------------------------------------*/ - -void Internal::eagerly_subsume_recently_learned_clauses (Clause *c) { - CADICAL_assert (opts.eagersubsume); - LOG (c, "trying eager subsumption with"); - mark (c); - int64_t lim = stats.eagertried + opts.eagersubsumelim; - const auto begin = clauses.begin (); - auto it = clauses.end (); -#ifdef LOGGING - int64_t before = stats.eagersub; -#endif - while (it != begin && stats.eagertried++ <= lim) { - Clause *d = *--it; - if (c == d) - continue; - if (d->garbage) - continue; - if (!d->redundant) - continue; - int needed = c->size; - for (auto &lit : *d) { - if (marked (lit) <= 0) - continue; - if (!--needed) - break; - } - if (needed) - continue; - LOG (d, "eager subsumed"); - stats.eagersub++; - stats.subsumed++; - mark_garbage (d); - } - unmark (c); -#ifdef LOGGING - uint64_t subsumed = stats.eagersub - before; - if (subsumed) - LOG ("eagerly subsumed %" PRIu64 " clauses", subsumed); -#endif -} - -/*------------------------------------------------------------------------*/ - -Clause *Internal::on_the_fly_strengthen (Clause *new_conflict, int uip) { - CADICAL_assert (new_conflict); - CADICAL_assert (new_conflict->size > 2); - LOG (new_conflict, "applying OTFS on lit %d", uip); - auto sorted = std::vector (); - sorted.reserve (new_conflict->size); - CADICAL_assert (sorted.empty ()); - ++stats.otfs.strengthened; - - int *lits = new_conflict->literals; - - CADICAL_assert (lits[0] == uip || lits[1] == uip); - const int other_init = lits[0] ^ lits[1] ^ uip; - - CADICAL_assert (mini_chain.empty ()); - - const int old_size = new_conflict->size; - int new_size = 0; - for (int i = 0; i < old_size; ++i) { - const int other = lits[i]; - sorted.push_back (other); - if (var (other).level) - lits[new_size++] = other; - } - - LOG (new_conflict, "removing all units in"); - - CADICAL_assert (lits[0] == uip || lits[1] == uip); - const int other = lits[0] ^ lits[1] ^ uip; - lits[0] = other; - lits[1] = lits[--new_size]; - LOG (new_conflict, "putting uip at pos 1"); - - if (other_init != other) - remove_watch (watches (other_init), new_conflict); - remove_watch (watches (uip), new_conflict); - - CADICAL_assert (!lrat || lrat_chain.back () == new_conflict->id); - if (lrat) { - CADICAL_assert (!lrat_chain.empty ()); - for (const auto &id : unit_chain) { - mini_chain.push_back (id); - } - const auto end = lrat_chain.rend (); - const auto begin = lrat_chain.rbegin (); - for (auto i = begin; i != end; i++) { - const auto id = *i; - mini_chain.push_back (id); - } - lrat_chain.clear (); - clear_unit_analyzed_literals (); - unit_chain.clear (); - } - CADICAL_assert (unit_analyzed.empty ()); - // sort the clause - { - int highest_pos = 0; - int highest_level = 0; - for (int i = 1; i < new_size; i++) { - const unsigned other = lits[i]; - CADICAL_assert (val (other) < 0); - const int level = var (other).level; - CADICAL_assert (level); - LOG ("checking %d", other); - if (level <= highest_level) - continue; - highest_pos = i; - highest_level = level; - } - LOG ("highest lit is %d", lits[highest_pos]); - if (highest_pos != 1) - swap (lits[1], lits[highest_pos]); - LOG ("removing %d literals", new_conflict->size - new_size); - - if (new_size == 1) { - LOG (new_conflict, "new size = 1, so interrupting"); - CADICAL_assert (!opts.exteagerreasons); - return 0; - } else { - otfs_strengthen_clause (new_conflict, uip, new_size, sorted); - CADICAL_assert (new_size == new_conflict->size); - } - } - - if (other_init != other) - watch_literal (other, lits[1], new_conflict); - else { - update_watch_size (watches (other), lits[1], new_conflict); - } - watch_literal (lits[1], other, new_conflict); - - LOG (new_conflict, "strengthened clause by OTFS"); - sorted.clear (); - - return new_conflict; -} - -/*------------------------------------------------------------------------*/ -inline void Internal::otfs_subsume_clause (Clause *subsuming, - Clause *subsumed) { - stats.subsumed++; - CADICAL_assert (subsuming->size <= subsumed->size); - LOG (subsumed, "subsumed"); - if (subsumed->redundant) - stats.subred++; - else - stats.subirr++; - if (subsumed->redundant || !subsuming->redundant) { - mark_garbage (subsumed); - return; - } - LOG ("turning redundant subsuming clause into irredundant clause"); - subsuming->redundant = false; - if (proof) - proof->strengthen (subsuming->id); - mark_garbage (subsumed); - stats.current.irredundant++; - stats.added.irredundant++; - stats.irrlits += subsuming->size; - CADICAL_assert (stats.current.redundant > 0); - stats.current.redundant--; - CADICAL_assert (stats.added.redundant > 0); - stats.added.redundant--; - // ... and keep 'stats.added.total'. -} - -/*------------------------------------------------------------------------*/ - -// Candidate clause 'c' is strengthened by removing 'lit' and units. -// -void Internal::otfs_strengthen_clause (Clause *c, int lit, int new_size, - const std::vector &old) { - stats.strengthened++; - CADICAL_assert (c->size > 2); - (void) shrink_clause (c, new_size); - if (proof) { - proof->otfs_strengthen_clause (c, old, mini_chain); - } - if (!c->redundant) { - mark_removed (lit); - } - mini_chain.clear (); - c->used = true; - LOG (c, "strengthened"); - external->check_shrunken_clause (c); -} - -/*------------------------------------------------------------------------*/ - -// If the average number of decisions per conflict (analysis actually so not -// taking OTFS conflicts into account) is high we do not bump reasons. This -// is the function which updates the exponential moving decision rate -// average. - -void Internal::update_decision_rate_average () { - int64_t current = stats.decisions; - int64_t decisions = current - saved_decisions; - UPDATE_AVERAGE (averages.current.decisions, decisions); - saved_decisions = current; -} - -/*------------------------------------------------------------------------*/ - -// This is the main conflict analysis routine. It assumes that a conflict -// was found. Then we derive the 1st UIP clause, optionally minimize it, -// add it as learned clause, and then uses the clause for conflict directed -// back-jumping and flipping the 1st UIP literal. In combination with -// chronological backtracking (see discussion above) the algorithm becomes -// slightly more involved. - -void Internal::analyze () { - - START (analyze); - - CADICAL_assert (conflict); - CADICAL_assert (lrat_chain.empty ()); - CADICAL_assert (unit_chain.empty ()); - CADICAL_assert (unit_analyzed.empty ()); - CADICAL_assert (clause.empty ()); - - // First update moving averages of trail height at conflict. - // - UPDATE_AVERAGE (averages.current.trail.fast, num_assigned); - UPDATE_AVERAGE (averages.current.trail.slow, num_assigned); - update_decision_rate_average (); - - /*----------------------------------------------------------------------*/ - - if (external_prop && !external_prop_is_lazy && opts.exteagerreasons) { - explain_external_propagations (); - } - - if (opts.chrono || external_prop) { - - int forced; - - const int conflict_level = find_conflict_level (forced); - - // In principle we can perform conflict analysis as in non-chronological - // backtracking except if there is only one literal with the maximum - // assignment level in the clause. Then standard conflict analysis is - // unnecessary and we can use the conflict as a driving clause. In the - // pseudo code of the SAT'18 paper on chronological backtracking this - // corresponds to the situation handled in line 4-6 in Alg. 1, except - // that the pseudo code in the paper only backtracks while we eagerly - // assign the single literal on the highest decision level. - - if (forced) { - - CADICAL_assert (forced); - CADICAL_assert (conflict_level > 0); - LOG ("single highest level literal %d", forced); - - // The pseudo code in the SAT'18 paper actually backtracks to the - // 'second highest decision' level, while their code backtracks - // to 'conflict_level-1', which is more in the spirit of chronological - // backtracking anyhow and thus we also do the latter. - // - backtrack (conflict_level - 1); - - // if we are on decision level 0 search assign will learn unit - // so we need a valid chain here (of course if we are not on decision - // level 0 this will not result in a valid chain). - // we can just use build_chain_for_units in propagate - // - build_chain_for_units (forced, conflict, 0); - - LOG ("forcing %d", forced); - search_assign_driving (forced, conflict); - - conflict = 0; - STOP (analyze); - return; - } - - // Backtracking to the conflict level is in the pseudo code in the - // SAT'18 chronological backtracking paper, but not in their actual - // implementation. In principle we do not need to backtrack here. - // However, as a side effect of backtracking to the conflict level we - // set 'level' to the conflict level which then allows us to reuse the - // old 'analyze' code as is. The alternative (which we also tried but - // then abandoned) is to use 'conflict_level' instead of 'level' in the - // analysis, which however requires to pass it to the 'analyze_reason' - // and 'analyze_literal' functions. - // - backtrack (conflict_level); - } - - // Actual conflict on root level, thus formula unsatisfiable. - // - if (!level) { - learn_empty_clause (); - if (external->learner) - external->export_learned_empty_clause (); - STOP (analyze); - return; - } - - /*----------------------------------------------------------------------*/ - - // First derive the 1st UIP clause by going over literals assigned on the - // current decision level. Literals in the conflict are marked as 'seen' - // as well as all literals in reason clauses of already 'seen' literals on - // the current decision level. Thus the outer loop starts with the - // conflict clause as 'reason' and then uses the 'reason' of the next - // seen literal on the trail assigned on the current decision level. - // During this process maintain the number 'open' of seen literals on the - // current decision level with not yet processed 'reason'. As soon 'open' - // drops to one, we have found the first unique implication point. This - // is sound because the topological order in which literals are processed - // follows the assignment order and a more complex algorithm to find - // articulation points is not necessary. - // - Clause *reason = conflict; - LOG (reason, "analyzing conflict"); - - CADICAL_assert (clause.empty ()); - CADICAL_assert (lrat_chain.empty ()); - - const auto &t = &trail; - int i = t->size (); // Start at end-of-trail. - int open = 0; // Seen but not processed on this level. - int uip = 0; // The first UIP literal. - int resolvent_size = 0; // without the uip - int antecedent_size = 1; // with the uip and without unit literals - int conflict_size = 0; // without the uip and without unit literals - int resolved = 0; // number of resolution (0 = clause in CNF) - const bool otfs = opts.otfs; - - for (;;) { - antecedent_size = 1; // for uip - analyze_reason (uip, reason, open, resolvent_size, antecedent_size); - if (resolved == 0) - conflict_size = antecedent_size - 1; - CADICAL_assert (resolvent_size == open + (int) clause.size ()); - - if (otfs && resolved > 0 && antecedent_size > 2 && - resolvent_size < antecedent_size) { - CADICAL_assert (reason != conflict); - LOG (analyzed, "found candidate for OTFS conflict"); - LOG (clause, "found candidate for OTFS conflict"); - LOG (reason, "found candidate (size %d) for OTFS resolvent", - antecedent_size); - const int other = reason->literals[0] ^ reason->literals[1] ^ uip; - CADICAL_assert (other != uip); - reason = on_the_fly_strengthen (reason, uip); - if (opts.bump) - bump_variables (); - - CADICAL_assert (conflict_size); - if (!reason) { - uip = -other; - CADICAL_assert (open == 1); - LOG ("clause is actually unit %d, stopping", -uip); - reverse (begin (mini_chain), end (mini_chain)); - for (auto id : mini_chain) - lrat_chain.push_back (id); - mini_chain.clear (); - clear_analyzed_levels (); - CADICAL_assert (!opts.exteagerreasons); - clause.clear (); - break; - } - CADICAL_assert (conflict_size >= 2); - - if (resolved == 1 && resolvent_size < conflict_size) { - // here both clauses are part of the CNF, so one subsumes the other - otfs_subsume_clause (reason, conflict); - LOG (reason, "changing conflict to"); - --conflict_size; - CADICAL_assert (conflict_size == reason->size); - ++stats.otfs.subsumed; - ++stats.subsumed; - } - - LOG (reason, "changing conflict to"); - conflict = reason; - if (open == 1) { - int forced = 0; - const int conflict_level = otfs_find_backtrack_level (forced); - int new_level = determine_actual_backtrack_level (conflict_level); - UPDATE_AVERAGE (averages.current.level, new_level); - backtrack (new_level); - - LOG ("forcing %d", forced); - search_assign_driving (forced, conflict); - - // Clean up. - // - conflict = 0; - clear_analyzed_literals (); - clear_analyzed_levels (); - clause.clear (); - STOP (analyze); - return; - } - - stats.conflicts++; - - clear_analyzed_literals (); - clear_analyzed_levels (); - clause.clear (); - resolvent_size = 0; - antecedent_size = 1; - resolved = 0; - open = 0; - analyze_reason (0, reason, open, resolvent_size, antecedent_size); - conflict_size = antecedent_size - 1; - CADICAL_assert (open > 1); - } - - ++resolved; - - uip = 0; - while (!uip) { - CADICAL_assert (i > 0); - const int lit = (*t)[--i]; - if (!flags (lit).seen) - continue; - if (var (lit).level == level) - uip = lit; - } - if (!--open) - break; - reason = var (uip).reason; - if (reason == external_reason) { - CADICAL_assert (!opts.exteagerreasons); - reason = learn_external_reason_clause (-uip, 0, true); - var (uip).reason = reason; - } - CADICAL_assert (reason != external_reason); - LOG (reason, "analyzing %d reason", uip); - CADICAL_assert (resolvent_size); - --resolvent_size; - } - LOG ("first UIP %d", uip); - clause.push_back (-uip); - - // Update glue and learned (1st UIP literals) statistics. - // - int size = (int) clause.size (); - const int glue = (int) levels.size () - 1; - LOG (clause, "1st UIP size %d and glue %d clause", size, glue); - UPDATE_AVERAGE (averages.current.glue.fast, glue); - UPDATE_AVERAGE (averages.current.glue.slow, glue); - stats.learned.literals += size; - stats.learned.clauses++; - CADICAL_assert (glue < size); - - // up to this point lrat_chain contains the proof for current clause in - // reversed order. in minimize and shrink the clause is changed and - // therefore lrat_chain has to be extended. Unfortunately we cannot create - // the chain directly during minimization (or shrinking) but afterwards we - // can calculate it pretty easily and even better the same algorithm works - // for both shrinking and minimization. - - // Minimize the 1st UIP clause as pioneered by Niklas Soerensson in - // MiniSAT and described in our joint SAT'09 paper. - // - if (size > 1) { - if (opts.shrink) - shrink_and_minimize_clause (); - else if (opts.minimize) - minimize_clause (); - - size = (int) clause.size (); - - // Update decision heuristics. - // - if (opts.bump) { - bump_also_all_reason_literals (); - bump_variables (); - } - - if (external->learner) - external->export_learned_large_clause (clause); - } else if (external->learner) - external->export_learned_unit_clause (-uip); - - // Update actual size statistics. - // - stats.units += (size == 1); - stats.binaries += (size == 2); - UPDATE_AVERAGE (averages.current.size, size); - - // reverse lrat_chain. We could probably work with reversed iterators - // (views) to be more efficient but we would have to distinguish in proof - // - if (lrat) { - LOG (unit_chain, "unit chain: "); - for (auto id : unit_chain) - lrat_chain.push_back (id); - unit_chain.clear (); - reverse (lrat_chain.begin (), lrat_chain.end ()); - } - - // Determine back-jump level, learn driving clause, backtrack and assign - // flipped 1st UIP literal. - // - int jump; - Clause *driving_clause = new_driving_clause (glue, jump); - UPDATE_AVERAGE (averages.current.jump, jump); - - int new_level = determine_actual_backtrack_level (jump); - UPDATE_AVERAGE (averages.current.level, new_level); - backtrack (new_level); - - // It should hold that (!level <=> size == 1) - // and (!uip <=> size == 0) - // this means either we have already learned a clause => size >= 2 - // in this case we will not learn empty clause or unit here - // or we haven't actually learned a clause in new_driving_clause - // then lrat_chain is still valid and we will learn a unit or empty clause - // - if (uip) { - search_assign_driving (-uip, driving_clause); - } else - learn_empty_clause (); - - if (stable) - reluctant.tick (); // Reluctant has its own 'conflict' counter. - - // Clean up. - // - clear_analyzed_literals (); - clear_unit_analyzed_literals (); - clear_analyzed_levels (); - clause.clear (); - conflict = 0; - - lrat_chain.clear (); - STOP (analyze); - - if (driving_clause && opts.eagersubsume) - eagerly_subsume_recently_learned_clauses (driving_clause); - - if (lim.recompute_tier <= stats.conflicts) - recompute_tier (); -} - -// We wait reporting a learned unit until propagation of that unit is -// completed. Otherwise the 'i' report gives the number of remaining -// variables before propagating the unit (and hides the actual remaining -// variables after propagating it). - -void Internal::iterate () { - iterating = false; - report ('i'); -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_arena.cpp b/src/sat/cadical/cadical_arena.cpp deleted file mode 100644 index a8a9b183f..000000000 --- a/src/sat/cadical/cadical_arena.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -Arena::Arena (Internal *i) { - memset (this, 0, sizeof *this); - internal = i; -} - -Arena::~Arena () { - delete[] from.start; - delete[] to.start; -} - -void Arena::prepare (size_t bytes) { - LOG ("preparing 'to' space of arena with %zd bytes", bytes); - CADICAL_assert (!to.start); - to.top = to.start = new char[bytes]; - to.end = to.start + bytes; -} - -void Arena::swap () { - delete[] from.start; - LOG ("delete 'from' space of arena with %zd bytes", - (size_t) (from.end - from.start)); - from = to; - to.start = to.top = to.end = 0; -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_assume.cpp b/src/sat/cadical/cadical_assume.cpp deleted file mode 100644 index e7d5b79b7..000000000 --- a/src/sat/cadical/cadical_assume.cpp +++ /dev/null @@ -1,613 +0,0 @@ -#include "global.h" - -#include "internal.hpp" -#include "options.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -// Failed literal handling as pioneered by MiniSAT. This first function -// adds an assumption literal onto the assumption stack. - -void Internal::assume (int lit) { - if (level && !opts.ilbassumptions) - backtrack (); - else if (val (lit) < 0) - backtrack (max (0, var (lit).level - 1)); - Flags &f = flags (lit); - const unsigned char bit = bign (lit); - if (f.assumed & bit) { - LOG ("ignoring already assumed %d", lit); - return; - } - LOG ("assume %d", lit); - f.assumed |= bit; - assumptions.push_back (lit); - freeze (lit); -} - -// for LRAT we actually need to implement recursive DFS -// for non-lrat use BFS. TODO: maybe derecursify to avoid stack overflow -// -void Internal::assume_analyze_literal (int lit) { - CADICAL_assert (lit); - Flags &f = flags (lit); - if (f.seen) - return; - f.seen = true; - analyzed.push_back (lit); - Var &v = var (lit); - CADICAL_assert (val (lit) < 0); - if (v.reason == external_reason) { - v.reason = wrapped_learn_external_reason_clause (-lit); - CADICAL_assert (v.reason || !v.level); - } - CADICAL_assert (v.reason != external_reason); - if (!v.level) { - int64_t id = unit_id (-lit); - lrat_chain.push_back (id); - return; - } - if (v.reason) { - CADICAL_assert (v.level); - LOG (v.reason, "analyze reason"); - for (const auto &other : *v.reason) { - assume_analyze_literal (other); - } - lrat_chain.push_back (v.reason->id); - return; - } - CADICAL_assert (assumed (-lit)); - LOG ("failed assumption %d", -lit); - clause.push_back (lit); -} - -void Internal::assume_analyze_reason (int lit, Clause *reason) { - CADICAL_assert (reason); - CADICAL_assert (lrat_chain.empty ()); - CADICAL_assert (reason != external_reason); - CADICAL_assert (lrat); - for (const auto &other : *reason) - if (other != lit) - assume_analyze_literal (other); - lrat_chain.push_back (reason->id); -} - -// Find all failing assumptions starting from the one on the assumption -// stack with the lowest decision level. This goes back to MiniSAT and is -// called 'analyze_final' there. - -void Internal::failing () { - - START (analyze); - - LOG ("analyzing failing assumptions"); - - CADICAL_assert (analyzed.empty ()); - CADICAL_assert (clause.empty ()); - CADICAL_assert (lrat_chain.empty ()); - CADICAL_assert (!marked_failed); - CADICAL_assert (!conflict_id); - - if (!unsat_constraint) { - // Search for failing assumptions in the (internal) assumption stack. - - // There are in essence three cases: (1) An assumption is falsified on - // the root-level and then 'failed_unit' is set to that assumption, (2) - // two clashing assumptions are assumed and then 'failed_clashing' is - // set to the second assumed one, or otherwise (3) there is a failing - // assumption 'first_failed' with minimum (non-zero) decision level - // 'failed_level'. - - int failed_unit = 0; - int failed_clashing = 0; - int first_failed = 0; - int failed_level = INT_MAX; - int efailed = 0; - - for (auto &elit : external->assumptions) { - int lit = external->e2i[abs (elit)]; - if (elit < 0) - lit = -lit; - if (val (lit) >= 0) - continue; - const Var &v = var (lit); - if (!v.level) { - failed_unit = lit; - efailed = elit; - break; - } - if (failed_clashing) - continue; - if (v.reason == external_reason) { - Var &ev = var (lit); - ev.reason = learn_external_reason_clause (-lit); - if (!ev.reason) { - ev.level = 0; - failed_unit = lit; - efailed = elit; - break; - } - ev.level = 0; - // Recalculate assignment level - for (const auto &other : *ev.reason) { - if (other == -lit) - continue; - CADICAL_assert (val (other)); - int tmp = var (other).level; - if (tmp > ev.level) - ev.level = tmp; - } - if (!ev.level) { - failed_unit = lit; - efailed = elit; - break; - } - } - CADICAL_assert (v.reason != external_reason); - if (!v.reason) { - failed_clashing = lit; - efailed = elit; - } else if (!first_failed || v.level < failed_level) { - first_failed = lit; - efailed = elit; - failed_level = v.level; - } - } - - CADICAL_assert (clause.empty ()); - - // Get the 'failed' assumption from one of the three cases. - int failed; - if (failed_unit) - failed = failed_unit; - else if (failed_clashing) - failed = failed_clashing; - else - failed = first_failed; - CADICAL_assert (failed); - CADICAL_assert (efailed); - - // In any case mark literal 'failed' as failed assumption. - { - Flags &f = flags (failed); - const unsigned bit = bign (failed); - CADICAL_assert (!(f.failed & bit)); - f.failed |= bit; - } - - // First case (1). - if (failed_unit) { - CADICAL_assert (failed == failed_unit); - LOG ("root-level falsified assumption %d", failed); - if (proof) { - if (lrat) { - unsigned eidx = (efailed > 0) + 2u * (unsigned) abs (efailed); - CADICAL_assert ((size_t) eidx < external->ext_units.size ()); - const int64_t id = external->ext_units[eidx]; - if (id) { - lrat_chain.push_back (id); - } else { - int64_t id = unit_id (-failed_unit); - lrat_chain.push_back (id); - } - } - proof->add_assumption_clause (++clause_id, -efailed, lrat_chain); - conclusion.push_back (clause_id); - lrat_chain.clear (); - } - goto DONE; - } - - // Second case (2). - if (failed_clashing) { - CADICAL_assert (failed == failed_clashing); - LOG ("clashing assumptions %d and %d", failed, -failed); - Flags &f = flags (-failed); - const unsigned bit = bign (-failed); - CADICAL_assert (!(f.failed & bit)); - f.failed |= bit; - if (proof) { - vector clash = {externalize (failed), externalize (-failed)}; - proof->add_assumption_clause (++clause_id, clash, lrat_chain); - conclusion.push_back (clause_id); - } - goto DONE; - } - - // Fall through to third case (3). - LOG ("starting with assumption %d falsified on minimum decision level " - "%d", - first_failed, failed_level); - - CADICAL_assert (first_failed); - CADICAL_assert (failed_level > 0); - - // The 'analyzed' stack serves as working stack for a BFS through the - // implication graph until decisions, which are all assumptions, or - // units are reached. This is simpler than corresponding code in - // 'analyze'. - { - LOG ("failed assumption %d", first_failed); - Flags &f = flags (first_failed); - CADICAL_assert (!f.seen); - f.seen = true; - CADICAL_assert (f.failed & bign (first_failed)); - analyzed.push_back (-first_failed); - clause.push_back (-first_failed); - } - } else { - // unsat_constraint - // The assumptions necessary to fail each literal in the constraint are - // collected. - for (auto lit : constraint) { - lit *= -1; - CADICAL_assert (lit != INT_MIN); - flags (lit).seen = true; - analyzed.push_back (lit); - } - } - - { - // used for unsat_constraint lrat - vector> constraint_chains; - vector> constraint_clauses; - vector sum_constraints; - vector econstraints; - for (auto &elit : external->constraint) { - int lit = external->e2i[abs (elit)]; - if (elit < 0) - lit = -lit; - if (!lit) - continue; - Flags &f = flags (lit); - if (f.seen) - continue; - if (std::find (econstraints.begin (), econstraints.end (), elit) != - econstraints.end ()) - continue; - econstraints.push_back (elit); - } - - // no LRAT do bfs as it was before - if (!lrat) { - size_t next = 0; - while (next < analyzed.size ()) { - const int lit = analyzed[next++]; - CADICAL_assert (val (lit) > 0); - Var &v = var (lit); - if (!v.level) - continue; - if (v.reason == external_reason) { - v.reason = wrapped_learn_external_reason_clause (lit); - if (!v.reason) { - v.level = 0; - continue; - } - } - CADICAL_assert (v.reason != external_reason); - if (v.reason) { - CADICAL_assert (v.level); - LOG (v.reason, "analyze reason"); - for (const auto &other : *v.reason) { - Flags &f = flags (other); - if (f.seen) - continue; - f.seen = true; - CADICAL_assert (val (other) < 0); - analyzed.push_back (-other); - } - } else { - CADICAL_assert (assumed (lit)); - LOG ("failed assumption %d", lit); - clause.push_back (-lit); - Flags &f = flags (lit); - const unsigned bit = bign (lit); - CADICAL_assert (!(f.failed & bit)); - f.failed |= bit; - } - } - clear_analyzed_literals (); - } else if (!unsat_constraint) { // LRAT for case (3) - CADICAL_assert (clause.size () == 1); - const int lit = clause[0]; - Var &v = var (lit); - CADICAL_assert (v.reason); - if (v.reason == external_reason) { // does this even happen? - v.reason = wrapped_learn_external_reason_clause (lit); - } - CADICAL_assert (v.reason != external_reason); - if (v.reason) - assume_analyze_reason (lit, v.reason); - else { - int64_t id = unit_id (lit); - lrat_chain.push_back (id); - } - for (auto &lit : clause) { - Flags &f = flags (lit); - const unsigned bit = bign (-lit); - if (!(f.failed & bit)) - f.failed |= bit; - } - clear_analyzed_literals (); - } else { // LRAT for unsat_constraint - CADICAL_assert (clause.empty ()); - clear_analyzed_literals (); - for (auto lit : constraint) { - // make sure nothing gets marked failed twice - // also might shortcut the case where - // lrat_chain is empty because clause is tautological - CADICAL_assert (lit != INT_MIN); - assume_analyze_literal (lit); - vector empty; - vector empty2; - constraint_chains.push_back (empty); - constraint_clauses.push_back (empty2); - for (auto ign : clause) { - constraint_clauses.back ().push_back (ign); - Flags &f = flags (ign); - const unsigned bit = bign (-ign); - if (!(f.failed & bit)) { - sum_constraints.push_back (ign); - CADICAL_assert (!(f.failed & bit)); - f.failed |= bit; - } - } - clause.clear (); - clear_analyzed_literals (); - for (auto p : lrat_chain) { - constraint_chains.back ().push_back (p); - } - lrat_chain.clear (); - } - for (auto &lit : sum_constraints) - clause.push_back (lit); - } - clear_analyzed_literals (); - - // Doing clause minimization here does not do anything because - // the clause already contains only one literal of each level - // and minimization can never reduce the number of levels - - VERBOSE (1, "found %zd failed assumptions %.0f%%", clause.size (), - percent (clause.size (), assumptions.size ())); - - // We do not actually need to learn this clause, since the conflict is - // forced already by some other clauses. There is also no bumping - // of variables nor clauses necessary. But we still want to check - // correctness of the claim that the determined subset of failing - // assumptions are a high-level core or equivalently their negations - // form a unit-implied clause. - // - if (!unsat_constraint) { - external->check_learned_clause (); - if (proof) { - vector eclause; - for (auto &lit : clause) - eclause.push_back (externalize (lit)); - proof->add_assumption_clause (++clause_id, eclause, lrat_chain); - conclusion.push_back (clause_id); - } - } else { - CADICAL_assert (!lrat || (constraint.size () == constraint_clauses.size () && - constraint.size () == constraint_chains.size ())); - for (auto p = constraint.rbegin (); p != constraint.rend (); p++) { - const auto &lit = *p; - if (lrat) { - clause.clear (); - for (auto &ign : constraint_clauses.back ()) - clause.push_back (ign); - constraint_clauses.pop_back (); - } - clause.push_back (-lit); - external->check_learned_clause (); - if (proof) { - if (lrat) { - for (auto p : constraint_chains.back ()) { - lrat_chain.push_back (p); - } - constraint_chains.pop_back (); - LOG (lrat_chain, "assume proof chain with constraints"); - } - vector eclause; - for (auto &lit : clause) - eclause.push_back (externalize (lit)); - proof->add_assumption_clause (++clause_id, eclause, lrat_chain); - conclusion.push_back (clause_id); - lrat_chain.clear (); - } - clause.pop_back (); - } - if (proof) { - for (auto &elit : econstraints) { - if (lrat) { - unsigned eidx = (elit > 0) + 2u * (unsigned) abs (elit); - CADICAL_assert ((size_t) eidx < external->ext_units.size ()); - const int64_t id = external->ext_units[eidx]; - if (id) { - lrat_chain.push_back (id); - } else { - int lit = external->e2i[abs (elit)]; - if (elit < 0) - lit = -lit; - int64_t id = unit_id (-lit); - lrat_chain.push_back (id); - } - } - proof->add_assumption_clause (++clause_id, -elit, lrat_chain); - conclusion.push_back (clause_id); - lrat_chain.clear (); - } - } - } - lrat_chain.clear (); - clause.clear (); - } - -DONE: - - STOP (analyze); -} - -bool Internal::failed (int lit) { - if (!marked_failed) { - if (!conflict_id) - failing (); - marked_failed = true; - } - conclude_unsat (); - Flags &f = flags (lit); - const unsigned bit = bign (lit); - return (f.failed & bit) != 0; -} - -void Internal::conclude_unsat () { - if (!proof || concluded) - return; - concluded = true; - if (!marked_failed) { - CADICAL_assert (conclusion.empty ()); - if (!conflict_id) - failing (); - marked_failed = true; - } - ConclusionType con; - if (conflict_id) - con = CONFLICT; - else if (unsat_constraint) - con = CONSTRAINT; - else - con = ASSUMPTIONS; - proof->conclude_unsat (con, conclusion); -} - -void Internal::reset_concluded () { - if (proof) - proof->reset_assumptions (); - if (concluded) { - LOG ("reset concluded"); - concluded = false; - } - if (conflict_id) { - CADICAL_assert (conclusion.size () == 1); - return; - } - conclusion.clear (); -} - -// Add the start of each incremental phase (leaving the state -// 'UNSATISFIABLE' actually) we reset all assumptions. - -void Internal::reset_assumptions () { - for (const auto &lit : assumptions) { - Flags &f = flags (lit); - const unsigned char bit = bign (lit); - f.assumed &= ~bit; - f.failed &= ~bit; - melt (lit); - } - LOG ("cleared %zd assumptions", assumptions.size ()); - assumptions.clear (); - marked_failed = true; -} - -struct sort_assumptions_positive_rank { - Internal *internal; - - // Decision level could be 'INT_MAX' and thus 'level + 1' could overflow. - // Therefore we carefully have to use 'unsigned' for levels below. - - const unsigned max_level; - - sort_assumptions_positive_rank (Internal *s) - : internal (s), max_level (s->level + 1u) {} - - typedef uint64_t Type; - - // Set assumptions first, then sorted by position on the trail - // unset literals are sorted by literal value. - - Type operator() (const int &a) const { - const int val = internal->val (a); - const bool assigned = (val != 0); - const Var &v = internal->var (a); - uint64_t res = (assigned ? (unsigned) v.level : max_level); - res <<= 32; - res |= (assigned ? v.trail : abs (a)); - return res; - } -}; - -struct sort_assumptions_smaller { - Internal *internal; - sort_assumptions_smaller (Internal *s) : internal (s) {} - bool operator() (const int &a, const int &b) const { - return sort_assumptions_positive_rank (internal) (a) < - sort_assumptions_positive_rank (internal) (b); - } -}; - -// Sort the assumptions by the current position on the trail and backtrack -// to the first place where the assumptions and the current trail differ. - -void Internal::sort_and_reuse_assumptions () { - CADICAL_assert (opts.ilbassumptions); - if (assumptions.empty ()) - return; - MSORT (opts.radixsortlim, assumptions.begin (), assumptions.end (), - sort_assumptions_positive_rank (this), - sort_assumptions_smaller (this)); - - unsigned max_level = 0; - // assumptions are sorted by level, with unset at the end - for (auto lit : assumptions) { - if (val (lit)) - max_level = var (lit).level; - else - break; - } - - const unsigned size = min (level + 1u, max_level + 1); - CADICAL_assert ((size_t) level == control.size () - 1); - LOG (assumptions, "sorted assumptions"); - int target = 0; - for (unsigned i = 1, j = 0; i < size;) { - const Level &l = control[i]; - const int lit = l.decision; - const int alit = assumptions[j]; - const int lev = i; - target = lev; - if (val (alit) > 0 && - var (alit).level < lev) { // we can ignore propagated assumptions - LOG ("ILB skipping propagation %d", alit); - ++j; - continue; - } - if (!lit) { // skip fake decisions - target = lev - 1; - break; - } - ++i, ++j; - CADICAL_assert (var (lit).level == lev); - if (l.decision == alit) { - continue; - } - target = lev - 1; - LOG ("first different literal %d on the trail and %d from the " - "assumptions", - lit, alit); - break; - } - if (target < level) - backtrack (target); - LOG ("assumptions allow for reuse of trail up to level %d", level); - // COVER (target > 1); - if ((size_t) level > assumptions.size ()) - stats.assumptionsreused += assumptions.size (); - else - stats.assumptionsreused += level; -} -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_averages.cpp b/src/sat/cadical/cadical_averages.cpp deleted file mode 100644 index d40a98cdb..000000000 --- a/src/sat/cadical/cadical_averages.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -void Internal::init_averages () { - - LOG ("initializing averages"); - - INIT_EMA (averages.current.jump, opts.emajump); - INIT_EMA (averages.current.level, opts.emalevel); - INIT_EMA (averages.current.size, opts.emasize); - - INIT_EMA (averages.current.glue.fast, opts.emagluefast); - INIT_EMA (averages.current.glue.slow, opts.emaglueslow); - - INIT_EMA (averages.current.decisions, opts.emadecisions); - - INIT_EMA (averages.current.trail.fast, opts.ematrailfast); - INIT_EMA (averages.current.trail.slow, opts.ematrailslow); - - CADICAL_assert (!averages.swapped); -} - -void Internal::swap_averages () { - LOG ("saving current averages"); - swap (averages.current, averages.saved); - if (!averages.swapped) - init_averages (); - else - LOG ("swapping in previously saved averages"); - averages.swapped++; -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_backtrack.cpp b/src/sat/cadical/cadical_backtrack.cpp deleted file mode 100644 index b3c519ba2..000000000 --- a/src/sat/cadical/cadical_backtrack.cpp +++ /dev/null @@ -1,179 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -// The global assignment stack can only be (partially) reset through -// 'backtrack' which is the only function using 'unassign' (inlined and thus -// local to this file). It turns out that 'unassign' does not need a -// specialization for 'probe' nor 'vivify' and thus it is shared. - -inline void Internal::unassign (int lit) { - CADICAL_assert (val (lit) > 0); - set_val (lit, 0); - - int idx = vidx (lit); - LOG ("unassign %d @ %d", lit, var (idx).level); - num_assigned--; - - // In the standard EVSIDS variable decision heuristic of MiniSAT, we need - // to push variables which become unassigned back to the heap. - // - if (!scores.contains (idx)) - scores.push_back (idx); - - // For VMTF we need to update the 'queue.unassigned' pointer in case this - // variable sits after the variable to which 'queue.unassigned' currently - // points. See our SAT'15 paper for more details on this aspect. - // - if (queue.bumped < btab[idx]) - update_queue_unassigned (idx); -} - -/*------------------------------------------------------------------------*/ - -// Update the current target maximum assignment and also the very best -// assignment. Whether a trail produces a conflict is determined during -// propagation. Thus that all functions in the 'search' loop after -// propagation can assume that 'no_conflict_until' is valid. If a conflict -// is found then the trail before the last decision is used (see the end of -// 'propagate'). During backtracking we can then save this largest -// propagation conflict free assignment. It is saved as both 'target' -// assignment for picking decisions in 'stable' mode and if it is the -// largest ever such assignment also as 'best' assignment. This 'best' -// assignment can then be used in future stable decisions after the next -// 'rephase_best' overwrites saved phases with it. - -void Internal::update_target_and_best () { - - bool reset = (rephased && stats.conflicts > last.rephase.conflicts); - - if (reset) { - target_assigned = 0; - if (rephased == 'B') - best_assigned = 0; // update it again - } - - if (no_conflict_until > target_assigned) { - copy_phases (phases.target); - target_assigned = no_conflict_until; - LOG ("new target trail level %zu", target_assigned); - } - - if (no_conflict_until > best_assigned) { - copy_phases (phases.best); - best_assigned = no_conflict_until; - LOG ("new best trail level %zu", best_assigned); - } - - if (reset) { - report (rephased); - rephased = 0; - } -} - -/*------------------------------------------------------------------------*/ - -void Internal::backtrack (int new_level) { - CADICAL_assert (new_level <= level); - if (new_level == level) - return; - - update_target_and_best (); - backtrack_without_updating_phases (new_level); -} - -void Internal::backtrack_without_updating_phases (int new_level) { - - CADICAL_assert (new_level <= level); - if (new_level == level) - return; - - stats.backtracks++; - - CADICAL_assert (num_assigned == trail.size ()); - - const size_t assigned = control[new_level + 1].trail; - - LOG ("backtracking to decision level %d with decision %d and trail %zd", - new_level, control[new_level].decision, assigned); - - const size_t end_of_trail = trail.size (); - size_t i = assigned, j = i; - -#ifdef LOGGING - int unassigned = 0; -#endif - int reassigned = 0; - - notify_backtrack (new_level); - if (external_prop && !external_prop_is_lazy && !private_steps && - notified > assigned) { - LOG ("external propagator is notified about some unassignments (trail: " - "%zd, notified: %zd).", - trail.size (), notified); - notified = assigned; - } - - while (i < end_of_trail) { - int lit = trail[i++]; - Var &v = var (lit); - if (v.level > new_level) { - unassign (lit); -#ifdef LOGGING - unassigned++; -#endif - } else { - // This is the essence of the SAT'18 paper on chronological - // backtracking. It is possible to just keep out-of-order assigned - // literals on the trail without breaking the solver (after some - // modifications to 'analyze' - see 'opts.chrono' guarded code there). - CADICAL_assert (opts.chrono || external_prop || did_external_prop); -#ifdef LOGGING - if (!v.level) - LOG ("reassign %d @ 0 unit clause %d", lit, lit); - else - LOG (v.reason, "reassign %d @ %d", lit, v.level); -#endif - trail[j] = lit; - v.trail = j++; - reassigned++; - } - } - trail.resize (j); - LOG ("unassigned %d literals %.0f%%", unassigned, - percent (unassigned, unassigned + reassigned)); - LOG ("reassigned %d literals %.0f%%", reassigned, - percent (reassigned, unassigned + reassigned)); - - if (propagated > assigned) - propagated = assigned; - if (propagated2 > assigned) - propagated2 = assigned; - if (no_conflict_until > assigned) - no_conflict_until = assigned; - - propergated = 0; // Always go back to root-level. - - CADICAL_assert (notified <= assigned + reassigned); - if (reassigned) { - notify_assignments (); - } - - control.resize (new_level + 1); - level = new_level; - if (tainted_literal) { - CADICAL_assert (opts.ilb); - if (!val (tainted_literal)) { - tainted_literal = 0; - } - } - CADICAL_assert (num_assigned == trail.size ()); -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_backward.cpp b/src/sat/cadical/cadical_backward.cpp deleted file mode 100644 index 5778029a5..000000000 --- a/src/sat/cadical/cadical_backward.cpp +++ /dev/null @@ -1,237 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -/*------------------------------------------------------------------------*/ - -// Provide eager backward subsumption for resolved clauses. - -// The eliminator maintains a queue of clauses that are new and have to be -// checked to subsume or strengthen other (longer or same size) clauses. - -void Eliminator::enqueue (Clause *c) { - if (!internal->opts.elimbackward) - return; - if (c->enqueued) - return; - LOG (c, "backward enqueue"); - backward.push (c); - c->enqueued = true; -} - -Clause *Eliminator::dequeue () { - if (backward.empty ()) - return 0; - Clause *res = backward.front (); - backward.pop (); - CADICAL_assert (res->enqueued); - res->enqueued = false; - LOG (res, "backward dequeue"); - return res; -} - -Eliminator::~Eliminator () { - while (dequeue ()) - ; -} - -/*------------------------------------------------------------------------*/ - -void Internal::elim_backward_clause (Eliminator &eliminator, Clause *c) { - CADICAL_assert (opts.elimbackward); - CADICAL_assert (!c->redundant); - if (c->garbage) - return; - LOG (c, "attempting backward subsumption and strengthening with"); - size_t len = UINT_MAX; - unsigned size = 0; - int best = 0; - bool satisfied = false; - CADICAL_assert (mini_chain.empty ()); - for (const auto &lit : *c) { - const signed char tmp = val (lit); - if (tmp > 0) { - satisfied = true; - break; - } - if (tmp < 0) - continue; - size_t l = occs (lit).size (); - LOG ("literal %d occurs %zd times", lit, l); - if (l < len) - best = lit, len = l; - mark (lit); - size++; - } - if (satisfied) { - LOG ("clause actually already satisfied"); - elim_update_removed_clause (eliminator, c); - mark_garbage (c); - } else if (len > (size_t) opts.elimocclim) { - LOG ("skipping backward subsumption due to too many occurrences"); - } else { - CADICAL_assert (len); - LOG ("literal %d has smallest number of occurrences %zd", best, len); - LOG ("marked %d literals in clause of size %d", size, c->size); - for (auto &d : occs (best)) { - if (d == c) - continue; - if (d->garbage) - continue; - if ((unsigned) d->size < size) - continue; - int negated = 0; - unsigned found = 0; - satisfied = false; - for (const auto &lit : *d) { - signed char tmp = val (lit); - if (tmp > 0) { - satisfied = true; - break; - } - if (tmp < 0) - continue; - tmp = marked (lit); - if (!tmp) - continue; - if (tmp < 0) { - if (negated) { - size = UINT_MAX; - break; - } else - negated = lit; - } - if (++found == size) - break; - } - if (satisfied) { - LOG (d, "found satisfied clause"); - elim_update_removed_clause (eliminator, d); - mark_garbage (d); - } else if (found == size) { - if (!negated) { - LOG (d, "found subsumed clause"); - elim_update_removed_clause (eliminator, d); - mark_garbage (d); - stats.subsumed++; - stats.elimbwsub++; - } else { - int unit = 0; - CADICAL_assert (minimize_chain.empty ()); - CADICAL_assert (analyzed.empty ()); - CADICAL_assert (lrat_chain.empty ()); - // figure out wether we strengthen c or get a new unit - for (const auto &lit : *d) { - const signed char tmp = val (lit); - if (tmp < 0) { - if (!lrat) - continue; - Flags &f = flags (lit); - CADICAL_assert (!f.seen); - if (f.seen) - continue; - f.seen = true; - analyzed.push_back (lit); - continue; - } - if (tmp > 0) { - satisfied = true; - break; - } - if (lit == negated) - continue; - if (unit) { - unit = INT_MIN; - continue; // needed to guarantee d is not satsified - } else - unit = lit; - } - if (lrat && !satisfied) { - // if we found a unit we need to add all unit ids from - // {c\d}U{d\c} otherwise just the unit ids from {c\d} - for (const auto &lit : *c) { - const signed char tmp = val (lit); - CADICAL_assert (tmp <= 0); - if (tmp >= 0) - continue; - Flags &f = flags (lit); - if (f.seen && unit && unit == INT_MIN) { - f.seen = false; - continue; - } else if (!f.seen) { - f.seen = true; - analyzed.push_back (lit); - } - } - if (unit == INT_MIN) { // we do not need units from {d\c} - for (const auto &lit : *d) { - flags (lit).seen = false; - } - } - for (const auto &lit : analyzed) { - Flags &f = flags (lit); - if (!f.seen) { - f.seen = true; - continue; - } - int64_t id = unit_id (-lit); - lrat_chain.push_back (id); - } - clear_analyzed_literals (); - lrat_chain.push_back (d->id); - lrat_chain.push_back (c->id); - } else if (lrat) - clear_analyzed_literals (); - if (satisfied) { - CADICAL_assert (lrat_chain.empty ()); - mark_garbage (d); - elim_update_removed_clause (eliminator, d); - } else if (unit && unit != INT_MIN) { - CADICAL_assert (unit); - LOG (d, "unit %d through hyper unary resolution with", unit); - assign_unit (unit); - elim_propagate (eliminator, unit); - lrat_chain.clear (); - break; - } else if (occs (negated).size () <= (size_t) opts.elimocclim) { - strengthen_clause (d, negated); - remove_occs (occs (negated), d); - elim_update_removed_lit (eliminator, negated); - stats.elimbwstr++; - CADICAL_assert (negated != best); - eliminator.enqueue (d); - } - lrat_chain.clear (); - } - } - } - } - mini_chain.clear (); - unmark (c); -} - -/*------------------------------------------------------------------------*/ - -void Internal::elim_backward_clauses (Eliminator &eliminator) { - if (!opts.elimbackward) { - CADICAL_assert (eliminator.backward.empty ()); - return; - } - START (backward); - LOG ("attempting backward subsumption and strengthening with %zd clauses", - eliminator.backward.size ()); - Clause *c; - while (!unsat && (c = eliminator.dequeue ())) - elim_backward_clause (eliminator, c); - STOP (backward); -} - -/*------------------------------------------------------------------------*/ - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_bins.cpp b/src/sat/cadical/cadical_bins.cpp deleted file mode 100644 index fba96f216..000000000 --- a/src/sat/cadical/cadical_bins.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -/*------------------------------------------------------------------------*/ - -// Binary implication graph lists. - -void Internal::init_bins () { - CADICAL_assert (big.empty ()); - if (big.size () < 2 * vsize) - big.resize (2 * vsize, Bins ()); - LOG ("initialized binary implication graph"); -} - -void Internal::reset_bins () { - CADICAL_assert (!big.empty ()); - erase_vector (big); - LOG ("reset binary implication graph"); -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_block.cpp b/src/sat/cadical/cadical_block.cpp deleted file mode 100644 index 12f852f08..000000000 --- a/src/sat/cadical/cadical_block.cpp +++ /dev/null @@ -1,830 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -/*------------------------------------------------------------------------*/ - -// This implements an inprocessing version of blocked clause elimination and -// is assumed to be triggered just before bounded variable elimination. It -// has a separate 'block' flag while variable elimination uses 'elim'. -// Thus it only tries to block clauses on a literal which was removed in an -// irredundant clause in negated form before and has not been tried to use -// as blocking literal since then. - -/*------------------------------------------------------------------------*/ - -inline bool block_more_occs_size::operator() (unsigned a, unsigned b) { - size_t s = internal->noccs (-internal->u2i (a)); - size_t t = internal->noccs (-internal->u2i (b)); - if (s > t) - return true; - if (s < t) - return false; - s = internal->noccs (internal->u2i (a)); - t = internal->noccs (internal->u2i (b)); - if (s > t) - return true; - if (s < t) - return false; - return a > b; -} - -/*------------------------------------------------------------------------*/ - -// Determine whether 'c' is blocked on 'lit', by first marking all its -// literals and then checking all resolvents with negative clauses (with -// '-lit') are tautological. We use a move-to-front scheme for both the -// occurrence list of negative clauses (with '-lit') and then for literals -// within each such clause. The clause move-to-front scheme has the goal to -// find non-tautological clauses faster in the future, while the literal -// move-to-front scheme has the goal to faster find the matching literal, -// which makes the resolvent tautological (again in the future). - -bool Internal::is_blocked_clause (Clause *c, int lit) { - - LOG (c, "trying to block on %d", lit); - - CADICAL_assert (c->size >= opts.blockminclslim); - CADICAL_assert (c->size <= opts.blockmaxclslim); - CADICAL_assert (active (lit)); - CADICAL_assert (!val (lit)); - CADICAL_assert (!c->garbage); - CADICAL_assert (!c->redundant); - CADICAL_assert (!level); - - mark (c); // First mark all literals in 'c'. - - Occs &os = occs (-lit); - LOG ("resolving against at most %zd clauses with %d", os.size (), -lit); - - bool res = true; // Result is true if all resolvents tautological. - - // Can not use 'auto' here since we update 'os' during traversal. - // - const auto end_of_os = os.end (); - auto i = os.begin (); - - Clause *prev_d = 0; // Previous non-tautological clause. - - for (; i != end_of_os; i++) { - // Move the first clause with non-tautological resolvent to the front of - // the occurrence list to improve finding it faster later. - // - Clause *d = *i; - - CADICAL_assert (!d->garbage); - CADICAL_assert (!d->redundant); - CADICAL_assert (d->size <= opts.blockmaxclslim); - - *i = prev_d; // Move previous non-tautological clause - prev_d = d; // backwards but remember clause at this position. - - LOG (d, "resolving on %d against", lit); - stats.blockres++; - - int prev_other = 0; // Previous non-tautological literal. - - // No 'auto' since we update literals of 'd' during traversal. - // - const const_literal_iterator end_of_d = d->end (); - literal_iterator l; - - for (l = d->begin (); l != end_of_d; l++) { - // Same move-to-front mechanism for literals within a clause. It - // moves the first negatively marked literal to the front to find it - // faster in the future. - // - const int other = *l; - *l = prev_other; - prev_other = other; - if (other == -lit) - continue; - CADICAL_assert (other != lit); - CADICAL_assert (active (other)); - CADICAL_assert (!val (other)); - if (marked (other) < 0) { - LOG ("found tautological literal %d", other); - d->literals[0] = other; // Move to front of 'd'. - break; - } - } - - if (l == end_of_d) { - LOG ("no tautological literal found"); - // - // Since we did not find a tautological literal we restore the old - // order of literals in the clause. - // - const const_literal_iterator begin_of_d = d->begin (); - while (l-- != begin_of_d) { - const int other = *l; - *l = prev_other; - prev_other = other; - } - res = false; // Now 'd' is a witness that 'c' is not blocked. - os[0] = d; // Move it to the front of the occurrence list. - break; - } - } - unmark (c); // ... all literals of the candidate clause. - - // If all resolvents are tautological and thus the clause is blocked we - // restore the old order of clauses in the occurrence list of '-lit'. - // - if (res) { - CADICAL_assert (i == end_of_os); - const auto boc = os.begin (); - while (i != boc) { - Clause *d = *--i; - *i = prev_d; - prev_d = d; - } - } - - return res; -} - -/*------------------------------------------------------------------------*/ - -void Internal::block_schedule (Blocker &blocker) { - // Set skip flags for all literals in too large clauses. - // - for (const auto &c : clauses) { - - if (c->garbage) - continue; - if (c->redundant) - continue; - if (c->size <= opts.blockmaxclslim) - continue; - - for (const auto &lit : *c) - mark_skip (-lit); - } - - // Connect all literal occurrences in irredundant clauses. - // - for (const auto &c : clauses) { - - if (c->garbage) - continue; - if (c->redundant) - continue; - - for (const auto &lit : *c) { - CADICAL_assert (active (lit)); - CADICAL_assert (!val (lit)); - occs (lit).push_back (c); - } - } - - // We establish the invariant that 'noccs' gives the number of actual - // occurrences of 'lit' in non-garbage clauses, while 'occs' might still - // refer to garbage clauses, thus 'noccs (lit) <= occs (lit).size ()'. It - // is expensive to remove references to garbage clauses from 'occs' during - // blocked clause elimination, but decrementing 'noccs' is cheap. - - for (auto lit : lits) { - if (!active (lit)) - continue; - CADICAL_assert (!val (lit)); - Occs &os = occs (lit); - noccs (lit) = os.size (); - } - - // Now we fill the schedule (priority queue) of candidate literals to be - // tried as blocking literals. It is probably slightly faster to do this - // in one go after all occurrences have been determined, instead of - // filling the priority queue during pushing occurrences. Filling the - // schedule can not be fused with the previous loop (easily) since we - // first have to initialize 'noccs' for both 'lit' and '-lit'. - -#ifndef CADICAL_QUIET - int skipped = 0; -#endif - - for (auto idx : vars) { - if (!active (idx)) - continue; - if (frozen (idx)) { -#ifndef CADICAL_QUIET - skipped += 2; -#endif - continue; - } - CADICAL_assert (!val (idx)); - for (int sign = -1; sign <= 1; sign += 2) { - const int lit = sign * idx; - if (marked_skip (lit)) { -#ifndef CADICAL_QUIET - skipped++; -#endif - continue; - } - if (!marked_block (lit)) - continue; - unmark_block (lit); - LOG ("scheduling %d with %" PRId64 " positive and %" PRId64 - " negative occurrences", - lit, noccs (lit), noccs (-lit)); - blocker.schedule.push_back (vlit (lit)); - } - } - - PHASE ("block", stats.blockings, - "scheduled %zd candidate literals %.2f%% (%d skipped %.2f%%)", - blocker.schedule.size (), - percent (blocker.schedule.size (), 2.0 * active ()), skipped, - percent (skipped, 2.0 * active ())); -} - -/*------------------------------------------------------------------------*/ - -// A literal is pure if it only occurs positive. Then all clauses in which -// it occurs are blocked on it. This special case can be implemented faster -// than trying to block literals with at least one negative occurrence and -// is thus handled separately. It also allows to avoid pushing blocked -// clauses onto the extension stack. - -void Internal::block_pure_literal (Blocker &blocker, int lit) { - if (frozen (lit)) - return; - CADICAL_assert (active (lit)); - - Occs &pos = occs (lit); - Occs &nos = occs (-lit); - - CADICAL_assert (!noccs (-lit)); -#ifndef CADICAL_NDEBUG - for (const auto &c : nos) - CADICAL_assert (c->garbage); -#endif - stats.blockpurelits++; - LOG ("found pure literal %d", lit); -#ifdef LOGGING - int64_t pured = 0; -#endif - for (const auto &c : pos) { - if (c->garbage) - continue; - CADICAL_assert (!c->redundant); - LOG (c, "pure literal %d in", lit); - blocker.reschedule.push_back (c); - if (proof) { - proof->weaken_minus (c); - } - external->push_clause_on_extension_stack (c, lit); - stats.blockpured++; - mark_garbage (c); -#ifdef LOGGING - pured++; -#endif - } - - erase_vector (pos); - erase_vector (nos); - - mark_pure (lit); - stats.blockpured++; - LOG ("blocking %" PRId64 " clauses on pure literal %d", pured, lit); -} - -/*------------------------------------------------------------------------*/ - -// If there is only one negative clause with '-lit' it is faster to mark it -// instead of marking all the positive clauses with 'lit' one after the -// other and then resolving against the negative clause. - -void Internal::block_literal_with_one_negative_occ (Blocker &blocker, - int lit) { - CADICAL_assert (active (lit)); - CADICAL_assert (!frozen (lit)); - CADICAL_assert (noccs (lit) > 0); - CADICAL_assert (noccs (-lit) == 1); - - Occs &nos = occs (-lit); - CADICAL_assert (nos.size () >= 1); - - Clause *d = 0; - for (const auto &c : nos) { - if (c->garbage) - continue; - CADICAL_assert (!d); - d = c; -#ifndef CADICAL_NDEBUG - break; -#endif - } - CADICAL_assert (d); - nos.resize (1); - nos[0] = d; - - if (d && d->size > opts.blockmaxclslim) { - LOG (d, "skipped common antecedent"); - return; - } - - CADICAL_assert (!d->garbage); - CADICAL_assert (!d->redundant); - CADICAL_assert (d->size <= opts.blockmaxclslim); - - LOG (d, "common %d antecedent", lit); - mark (d); - int64_t blocked = 0; -#ifdef LOGGING - int64_t skipped = 0; -#endif - Occs &pos = occs (lit); - - // Again no 'auto' since 'pos' is update during traversal. - // - const auto eop = pos.end (); - auto j = pos.begin (), i = j; - - for (; i != eop; i++) { - Clause *c = *j++ = *i; - - if (c->garbage) { - j--; - continue; - } - if (c->size > opts.blockmaxclslim) { -#ifdef LOGGING - skipped++; -#endif - continue; - } - if (c->size < opts.blockminclslim) { -#ifdef LOGGING - skipped++; -#endif - continue; - } - - LOG (c, "trying to block on %d", lit); - - // We use the same literal move-to-front strategy as in - // 'is_blocked_clause'. See there for more explanations. - - int prev_other = 0; // Previous non-tautological literal. - - // No 'auto' since literals of 'c' are updated during traversal. - // - const const_literal_iterator end_of_c = c->end (); - literal_iterator l; - - for (l = c->begin (); l != end_of_c; l++) { - const int other = *l; - *l = prev_other; - prev_other = other; - if (other == lit) - continue; - CADICAL_assert (other != -lit); - CADICAL_assert (active (other)); - CADICAL_assert (!val (other)); - if (marked (other) < 0) { - LOG ("found tautological literal %d", other); - c->literals[0] = other; // Move to front of 'c'. - break; - } - } - - if (l == end_of_c) { - LOG ("no tautological literal found"); - - // Restore old literal order in the clause because. - - const const_literal_iterator begin_of_c = c->begin (); - while (l-- != begin_of_c) { - const int other = *l; - *l = prev_other; - prev_other = other; - } - - continue; // ... with next candidate 'c' in 'pos'. - } - - blocked++; - LOG (c, "blocked"); - if (proof) { - proof->weaken_minus (c); - } - external->push_clause_on_extension_stack (c, lit); - blocker.reschedule.push_back (c); - mark_garbage (c); - j--; - } - if (j == pos.begin ()) - erase_vector (pos); - else - pos.resize (j - pos.begin ()); - - stats.blocked += blocked; - LOG ("blocked %" PRId64 " clauses on %d (skipped %" PRId64 ")", blocked, - lit, skipped); - - unmark (d); -} - -/*------------------------------------------------------------------------*/ - -// Determine the set of candidate clauses with 'lit', which are checked to -// be blocked by 'lit'. Filter out too large and small clauses and which do -// not have any negated other literal in any of the clauses with '-lit'. - -size_t Internal::block_candidates (Blocker &blocker, int lit) { - - CADICAL_assert (blocker.candidates.empty ()); - - Occs &pos = occs (lit); // Positive occurrences of 'lit'. - Occs &nos = occs (-lit); - - CADICAL_assert ((size_t) noccs (lit) <= pos.size ()); - CADICAL_assert ((size_t) noccs (-lit) == nos.size ()); // Already flushed. - - // Mark all literals in clauses with '-lit'. Note that 'mark2' uses - // separate bits for 'lit' and '-lit'. - // - for (const auto &c : nos) - mark2 (c); - - const auto eop = pos.end (); - auto j = pos.begin (), i = j; - - for (; i != eop; i++) { - Clause *c = *j++ = *i; - if (c->garbage) { - j--; - continue; - } - CADICAL_assert (!c->redundant); - if (c->size > opts.blockmaxclslim) - continue; - if (c->size < opts.blockminclslim) - continue; - const const_literal_iterator eoc = c->end (); - const_literal_iterator l; - for (l = c->begin (); l != eoc; l++) { - const int other = *l; - if (other == lit) - continue; - CADICAL_assert (other != -lit); - CADICAL_assert (active (other)); - CADICAL_assert (!val (other)); - if (marked2 (-other)) - break; - } - if (l != eoc) - blocker.candidates.push_back (c); - } - if (j == pos.begin ()) - erase_vector (pos); - else - pos.resize (j - pos.begin ()); - - CADICAL_assert (pos.size () == (size_t) noccs (lit)); // Now also flushed. - - for (const auto &c : nos) - unmark (c); - - return blocker.candidates.size (); -} - -/*------------------------------------------------------------------------*/ - -// Try to find a clause with '-lit' which does not have any literal in -// clauses with 'lit'. If such a clause exists no candidate clause can be -// blocked on 'lit' since all candidates would produce a non-tautological -// resolvent with that clause. - -Clause *Internal::block_impossible (Blocker &blocker, int lit) { - CADICAL_assert (noccs (-lit) > 1); - CADICAL_assert (blocker.candidates.size () > 1); - - for (const auto &c : blocker.candidates) - mark2 (c); - - Occs &nos = occs (-lit); - Clause *res = 0; - - for (const auto &c : nos) { - CADICAL_assert (!c->garbage); - CADICAL_assert (!c->redundant); - CADICAL_assert (c->size <= opts.blockmaxclslim); - const const_literal_iterator eoc = c->end (); - const_literal_iterator l; - for (l = c->begin (); l != eoc; l++) { - const int other = *l; - if (other == -lit) - continue; - CADICAL_assert (other != lit); - CADICAL_assert (active (other)); - CADICAL_assert (!val (other)); - if (marked2 (-other)) - break; - } - if (l == eoc) - res = c; - } - - for (const auto &c : blocker.candidates) - unmark (c); - - if (res) { - LOG (res, "common non-tautological resolvent producing"); - blocker.candidates.clear (); - } - - return res; -} - -/*------------------------------------------------------------------------*/ - -// In the general case we have at least two negative occurrences. - -void Internal::block_literal_with_at_least_two_negative_occs ( - Blocker &blocker, int lit) { - CADICAL_assert (active (lit)); - CADICAL_assert (!frozen (lit)); - CADICAL_assert (noccs (lit) > 0); - CADICAL_assert (noccs (-lit) > 1); - - Occs &nos = occs (-lit); - CADICAL_assert ((size_t) noccs (-lit) <= nos.size ()); - - int max_size = 0; - - // Flush all garbage clauses in occurrence list 'nos' of '-lit' and - // determine the maximum size of negative clauses (with '-lit'). - // - const auto eon = nos.end (); - auto j = nos.begin (), i = j; - for (; i != eon; i++) { - Clause *c = *j++ = *i; - if (c->garbage) - j--; - else if (c->size > max_size) - max_size = c->size; - } - if (j == nos.begin ()) - erase_vector (nos); - else - nos.resize (j - nos.begin ()); - - CADICAL_assert (nos.size () == (size_t) noccs (-lit)); - CADICAL_assert (nos.size () > 1); - - // If the maximum size of a negative clause (with '-lit') exceeds the - // maximum clause size limit ignore this candidate literal. - // - if (max_size > opts.blockmaxclslim) { - LOG ("maximum size %d of clauses with %d exceeds clause size limit %d", - max_size, -lit, opts.blockmaxclslim); - return; - } - - LOG ("maximum size %d of clauses with %d", max_size, -lit); - - // We filter candidate clauses with positive occurrence of 'lit' in - // 'blocker.candidates' and return if no candidate clause remains. - // Candidates should be small enough and should have at least one literal - // which occurs negated in one of the clauses with '-lit'. - // - size_t candidates = block_candidates (blocker, lit); - if (!candidates) { - LOG ("no candidate clauses found"); - return; - } - - LOG ("found %zd candidate clauses", candidates); - - // We further search for a clause with '-lit' that has no literal - // negated in any of the candidate clauses (except 'lit'). If such a - // clause exists, we know that none of the candidates is blocked. - // - if (candidates > 1 && block_impossible (blocker, lit)) { - LOG ("impossible to block any candidate clause on %d", lit); - CADICAL_assert (blocker.candidates.empty ()); - return; - } - - LOG ("trying to block %zd clauses out of %" PRId64 " with literal %d", - candidates, noccs (lit), lit); - - int64_t blocked = 0; - - // Go over all remaining candidates and try to block them on 'lit'. - // - for (const auto &c : blocker.candidates) { - CADICAL_assert (!c->garbage); - CADICAL_assert (!c->redundant); - if (!is_blocked_clause (c, lit)) - continue; - blocked++; - LOG (c, "blocked"); - if (proof) { - proof->weaken_minus (c); - } - external->push_clause_on_extension_stack (c, lit); - blocker.reschedule.push_back (c); - mark_garbage (c); - } - - LOG ("blocked %" PRId64 - " clauses on %d out of %zd candidates in %zd occurrences", - blocked, lit, blocker.candidates.size (), occs (lit).size ()); - - blocker.candidates.clear (); - stats.blocked += blocked; - if (blocked) - flush_occs (lit); -} - -/*------------------------------------------------------------------------*/ - -// Reschedule literals in a clause (except 'lit') which was blocked. - -void Internal::block_reschedule_clause (Blocker &blocker, int lit, - Clause *c) { -#ifdef CADICAL_NDEBUG - (void) lit; -#endif - CADICAL_assert (c->garbage); - - for (const auto &other : *c) { - - int64_t &n = noccs (other); - CADICAL_assert (n > 0); - n--; - - LOG ("updating %d with %" PRId64 " positive and %" PRId64 - " negative occurrences", - other, noccs (other), noccs (-other)); - - if (blocker.schedule.contains (vlit (-other))) - blocker.schedule.update (vlit (-other)); - else if (active (other) && !frozen (other) && !marked_skip (-other)) { - LOG ("rescheduling to block clauses on %d", -other); - blocker.schedule.push_back (vlit (-other)); - } - - if (blocker.schedule.contains (vlit (other))) { - CADICAL_assert (other != lit); - blocker.schedule.update (vlit (other)); - } - } -} - -// Reschedule all literals in clauses blocked by 'lit' (except 'lit'). - -void Internal::block_reschedule (Blocker &blocker, int lit) { - while (!blocker.reschedule.empty ()) { - Clause *c = blocker.reschedule.back (); - blocker.reschedule.pop_back (); - block_reschedule_clause (blocker, lit, c); - } -} - -/*------------------------------------------------------------------------*/ - -void Internal::block_literal (Blocker &blocker, int lit) { - CADICAL_assert (!marked_skip (lit)); - - if (!active (lit)) - return; // Pure literal '-lit'. - if (frozen (lit)) - return; - - CADICAL_assert (!val (lit)); - - // If the maximum number of a negative clauses (with '-lit') exceeds the - // occurrence limit ignore this candidate literal. - // - if (noccs (-lit) > opts.blockocclim) - return; - - LOG ("blocking literal candidate %d " - "with %" PRId64 " positive and %" PRId64 " negative occurrences", - lit, noccs (lit), noccs (-lit)); - - stats.blockcands++; - - CADICAL_assert (blocker.reschedule.empty ()); - CADICAL_assert (blocker.candidates.empty ()); - - if (!noccs (-lit)) - block_pure_literal (blocker, lit); - else if (!noccs (lit)) { - // Rare situation, where the clause length limit was hit for 'lit' and - // '-lit' is skipped and then it becomes pure. Can be ignored. We also - // so it once happening for a 'elimboundmin=-1' and zero positive and - // one negative occurrence. - } else if (noccs (-lit) == 1) - block_literal_with_one_negative_occ (blocker, lit); - else - block_literal_with_at_least_two_negative_occs (blocker, lit); - - // Done with blocked clause elimination on this literal and we do not - // have to try blocked clause elimination on it again until irredundant - // clauses with its negation are removed. - // - CADICAL_assert (!frozen (lit)); // just to be sure ... - unmark_block (lit); -} - -/*------------------------------------------------------------------------*/ - -bool Internal::block () { - - if (!opts.block) - return false; - if (unsat) - return false; - if (!stats.current.irredundant) - return false; - if (terminated_asynchronously ()) - return false; - - if (propagated < trail.size ()) { - LOG ("need to propagate %zd units first", trail.size () - propagated); - init_watches (); - connect_watches (); - if (!propagate ()) { - LOG ("propagating units results in empty clause"); - learn_empty_clause (); - CADICAL_assert (unsat); - } - clear_watches (); - reset_watches (); - if (unsat) - return false; - } - - START_SIMPLIFIER (block, BLOCK); - - stats.blockings++; - - LOG ("block-%" PRId64 "", stats.blockings); - - CADICAL_assert (!level); - CADICAL_assert (!watching ()); - CADICAL_assert (!occurring ()); - - mark_satisfied_clauses_as_garbage (); - - init_occs (); // Occurrence lists for all literals. - init_noccs (); // Number of occurrences to avoid flushing garbage clauses. - - Blocker blocker (this); - block_schedule (blocker); - - int64_t blocked = stats.blocked; - int64_t resolutions = stats.blockres; - int64_t purelits = stats.blockpurelits; - int64_t pured = stats.blockpured; - - while (!terminated_asynchronously () && !blocker.schedule.empty ()) { - int lit = u2i (blocker.schedule.front ()); - blocker.schedule.pop_front (); - block_literal (blocker, lit); - block_reschedule (blocker, lit); - } - - blocker.erase (); - reset_noccs (); - reset_occs (); - - resolutions = stats.blockres - resolutions; - blocked = stats.blocked - blocked; - - PHASE ("block", stats.blockings, - "blocked %" PRId64 " clauses in %" PRId64 " resolutions", blocked, - resolutions); - - pured = stats.blockpured - pured; - purelits = stats.blockpurelits - purelits; - - if (pured) - mark_redundant_clauses_with_eliminated_variables_as_garbage (); - - if (purelits) - PHASE ("block", stats.blockings, - "found %" PRId64 " pure literals in %" PRId64 " clauses", - purelits, pured); - else - PHASE ("block", stats.blockings, "no pure literals found"); - - report ('b', !opts.reportall && !blocked); - - STOP_SIMPLIFIER (block, BLOCK); - - return blocked; -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_ccadical.cpp b/src/sat/cadical/cadical_ccadical.cpp deleted file mode 100644 index ae5c1093f..000000000 --- a/src/sat/cadical/cadical_ccadical.cpp +++ /dev/null @@ -1,211 +0,0 @@ -#include "global.h" - -#include "cadical.hpp" - -#include -#include - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -struct Wrapper : Learner, Terminator { - - Solver *solver; - struct { - void *state; - int (*function) (void *); - } terminator; - - struct { - void *state; - int max_length; - int *begin_clause, *end_clause, *capacity_clause; - void (*function) (void *, int *); - } learner; - - bool terminate () { - if (!terminator.function) - return false; - return terminator.function (terminator.state); - } - - bool learning (int size) { - if (!learner.function) - return false; - return size <= learner.max_length; - } - - void learn (int lit) { - if (learner.end_clause == learner.capacity_clause) { - size_t count = learner.end_clause - learner.begin_clause; - size_t size = count ? 2 * count : 1; - learner.begin_clause = - (int *) realloc (learner.begin_clause, size * sizeof (int)); - learner.end_clause = learner.begin_clause + count; - learner.capacity_clause = learner.begin_clause + size; - } - *learner.end_clause++ = lit; - if (lit) - return; - learner.function (learner.state, learner.begin_clause); - learner.end_clause = learner.begin_clause; - } - - Wrapper () : solver (new Solver ()) { - memset (&terminator, 0, sizeof terminator); - memset (&learner, 0, sizeof learner); - } - - ~Wrapper () { - terminator.function = 0; - if (learner.begin_clause) - free (learner.begin_clause); - delete solver; - } -}; - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END - -#include "ccadical.h" - -ABC_NAMESPACE_IMPL_START - -using namespace CaDiCaL; - -const char *ccadical_signature (void) { return Solver::signature (); } - -CCaDiCaL *ccadical_init (void) { return (CCaDiCaL *) new Wrapper (); } - -void ccadical_release (CCaDiCaL *wrapper) { delete (Wrapper *) wrapper; } - -void ccadical_constrain (CCaDiCaL *wrapper, int lit) { - ((Wrapper *) wrapper)->solver->constrain (lit); -} - -int ccadical_constraint_failed (CCaDiCaL *wrapper) { - return ((Wrapper *) wrapper)->solver->constraint_failed (); -} - -void ccadical_set_option (CCaDiCaL *wrapper, const char *name, int val) { - ((Wrapper *) wrapper)->solver->set (name, val); -} - -void ccadical_limit (CCaDiCaL *wrapper, const char *name, int val) { - ((Wrapper *) wrapper)->solver->limit (name, val); -} - -int ccadical_get_option (CCaDiCaL *wrapper, const char *name) { - return ((Wrapper *) wrapper)->solver->get (name); -} - -void ccadical_add (CCaDiCaL *wrapper, int lit) { - ((Wrapper *) wrapper)->solver->add (lit); -} - -void ccadical_assume (CCaDiCaL *wrapper, int lit) { - ((Wrapper *) wrapper)->solver->assume (lit); -} - -int ccadical_solve (CCaDiCaL *wrapper) { - return ((Wrapper *) wrapper)->solver->solve (); -} - -int ccadical_simplify (CCaDiCaL *wrapper) { - return ((Wrapper *) wrapper)->solver->simplify (); -} - -int ccadical_val (CCaDiCaL *wrapper, int lit) { - return ((Wrapper *) wrapper)->solver->val (lit); -} - -int ccadical_failed (CCaDiCaL *wrapper, int lit) { - return ((Wrapper *) wrapper)->solver->failed (lit); -} - -void ccadical_print_statistics (CCaDiCaL *wrapper) { - ((Wrapper *) wrapper)->solver->statistics (); -} - -void ccadical_terminate (CCaDiCaL *wrapper) { - ((Wrapper *) wrapper)->solver->terminate (); -} - -int64_t ccadical_active (CCaDiCaL *wrapper) { - return ((Wrapper *) wrapper)->solver->active (); -} - -int64_t ccadical_irredundant (CCaDiCaL *wrapper) { - return ((Wrapper *) wrapper)->solver->irredundant (); -} - -int ccadical_fixed (CCaDiCaL *wrapper, int lit) { - return ((Wrapper *) wrapper)->solver->fixed (lit); -} - -void ccadical_set_terminate (CCaDiCaL *ptr, void *state, - int (*terminate) (void *)) { - Wrapper *wrapper = (Wrapper *) ptr; - wrapper->terminator.state = state; - wrapper->terminator.function = terminate; - if (terminate) - wrapper->solver->connect_terminator (wrapper); - else - wrapper->solver->disconnect_terminator (); -} - -void ccadical_set_learn (CCaDiCaL *ptr, void *state, int max_length, - void (*learn) (void *state, int *clause)) { - Wrapper *wrapper = (Wrapper *) ptr; - wrapper->learner.state = state; - wrapper->learner.max_length = max_length; - wrapper->learner.function = learn; - if (learn) - wrapper->solver->connect_learner (wrapper); - else - wrapper->solver->disconnect_learner (); -} - -void ccadical_freeze (CCaDiCaL *ptr, int lit) { - ((Wrapper *) ptr)->solver->freeze (lit); -} - -void ccadical_melt (CCaDiCaL *ptr, int lit) { - ((Wrapper *) ptr)->solver->melt (lit); -} - -int ccadical_frozen (CCaDiCaL *ptr, int lit) { - return ((Wrapper *) ptr)->solver->frozen (lit); -} - -int ccadical_trace_proof (CCaDiCaL *ptr, FILE *file, const char *path) { - return ((Wrapper *) ptr)->solver->trace_proof (file, path); -} - -void ccadical_close_proof (CCaDiCaL *ptr) { - ((Wrapper *) ptr)->solver->close_proof_trace (); -} - -void ccadical_conclude (CCaDiCaL *ptr) { - ((Wrapper *) ptr)->solver->conclude (); -} - -int ccadical_vars (CCaDiCaL *ptr) { - return ((Wrapper *) ptr)->solver->vars (); -} - -int ccadical_reserve_difference (CCaDiCaL *ptr, int number_of_vars) { - return ((Wrapper *) ptr)->solver->reserve_difference (number_of_vars); -} - -void ccadical_reserve(CCaDiCaL *ptr, int min_max_var) { - ((Wrapper *) ptr)->solver->reserve(min_max_var); -} - -int ccadical_is_inconsistent(CCaDiCaL *ptr) { - return ((Wrapper *) ptr)->solver->inconsistent (); -} - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_checker.cpp b/src/sat/cadical/cadical_checker.cpp deleted file mode 100644 index 63a5f2b10..000000000 --- a/src/sat/cadical/cadical_checker.cpp +++ /dev/null @@ -1,654 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -/*------------------------------------------------------------------------*/ - -inline unsigned Checker::l2u (int lit) { - CADICAL_assert (lit); - CADICAL_assert (lit != INT_MIN); - unsigned res = 2 * (abs (lit) - 1); - if (lit < 0) - res++; - return res; -} - -inline signed char Checker::val (int lit) { - CADICAL_assert (lit); - CADICAL_assert (lit != INT_MIN); - CADICAL_assert (abs (lit) < size_vars); - CADICAL_assert (vals[lit] == -vals[-lit]); - return vals[lit]; -} - -signed char &Checker::mark (int lit) { - const unsigned u = l2u (lit); - CADICAL_assert (u < marks.size ()); - return marks[u]; -} - -inline CheckerWatcher &Checker::watcher (int lit) { - const unsigned u = l2u (lit); - CADICAL_assert (u < watchers.size ()); - return watchers[u]; -} - -/*------------------------------------------------------------------------*/ - -CheckerClause *Checker::new_clause () { - const size_t size = simplified.size (); - CADICAL_assert (size > 1), CADICAL_assert (size <= UINT_MAX); - const size_t bytes = sizeof (CheckerClause) + (size - 2) * sizeof (int); - CheckerClause *res = (CheckerClause *) new char[bytes]; - DeferDeleteArray delete_res ((char *) res); - res->next = 0; - res->hash = last_hash; - res->size = size; - int *literals = res->literals, *p = literals; - for (const auto &lit : simplified) - *p++ = lit; - num_clauses++; - - // First two literals are used as watches and should not be false. - // - for (unsigned i = 0; i < 2; i++) { - int lit = literals[i]; - if (!val (lit)) - continue; - for (unsigned j = i + 1; j < size; j++) { - int other = literals[j]; - if (val (other)) - continue; - swap (literals[i], literals[j]); - break; - } - } - CADICAL_assert (!val (literals[0])); - CADICAL_assert (!val (literals[1])); - watcher (literals[0]).push_back (CheckerWatch (literals[1], res)); - watcher (literals[1]).push_back (CheckerWatch (literals[0], res)); - - delete_res.release (); - return res; -} - -void Checker::delete_clause (CheckerClause *c) { - if (c->size) { - CADICAL_assert (c->size > 1); - CADICAL_assert (num_clauses); - num_clauses--; - } else { - CADICAL_assert (num_garbage); - num_garbage--; - } - delete[] (char *) c; -} - -void Checker::enlarge_clauses () { - CADICAL_assert (num_clauses == size_clauses); - const uint64_t new_size_clauses = size_clauses ? 2 * size_clauses : 1; - LOG ("CHECKER enlarging clauses of checker from %" PRIu64 " to %" PRIu64, - (uint64_t) size_clauses, (uint64_t) new_size_clauses); - CheckerClause **new_clauses; - new_clauses = new CheckerClause *[new_size_clauses]; - clear_n (new_clauses, new_size_clauses); - for (uint64_t i = 0; i < size_clauses; i++) { - for (CheckerClause *c = clauses[i], *next; c; c = next) { - next = c->next; - const uint64_t h = reduce_hash (c->hash, new_size_clauses); - c->next = new_clauses[h]; - new_clauses[h] = c; - } - } - delete[] clauses; - clauses = new_clauses; - size_clauses = new_size_clauses; -} - -bool Checker::clause_satisfied (CheckerClause *c) { - for (unsigned i = 0; i < c->size; i++) - if (val (c->literals[i]) > 0) - return true; - return false; -} - -// The main reason why we have an explicit garbage collection phase is that -// removing clauses from watcher lists eagerly might lead to an accumulated -// quadratic algorithm. Thus we delay removing garbage clauses from watcher -// lists until garbage collection (even though we remove garbage clauses on -// the fly during propagation too). We also remove satisfied clauses. -// -void Checker::collect_garbage_clauses () { - - stats.collections++; - - for (size_t i = 0; i < size_clauses; i++) { - CheckerClause **p = clauses + i, *c; - while ((c = *p)) { - if (clause_satisfied (c)) { - c->size = 0; // mark as garbage - *p = c->next; - c->next = garbage; - garbage = c; - num_garbage++; - CADICAL_assert (num_clauses); - num_clauses--; - } else - p = &c->next; - } - } - - LOG ("CHECKER collecting %" PRIu64 " garbage clauses %.0f%%", num_garbage, - percent (num_garbage, num_clauses)); - - for (int lit = -size_vars + 1; lit < size_vars; lit++) { - if (!lit) - continue; - CheckerWatcher &ws = watcher (lit); - const auto end = ws.end (); - auto j = ws.begin (), i = j; - for (; i != end; i++) { - CheckerWatch &w = *i; - if (w.clause->size) - *j++ = w; - } - if (j == ws.end ()) - continue; - if (j == ws.begin ()) - erase_vector (ws); - else - ws.resize (j - ws.begin ()); - } - - for (CheckerClause *c = garbage, *next; c; c = next) - next = c->next, delete_clause (c); - - CADICAL_assert (!num_garbage); - garbage = 0; -} - -/*------------------------------------------------------------------------*/ - -Checker::Checker (Internal *i) - : internal (i), size_vars (0), vals (0), inconsistent (false), - num_clauses (0), num_garbage (0), size_clauses (0), clauses (0), - garbage (0), next_to_propagate (0), last_hash (0) { - - // Initialize random number table for hash function. - // - Random random (42); - for (unsigned n = 0; n < num_nonces; n++) { - uint64_t nonce = random.next (); - if (!(nonce & 1)) - nonce++; - CADICAL_assert (nonce), CADICAL_assert (nonce & 1); - nonces[n] = nonce; - } - - memset (&stats, 0, sizeof (stats)); // Initialize statistics. -} - -void Checker::connect_internal (Internal *i) { - internal = i; - LOG ("CHECKER connected to internal"); -} - -Checker::~Checker () { - LOG ("CHECKER delete"); - vals -= size_vars; - delete[] vals; - for (size_t i = 0; i < size_clauses; i++) - for (CheckerClause *c = clauses[i], *next; c; c = next) - next = c->next, delete_clause (c); - for (CheckerClause *c = garbage, *next; c; c = next) - next = c->next, delete_clause (c); - delete[] clauses; -} - -/*------------------------------------------------------------------------*/ - -// The simplicity for accessing 'vals' and 'watchers' directly through a -// signed integer literal, comes with the price of slightly more complex -// code in deleting and enlarging the checker data structures. - -void Checker::enlarge_vars (int64_t idx) { - - CADICAL_assert (0 < idx), CADICAL_assert (idx <= INT_MAX); - - int64_t new_size_vars = size_vars ? 2 * size_vars : 2; - while (idx >= new_size_vars) - new_size_vars *= 2; - LOG ("CHECKER enlarging variables of checker from %" PRId64 " to %" PRId64 - "", - size_vars, new_size_vars); - - signed char *new_vals; - new_vals = new signed char[2 * new_size_vars]; - clear_n (new_vals, 2 * new_size_vars); - new_vals += new_size_vars; - if (size_vars) // To make sanitizer happy (without '-O'). - memcpy ((void *) (new_vals - size_vars), (void *) (vals - size_vars), - 2 * size_vars); - vals -= size_vars; - delete[] vals; - vals = new_vals; - size_vars = new_size_vars; - - watchers.resize (2 * new_size_vars); - marks.resize (2 * new_size_vars); - - CADICAL_assert (idx < new_size_vars); -} - -inline void Checker::import_literal (int lit) { - CADICAL_assert (lit); - CADICAL_assert (lit != INT_MIN); - int idx = abs (lit); - if (idx >= size_vars) - enlarge_vars (idx); - simplified.push_back (lit); - unsimplified.push_back (lit); -} - -void Checker::import_clause (const vector &c) { - for (const auto &lit : c) - import_literal (lit); -} - -struct lit_smaller { - bool operator() (int a, int b) const { - int c = abs (a), d = abs (b); - if (c < d) - return true; - if (c > d) - return false; - return a < b; - } -}; - -bool Checker::tautological () { - sort (simplified.begin (), simplified.end (), lit_smaller ()); - const auto end = simplified.end (); - auto j = simplified.begin (); - int prev = 0; - for (auto i = j; i != end; i++) { - int lit = *i; - if (lit == prev) - continue; // duplicated literal - if (lit == -prev) - return true; // tautological clause - const signed char tmp = val (lit); - if (tmp > 0) - return true; // satisfied literal and clause - *j++ = prev = lit; - } - simplified.resize (j - simplified.begin ()); - return false; -} - -/*------------------------------------------------------------------------*/ - -uint64_t Checker::reduce_hash (uint64_t hash, uint64_t size) { - CADICAL_assert (size > 0); - unsigned shift = 32; - uint64_t res = hash; - while ((((uint64_t) 1) << shift) > size) { - res ^= res >> shift; - shift >>= 1; - } - res &= size - 1; - CADICAL_assert (res < size); - return res; -} - -uint64_t Checker::compute_hash () { - unsigned j = last_id % num_nonces; - uint64_t tmp = nonces[j] * last_id; - return last_hash = tmp; -} - -CheckerClause **Checker::find () { - stats.searches++; - CheckerClause **res, *c; - const uint64_t hash = compute_hash (); - const unsigned size = simplified.size (); - const uint64_t h = reduce_hash (hash, size_clauses); - for (const auto &lit : simplified) - mark (lit) = true; - for (res = clauses + h; (c = *res); res = &c->next) { - if (c->hash == hash && c->size == size) { - bool found = true; - const int *literals = c->literals; - for (unsigned i = 0; found && i != size; i++) - found = mark (literals[i]); - if (found) - break; - } - stats.collisions++; - } - for (const auto &lit : simplified) - mark (lit) = false; - return res; -} - -void Checker::insert () { - stats.insertions++; - if (num_clauses == size_clauses) - enlarge_clauses (); - const uint64_t h = reduce_hash (compute_hash (), size_clauses); - CheckerClause *c = new_clause (); - c->next = clauses[h]; - clauses[h] = c; -} - -/*------------------------------------------------------------------------*/ - -inline void Checker::assign (int lit) { - CADICAL_assert (!val (lit)); - vals[lit] = 1; - vals[-lit] = -1; - trail.push_back (lit); -} - -inline void Checker::assume (int lit) { - signed char tmp = val (lit); - if (tmp > 0) - return; - CADICAL_assert (!tmp); - stats.assumptions++; - assign (lit); -} - -void Checker::backtrack (unsigned previously_propagated) { - - CADICAL_assert (previously_propagated <= trail.size ()); - - while (trail.size () > previously_propagated) { - int lit = trail.back (); - CADICAL_assert (val (lit) > 0); - CADICAL_assert (val (-lit) < 0); - vals[lit] = vals[-lit] = 0; - trail.pop_back (); - } - - trail.resize (previously_propagated); - next_to_propagate = previously_propagated; - CADICAL_assert (trail.size () == next_to_propagate); -} - -/*------------------------------------------------------------------------*/ - -// This is a standard propagation routine without using blocking literals -// nor without saving the last replacement position. - -bool Checker::propagate () { - bool res = true; - while (res && next_to_propagate < trail.size ()) { - int lit = trail[next_to_propagate++]; - stats.propagations++; - CADICAL_assert (val (lit) > 0); - CADICAL_assert (abs (lit) < size_vars); - CheckerWatcher &ws = watcher (-lit); - const auto end = ws.end (); - auto j = ws.begin (), i = j; - for (; res && i != end; i++) { - CheckerWatch &w = *j++ = *i; - const int blit = w.blit; - CADICAL_assert (blit != -lit); - const signed char blit_val = val (blit); - if (blit_val > 0) - continue; - const unsigned size = w.size; - if (size == 2) { // not precise since - if (blit_val < 0) - res = false; // clause might be garbage - else - assign (w.blit); // but still sound - } else { - CADICAL_assert (size > 2); - CheckerClause *c = w.clause; - if (!c->size) { - j--; - continue; - } // skip garbage clauses - CADICAL_assert (size == c->size); - int *lits = c->literals; - int other = lits[0] ^ lits[1] ^ (-lit); - CADICAL_assert (other != -lit); - signed char other_val = val (other); - if (other_val > 0) { - j[-1].blit = other; - continue; - } - lits[0] = other, lits[1] = -lit; - unsigned k; - int replacement = 0; - signed char replacement_val = -1; - for (k = 2; k < size; k++) - if ((replacement_val = val (replacement = lits[k])) >= 0) - break; - if (replacement_val >= 0) { - watcher (replacement).push_back (CheckerWatch (-lit, c)); - swap (lits[1], lits[k]); - j--; - } else if (!other_val) - assign (other); - else - res = false; - } - } - while (i != end) - *j++ = *i++; - ws.resize (j - ws.begin ()); - } - return res; -} - -bool Checker::check () { - stats.checks++; - if (inconsistent) - return true; - unsigned previously_propagated = next_to_propagate; - for (const auto &lit : simplified) - assume (-lit); - bool res = !propagate (); - backtrack (previously_propagated); - return res; -} - -bool Checker::check_blocked () { - for (const auto &lit : unsimplified) { - mark (-lit) = true; - } - vector not_blocked; - for (size_t i = 0; i < size_clauses; i++) { - for (CheckerClause *c = clauses[i], *next; c; c = next) { - next = c->next; - unsigned count = 0; - int first; - for (int *i = c->literals; i < c->literals + c->size; i++) { - const int lit = *i; - if (val (lit) > 0) { - LOG (c->literals, c->size, "satisfied clause"); - count = 2; - break; - } - if (mark (lit)) { - count++; - LOG (c->literals, c->size, "clause"); - first = lit; - } - } - if (count == 1) - not_blocked.push_back (first); - } - } - for (const auto &lit : not_blocked) { - mark (lit) = false; - } - bool blocked = false; - for (const auto &lit : unsimplified) { - if (mark (-lit)) - blocked = true; - mark (-lit) = false; - } - return blocked; -} - -/*------------------------------------------------------------------------*/ - -void Checker::add_clause (const char *type) { -#ifndef LOGGING - (void) type; -#endif - - // If there are enough garbage clauses collect them first. - if (num_garbage > 0.5 * max ((size_t) size_clauses, (size_t) size_vars)) - collect_garbage_clauses (); - - int unit = 0; - for (const auto &lit : simplified) { - const signed char tmp = val (lit); - if (tmp < 0) - continue; - CADICAL_assert (!tmp); - if (unit) { - unit = INT_MIN; - break; - } - unit = lit; - } - - if (simplified.empty ()) { - LOG ("CHECKER added empty %s clause", type); - inconsistent = true; - } - if (!unit) { - LOG ("CHECKER added and checked falsified %s clause", type); - inconsistent = true; - } else if (unit != INT_MIN) { - LOG ("CHECKER added and checked %s unit clause %d", type, unit); - assign (unit); - stats.units++; - if (!propagate ()) { - LOG ("CHECKER inconsistent after propagating %s unit", type); - inconsistent = true; - } - } else - insert (); -} - -void Checker::add_original_clause (int64_t id, bool, const vector &c, - bool) { - if (inconsistent) - return; - START (checking); - LOG (c, "CHECKER addition of original clause"); - stats.added++; - stats.original++; - import_clause (c); - last_id = id; - if (tautological ()) - LOG ("CHECKER ignoring satisfied original clause"); - else - add_clause ("original"); - simplified.clear (); - unsimplified.clear (); - STOP (checking); -} - -void Checker::add_derived_clause (int64_t id, bool, const vector &c, - const vector &) { - if (inconsistent) - return; - START (checking); - LOG (c, "CHECKER addition of derived clause"); - stats.added++; - stats.derived++; - import_clause (c); - last_id = id; - if (tautological ()) - LOG ("CHECKER ignoring satisfied derived clause"); - else if (!check () && !check_blocked ()) { // needed for ER proof support - fatal_message_start (); - fputs ("failed to check derived clause:\n", stderr); - for (const auto &lit : unsimplified) - fprintf (stderr, "%d ", lit); - fputc ('0', stderr); - fatal_message_end (); - } else - add_clause ("derived"); - simplified.clear (); - unsimplified.clear (); - STOP (checking); -} - -/*------------------------------------------------------------------------*/ - -void Checker::delete_clause (int64_t id, bool, const vector &c) { - if (inconsistent) - return; - START (checking); - LOG (c, "CHECKER checking deletion of clause"); - stats.deleted++; - simplified.clear (); // Can be non-empty if clause allocation fails. - unsimplified.clear (); // Can be non-empty if clause allocation fails. - import_clause (c); - last_id = id; - if (!tautological ()) { - CheckerClause **p = find (), *d = *p; - if (d) { - CADICAL_assert (d->size > 1); - // Remove from hash table, mark as garbage, connect to garbage list. - num_garbage++; - CADICAL_assert (num_clauses); - num_clauses--; - *p = d->next; - d->next = garbage; - garbage = d; - d->size = 0; - } else { - fatal_message_start (); - fputs ("deleted clause not in proof:\n", stderr); - for (const auto &lit : unsimplified) - fprintf (stderr, "%d ", lit); - fputc ('0', stderr); - fatal_message_end (); - } - } - simplified.clear (); - unsimplified.clear (); - STOP (checking); -} - -void Checker::add_assumption_clause (int64_t id, const vector &c, - const vector &chain) { - add_derived_clause (id, true, c, chain); - delete_clause (id, true, c); -} - -/*------------------------------------------------------------------------*/ - -void Checker::dump () { - int max_var = 0; - for (uint64_t i = 0; i < size_clauses; i++) - for (CheckerClause *c = clauses[i]; c; c = c->next) - for (unsigned i = 0; i < c->size; i++) - if (abs (c->literals[i]) > max_var) - max_var = abs (c->literals[i]); - printf ("p cnf %d %" PRIu64 "\n", max_var, num_clauses); - for (uint64_t i = 0; i < size_clauses; i++) - for (CheckerClause *c = clauses[i]; c; c = c->next) { - for (unsigned i = 0; i < c->size; i++) - printf ("%d ", c->literals[i]); - printf ("0\n"); - } -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_clause.cpp b/src/sat/cadical/cadical_clause.cpp deleted file mode 100644 index 1c84994a6..000000000 --- a/src/sat/cadical/cadical_clause.cpp +++ /dev/null @@ -1,649 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -/*------------------------------------------------------------------------*/ - -// Signed marking or unmarking of a clause or the global 'clause'. - -void Internal::mark (Clause *c) { - for (const auto &lit : *c) - mark (lit); -} - -void Internal::mark2 (Clause *c) { - for (const auto &lit : *c) - mark2 (lit); -} - -void Internal::unmark (Clause *c) { - for (const auto &lit : *c) - unmark (lit); -} - -void Internal::mark_clause () { - for (const auto &lit : clause) - mark (lit); -} - -void Internal::unmark_clause () { - for (const auto &lit : clause) - unmark (lit); -} - -/*------------------------------------------------------------------------*/ - -// Mark the variables of an irredundant clause to 'have been removed', which -// will trigger these variables to be considered again in the next bounded -// variable elimination phase. This is called from 'mark_garbage' below. -// Note that 'mark_removed (int lit)' will also mark the blocking flag of -// '-lit' to trigger reconsidering blocking clauses on '-lit'. - -void Internal::mark_removed (Clause *c, int except) { - LOG (c, "marking removed"); - CADICAL_assert (!c->redundant); - for (const auto &lit : *c) - if (lit != except) - mark_removed (lit); -} - -// Mark the variables of a (redundant or irredundant) clause to 'have been -// added', which triggers clauses with such a variables, to be considered -// both as a subsumed or subsuming clause in the next subsumption phase. -// This function is called from 'new_clause' below as well as in situations -// where a clause is shrunken (and thus needs to be at least considered -// again to subsume a larger clause). We also use this to tell -// 'ternary' preprocessing reconsider clauses on an added literal as well as -// trying to block clauses on it. - -inline void Internal::mark_added (int lit, int size, bool redundant) { - mark_subsume (lit); - if (size == 3) - mark_ternary (lit); - if (!redundant) - mark_block (lit); - if (!redundant || size == 2) - mark_factor (lit); -} - -void Internal::mark_added (Clause *c) { - LOG (c, "marking added"); - CADICAL_assert (likely_to_be_kept_clause (c)); - for (const auto &lit : *c) - mark_added (lit, c->size, c->redundant); -} - -/*------------------------------------------------------------------------*/ - -Clause *Internal::new_clause (bool red, int glue) { - - CADICAL_assert (clause.size () <= (size_t) INT_MAX); - const int size = (int) clause.size (); - CADICAL_assert (size >= 2); - - if (glue > size) - glue = size; - - size_t bytes = Clause::bytes (size); - Clause *c = (Clause *) new char[bytes]; - DeferDeleteArray clause_delete ((char *) c); - - c->id = ++clause_id; - - c->conditioned = false; - c->covered = false; - c->enqueued = false; - c->frozen = false; - c->garbage = false; - c->gate = false; - c->hyper = false; - c->instantiated = false; - c->moved = false; - c->reason = false; - c->redundant = red; - c->transred = false; - c->subsume = false; - c->swept = false; - c->flushed = false; - c->vivified = false; - c->vivify = false; - c->used = 0; - - c->glue = glue; - c->size = size; - c->pos = 2; - - for (int i = 0; i < size; i++) - c->literals[i] = clause[i]; - - // Just checking that we did not mess up our sophisticated memory layout. - // This might be compiler dependent though. Crucial for correctness. - // - CADICAL_assert (c->bytes () == bytes); - - stats.current.total++; - stats.added.total++; - - if (red) { - stats.current.redundant++; - stats.added.redundant++; - } else { - stats.irrlits += size; - stats.current.irredundant++; - stats.added.irredundant++; - } - - clauses.push_back (c); - clause_delete.release (); - LOG (c, "new pointer %p", (void *) c); - - if (likely_to_be_kept_clause (c)) - mark_added (c); - - return c; -} - -/*------------------------------------------------------------------------*/ - -void Internal::promote_clause (Clause *c, int new_glue) { - CADICAL_assert (c->redundant); - const int tier1limit = tier1[false]; - const int tier2limit = max (tier1limit, tier2[false]); - if (!c->redundant) - return; - if (c->hyper) - return; - int old_glue = c->glue; - if (new_glue >= old_glue) - return; - if (old_glue > tier1limit && new_glue <= tier1limit) { - LOG (c, "promoting with new glue %d to tier1", new_glue); - stats.promoted1++; - c->used = max_used; - } else if (old_glue > tier2limit && new_glue <= tier2limit) { - LOG (c, "promoting with new glue %d to tier2", new_glue); - stats.promoted2++; - } else if (old_glue <= tier2limit) - LOG (c, "keeping with new glue %d in tier2", new_glue); - else - LOG (c, "keeping with new glue %d in tier3", new_glue); - stats.improvedglue++; - c->glue = new_glue; -} -/*------------------------------------------------------------------------*/ - -void Internal::promote_clause_glue_only (Clause *c, int new_glue) { - CADICAL_assert (c->redundant); - if (c->hyper) - return; - int old_glue = c->glue; - const int tier1limit = tier1[false]; - const int tier2limit = max (tier1limit, tier2[false]); - if (new_glue >= old_glue) - return; - if (new_glue <= tier1limit) { - LOG (c, "promoting with new glue %d to tier1", new_glue); - stats.promoted1++; - c->used = max_used; - } else if (old_glue > tier2limit && new_glue <= tier2limit) { - LOG (c, "promoting with new glue %d to tier2", new_glue); - stats.promoted2++; - } else if (old_glue <= tier2limit) - LOG (c, "keeping with new glue %d in tier2", new_glue); - else - LOG (c, "keeping with new glue %d in tier3", new_glue); - stats.improvedglue++; - c->glue = new_glue; -} - -/*------------------------------------------------------------------------*/ - -// Shrinking a clause, e.g., removing one or more literals, requires to fix -// the 'pos' field, if it exists and points after the new last literal. We -// also have adjust the global statistics counter of irredundant literals -// for irredundant clauses, and also adjust the glue value of redundant -// clauses if the size becomes smaller than the glue. Also mark the -// literals in the resulting clause as 'added'. The result is the number of -// (aligned) removed bytes, resulting from shrinking the clause. -// -size_t Internal::shrink_clause (Clause *c, int new_size) { - if (opts.check && is_external_forgettable (c->id)) - mark_garbage_external_forgettable (c->id); - CADICAL_assert (new_size >= 2); - int old_size = c->size; - CADICAL_assert (new_size < old_size); -#ifndef CADICAL_NDEBUG - for (int i = c->size; i < new_size; i++) - c->literals[i] = 0; -#endif - - if (c->pos >= new_size) - c->pos = 2; - - size_t old_bytes = c->bytes (); - c->size = new_size; - size_t new_bytes = c->bytes (); - size_t res = old_bytes - new_bytes; - - if (c->redundant) - promote_clause_glue_only (c, min (c->size - 1, c->glue)); - else { - int delta_size = old_size - new_size; - CADICAL_assert (stats.irrlits >= delta_size); - stats.irrlits -= delta_size; - } - - if (likely_to_be_kept_clause (c)) - mark_added (c); - - return res; -} - -// This is the 'raw' deallocation of a clause. If the clause is in the -// arena nothing happens. If the clause is not in the arena its memory is -// reclaimed immediately. - -void Internal::deallocate_clause (Clause *c) { - char *p = (char *) c; - if (arena.contains (p)) - return; - LOG (c, "deallocate pointer %p", (void *) c); - delete[] p; -} - -void Internal::delete_clause (Clause *c) { - LOG (c, "delete pointer %p", (void *) c); - size_t bytes = c->bytes (); - stats.collected += bytes; - if (c->garbage) { - CADICAL_assert (stats.garbage.bytes >= (int64_t) bytes); - stats.garbage.bytes -= bytes; - CADICAL_assert (stats.garbage.clauses > 0); - stats.garbage.clauses--; - CADICAL_assert (stats.garbage.literals >= c->size); - stats.garbage.literals -= c->size; - - // See the discussion in 'propagate' on avoiding to eagerly trace binary - // clauses as deleted (produce 'd ...' lines) as soon they are marked - // garbage. We avoid this and only trace them as deleted when they are - // actually deleted here. This allows the solver to propagate binary - // garbage clauses without producing incorrect 'd' lines. The effect - // from the proof perspective is that the deletion of these binary - // clauses occurs later in the proof file. - // - if (proof && c->size == 2 && !c->flushed) { - proof->delete_clause (c); - } - } - deallocate_clause (c); -} - -// We want to eagerly update statistics as soon clauses are marked garbage. -// Otherwise 'report' for instance gives wrong numbers after 'subsume' -// before the next 'reduce'. Thus we factored out marking and accounting -// for garbage clauses. -// -// Eagerly deleting clauses instead is problematic, since references to -// these clauses need to be flushed, which is too costly to do eagerly. -// -// We also update garbage statistics at this point. This helps to -// determine whether the garbage collector should be called during for -// instance bounded variable elimination, which usually generates lots of -// garbage clauses. -// -// In order not to miss any update to these clause statistics we call -// 'check_clause_stats' after garbage collection in debugging mode. -// -void Internal::mark_garbage (Clause *c) { - - CADICAL_assert (!c->garbage); - - // Delay tracing deletion of binary clauses. See the discussion above in - // 'delete_clause' and also in 'propagate'. - // - if (proof && (c->size != 2 || !watching ())) { - c->flushed = true; - proof->delete_clause (c); - } - - // Because of the internal model checking, external forgettable clauses - // must be marked as removed already upon mark_garbage, can not wait until - // actual deletion. - if (opts.check && is_external_forgettable (c->id)) - mark_garbage_external_forgettable (c->id); - - CADICAL_assert (stats.current.total > 0); - stats.current.total--; - - size_t bytes = c->bytes (); - if (c->redundant) { - CADICAL_assert (stats.current.redundant > 0); - stats.current.redundant--; - } else { - CADICAL_assert (stats.current.irredundant > 0); - stats.current.irredundant--; - CADICAL_assert (stats.irrlits >= c->size); - stats.irrlits -= c->size; - mark_removed (c); - } - stats.garbage.bytes += bytes; - stats.garbage.clauses++; - stats.garbage.literals += c->size; - c->garbage = true; - c->used = 0; - - LOG (c, "marked garbage pointer %p", (void *) c); -} - -/*------------------------------------------------------------------------*/ - -// Almost the same function as 'search_assign' except that we do not pretend -// to learn a new unit clause (which was confusing in log files). - -void Internal::assign_original_unit (int64_t id, int lit) { - CADICAL_assert (!level || opts.chrono); - CADICAL_assert (!unsat); - const int idx = vidx (lit); - CADICAL_assert (!vals[idx]); - CADICAL_assert (!flags (idx).eliminated ()); - Var &v = var (idx); - v.level = 0; - v.trail = (int) trail.size (); - v.reason = 0; - const signed char tmp = sign (lit); - set_val (idx, tmp); - trail.push_back (lit); - num_assigned++; - const unsigned uidx = vlit (lit); - if (lrat || frat) - unit_clauses (uidx) = id; - LOG ("original unit assign %d", lit); - CADICAL_assert (num_assigned == trail.size () || level); - mark_fixed (lit); - if (level) - return; - if (propagate ()) - return; - CADICAL_assert (conflict); - LOG ("propagation of original unit results in conflict"); - learn_empty_clause (); -} - -// New clause added through the API, e.g., while parsing a DIMACS file. -// Also used by external_propagate in various different modes. -// clause, original, lrat_chain and external->eclause are set. -// from_propagator and force_no_backtrack change the behaviour. -// sometimes the pointer to the new clause is needed, therefore it is -// made sure that newest_clause points to the new clause upon return. -// -// TODO: Find another name for 'tainted' in the context of ilb, tainted -// is reconstruction related already and they should not mix. -void Internal::add_new_original_clause (int64_t id) { - - if (!from_propagator && level && !opts.ilb) { - backtrack (); - } else if (tainted_literal) { - CADICAL_assert (val (tainted_literal)); - int new_level = var (tainted_literal).level - 1; - CADICAL_assert (new_level >= 0); - backtrack (new_level); - } - CADICAL_assert (!tainted_literal); - LOG (original, "original clause"); - CADICAL_assert (clause.empty ()); - bool skip = false; - unordered_set learned_levels; - size_t unassigned = 0; - newest_clause = 0; - if (unsat) { - LOG ("skipping clause since formula is already inconsistent"); - skip = true; - } else { - CADICAL_assert (clause.empty ()); - for (const auto &lit : original) { - int tmp = marked (lit); - if (tmp > 0) { - LOG ("removing duplicated literal %d", lit); - } else if (tmp < 0) { - LOG ("tautological since both %d and %d occur", -lit, lit); - skip = true; - } else { - mark (lit); - tmp = fixed (lit); - if (tmp < 0) { - LOG ("removing falsified literal %d", lit); - if (lrat) { - int elit = externalize (lit); - unsigned eidx = (elit > 0) + 2u * (unsigned) abs (elit); - if (!external->ext_units[eidx]) { - int64_t uid = unit_id (-lit); - lrat_chain.push_back (uid); - } - } - } else if (tmp > 0) { - LOG ("satisfied since literal %d true", lit); - skip = true; - } else { - clause.push_back (lit); - CADICAL_assert (flags (lit).status != Flags::UNUSED); - tmp = val (lit); - if (tmp) - learned_levels.insert (var (lit).level); - else - unassigned++; - } - } - } - for (const auto &lit : original) - unmark (lit); - } - if (skip) { - if (from_propagator) { - stats.ext_prop.elearn_conf++; - - // In case it was a skipped external forgettable, we need to mark it - // immediately as removed - - if (opts.check && is_external_forgettable (id)) - mark_garbage_external_forgettable (id); - } - if (proof) { - proof->delete_external_original_clause (id, false, external->eclause); - } - } else { - int64_t new_id = id; - const size_t size = clause.size (); - if (original.size () > size) { - new_id = ++clause_id; - if (proof) { - if (lrat) - lrat_chain.push_back (id); - proof->add_derived_clause (new_id, false, clause, lrat_chain); - proof->delete_external_original_clause (id, false, - external->eclause); - } - external->check_learned_clause (); - - if (from_propagator) { - // The original form of the added clause is immediately forgotten - // TODO: shall we save and check the simplified form? (one with - // new_id) - if (opts.check && is_external_forgettable (id)) - mark_garbage_external_forgettable (id); - } - } - external->eclause.clear (); - lrat_chain.clear (); - if (!size) { - if (from_propagator) - stats.ext_prop.elearn_conf++; - CADICAL_assert (!unsat); - if (!original.size ()) - VERBOSE (1, "found empty original clause"); - else - VERBOSE (1, "found falsified original clause"); - unsat = true; - conflict_id = new_id; - marked_failed = true; - conclusion.push_back (new_id); - } else if (size == 1) { - if (force_no_backtrack) { - CADICAL_assert (level); - const int idx = vidx (clause[0]); - CADICAL_assert (val (clause[0]) >= 0); - CADICAL_assert (!flags (idx).eliminated ()); - Var &v = var (idx); - CADICAL_assert (val (clause[0])); - v.level = 0; - v.reason = 0; - const unsigned uidx = vlit (clause[0]); - if (lrat || frat) - unit_clauses (uidx) = new_id; - mark_fixed (clause[0]); - } else { - const int lit = clause[0]; - CADICAL_assert (!val (lit) || var (lit).level); - if (val (lit) < 0) - backtrack (var (lit).level - 1); - CADICAL_assert (val (lit) >= 0); - handle_external_clause (0); - assign_original_unit (new_id, lit); - } - } else { - move_literals_to_watch (); -#ifndef CADICAL_NDEBUG - check_watched_literal_invariants (); -#endif - int glue = (int) (learned_levels.size () + unassigned); - CADICAL_assert (glue <= (int) clause.size ()); - bool clause_redundancy = from_propagator && ext_clause_forgettable; - Clause *c = new_clause (clause_redundancy, glue); - c->id = new_id; - clause_id--; - watch_clause (c); - clause.clear (); - original.clear (); - handle_external_clause (c); - newest_clause = c; - } - } - clause.clear (); - lrat_chain.clear (); -} - -// Add learned new clause during conflict analysis and watch it. Requires -// that the clause is at least of size 2, and the first two literals -// are assigned at the highest decision level. -// -Clause *Internal::new_learned_redundant_clause (int glue) { - CADICAL_assert (clause.size () > 1); -#ifndef CADICAL_NDEBUG - for (size_t i = 2; i < clause.size (); i++) - CADICAL_assert (var (clause[0]).level >= var (clause[i]).level), - CADICAL_assert (var (clause[1]).level >= var (clause[i]).level); -#endif - external->check_learned_clause (); - Clause *res = new_clause (true, glue); - if (proof) { - proof->add_derived_clause (res, lrat_chain); - } - CADICAL_assert (watching ()); - watch_clause (res); - return res; -} - -// Add hyper binary resolved clause during 'probing'. -// -Clause *Internal::new_hyper_binary_resolved_clause (bool red, int glue) { - external->check_learned_clause (); - Clause *res = new_clause (red, glue); - if (proof) { - proof->add_derived_clause (res, lrat_chain); - } - CADICAL_assert (watching ()); - watch_clause (res); - return res; -} - -// Add hyper ternary resolved clause during 'ternary'. -// -Clause *Internal::new_hyper_ternary_resolved_clause (bool red) { - external->check_learned_clause (); - size_t size = clause.size (); - Clause *res = new_clause (red, size); - if (proof) { - proof->add_derived_clause (res, lrat_chain); - } - CADICAL_assert (!watching ()); - return res; -} - -Clause *Internal::new_factor_clause () { - external->check_learned_clause (); - stats.factor_added++; - stats.literals_factored += clause.size (); - Clause *res = new_clause (false, 0); - if (proof) { - proof->add_derived_clause (res, lrat_chain); - } - CADICAL_assert (!watching ()); - CADICAL_assert (occurring ()); - for (const auto &lit : *res) { - occs (lit).push_back (res); - } - return res; -} - -// Add hyper ternary resolved clause during 'congruence' and watch it -// -Clause * -Internal::new_hyper_ternary_resolved_clause_and_watch (bool red, - bool full_watching) { - external->check_learned_clause (); - size_t size = clause.size (); - Clause *res = new_clause (red, size); - if (proof) { - proof->add_derived_clause (res, lrat_chain); - } - if (full_watching) { - CADICAL_assert (watching ()); - watch_clause (res); - } - return res; -} - -// Add a new clause with same glue and redundancy as 'orig' but literals are -// assumed to be in 'clause' in 'decompose' and 'vivify'. -// -Clause *Internal::new_clause_as (const Clause *orig) { - external->check_learned_clause (); - const int new_glue = orig->glue; - Clause *res = new_clause (orig->redundant, new_glue); - if (proof) { - proof->add_derived_clause (res, lrat_chain); - } - CADICAL_assert (watching ()); - watch_clause (res); - return res; -} - -// Add resolved clause during resolution, e.g., bounded variable -// elimination, but do not connect its occurrences here. -// -Clause *Internal::new_resolved_irredundant_clause () { - external->check_learned_clause (); - if (proof) { - proof->add_derived_clause (clause_id + 1, false, clause, lrat_chain); - } - Clause *res = new_clause (false); - CADICAL_assert (!watching ()); - return res; -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_collect.cpp b/src/sat/cadical/cadical_collect.cpp deleted file mode 100644 index c36e063b2..000000000 --- a/src/sat/cadical/cadical_collect.cpp +++ /dev/null @@ -1,551 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -/*------------------------------------------------------------------------*/ - -// Returns the positive number '1' ( > 0) if the given clause is root level -// satisfied or the negative number '-1' ( < 0) if it is not root level -// satisfied but contains a root level falsified literal. Otherwise, if it -// contains neither a satisfied nor falsified literal, then '0' is returned. - -int Internal::clause_contains_fixed_literal (Clause *c) { - int satisfied = 0, falsified = 0; - for (const auto &lit : *c) { - const int tmp = fixed (lit); - if (tmp > 0) { - LOG (c, "root level satisfied literal %d in", lit); - satisfied++; - } - if (tmp < 0) { - LOG (c, "root level falsified literal %d in", lit); - falsified++; - } - } - if (satisfied) - return 1; - else if (falsified) - return -1; - else - return 0; -} - -// Assume that the clause is not root level satisfied but contains a literal -// set to false (root level falsified literal), so it can be shrunken. The -// clause data is not actually reallocated at this point to avoid dealing -// with issues of special policies for watching binary clauses or whether a -// clause is extended or not. Only its size field is adjusted accordingly -// after flushing out root level falsified literals. - -void Internal::remove_falsified_literals (Clause *c) { - const const_literal_iterator end = c->end (); - const_literal_iterator i; - int num_non_false = 0; - for (i = c->begin (); num_non_false < 2 && i != end; i++) - if (fixed (*i) >= 0) - num_non_false++; - if (num_non_false < 2) - return; - if (proof) { - // Flush changes the clause id, external forgettables need to be - // marked here (or the new id could be used instead of old one) - if (opts.check && is_external_forgettable (c->id)) - mark_garbage_external_forgettable (c->id); - proof->flush_clause (c); - } - literal_iterator j = c->begin (); - for (i = j; i != end; i++) { - const int lit = *j++ = *i, tmp = fixed (lit); - CADICAL_assert (tmp <= 0); - if (tmp >= 0) - continue; - LOG ("flushing %d", lit); - j--; - } - stats.collected += shrink_clause (c, j - c->begin ()); -} - -// If there are new units (fixed variables) since the last garbage -// collection we go over all clauses, mark satisfied ones as garbage and -// flush falsified literals. Otherwise if no new units have been generated -// since the last garbage collection just skip this step. - -void Internal::mark_satisfied_clauses_as_garbage () { - - if (last.collect.fixed >= stats.all.fixed) - return; - last.collect.fixed = stats.all.fixed; - - LOG ("marking satisfied clauses and removing falsified literals"); - - for (const auto &c : clauses) { - if (c->garbage) - continue; - const int tmp = clause_contains_fixed_literal (c); - if (tmp > 0) - mark_garbage (c); - else if (tmp < 0) - remove_falsified_literals (c); - } -} - -/*------------------------------------------------------------------------*/ - -// Reason clauses can not be collected. -// -// We protect reasons before and release protection after garbage collection -// (actually within garbage collection). -// -// For 'reduce' we still need to make sure that all clauses which should not -// be removed are marked as such and thus we need to call it before marking -// clauses to be flushed. - -void Internal::protect_reasons () { - LOG ("protecting reason clauses of all assigned variables on trail"); - CADICAL_assert (!protected_reasons); -#ifdef LOGGING - size_t count = 0; -#endif - for (const auto &lit : trail) { - if (!active (lit)) - continue; - CADICAL_assert (val (lit)); - Var &v = var (lit); - CADICAL_assert (v.level > 0); - Clause *reason = v.reason; - if (!reason) - continue; - if (reason == external_reason) - continue; - LOG (reason, "protecting assigned %d reason %p", lit, (void *) reason); - CADICAL_assert (!reason->reason); - reason->reason = true; -#ifdef LOGGING - count++; -#endif - } - LOG ("protected %zd reason clauses referenced on trail", count); - protected_reasons = true; -} - -/*------------------------------------------------------------------------*/ - -// After garbage collection we reset the 'reason' flag of the reasons -// of assigned literals on the trail. - -void Internal::unprotect_reasons () { - LOG ("unprotecting reasons clauses of all assigned variables on trail"); - CADICAL_assert (protected_reasons); -#ifdef LOGGING - size_t count = 0; -#endif - for (const auto &lit : trail) { - if (!active (lit)) - continue; - CADICAL_assert (val (lit)); - Var &v = var (lit); - CADICAL_assert (v.level > 0); - Clause *reason = v.reason; - if (!reason) - continue; - if (reason == external_reason) - continue; - LOG (reason, "unprotecting assigned %d reason %p", lit, - (void *) reason); - CADICAL_assert (reason->reason); - reason->reason = false; -#ifdef LOGGING - count++; -#endif - } - LOG ("unprotected %zd reason clauses referenced on trail", count); - protected_reasons = false; -} - -/*------------------------------------------------------------------------*/ - -// Update occurrence lists before deleting garbage clauses in the context of -// preprocessing, e.g., during bounded variable elimination 'elim'. The -// result is the number of remaining clauses, which in this context means -// the number of non-garbage clauses. - -size_t Internal::flush_occs (int lit) { - Occs &os = occs (lit); - const const_occs_iterator end = os.end (); - occs_iterator j = os.begin (); - const_occs_iterator i; - size_t res = 0; - Clause *c; - for (i = j; i != end; i++) { - c = *i; - if (c->collect ()) - continue; - *j++ = c->moved ? c->copy : c; - // CADICAL_assert (!c->redundant); // -> not true in sweeping - res++; - } - os.resize (j - os.begin ()); - shrink_occs (os); - return res; -} - -// Update watch lists before deleting garbage clauses in the context of -// 'reduce' where we watch and no occurrence lists. We have to protect -// reason clauses not be collected and thus we have this additional check -// hidden in 'Clause.collect', which for the root level context of -// preprocessing is actually redundant. - -inline void Internal::flush_watches (int lit, Watches &saved) { - CADICAL_assert (saved.empty ()); - Watches &ws = watches (lit); - const const_watch_iterator end = ws.end (); - watch_iterator j = ws.begin (); - const_watch_iterator i; - for (i = j; i != end; i++) { - Watch w = *i; - Clause *c = w.clause; - if (c->collect ()) - continue; - if (c->moved) - c = w.clause = c->copy; - w.size = c->size; - const int new_blit_pos = (c->literals[0] == lit); - LOG (c, "clause in flush_watch starting from %d", lit); - CADICAL_assert (c->literals[!new_blit_pos] == lit); /*FW1*/ - w.blit = c->literals[new_blit_pos]; - if (w.binary ()) - *j++ = w; - else - saved.push_back (w); - } - ws.resize (j - ws.begin ()); - for (const auto &w : saved) - ws.push_back (w); - saved.clear (); - shrink_vector (ws); -} - -void Internal::flush_all_occs_and_watches () { - if (occurring ()) - for (auto idx : vars) - flush_occs (idx), flush_occs (-idx); - - if (watching ()) { - Watches tmp; - for (auto idx : vars) - flush_watches (idx, tmp), flush_watches (-idx, tmp); - } -} - -/*------------------------------------------------------------------------*/ - -void Internal::update_reason_references () { - LOG ("update assigned reason references"); -#ifdef LOGGING - size_t count = 0; -#endif - for (auto &lit : trail) { - if (!active (lit)) - continue; - Var &v = var (lit); - Clause *c = v.reason; - if (!c) - continue; - if (c == external_reason) - continue; - LOG (c, "updating assigned %d reason", lit); - CADICAL_assert (c->reason); - CADICAL_assert (c->moved); - Clause *d = c->copy; - v.reason = d; -#ifdef LOGGING - count++; -#endif - } - LOG ("updated %zd assigned reason references", count); -} - -/*------------------------------------------------------------------------*/ - -// This is a simple garbage collector which does not move clauses. It needs -// less space than the arena based clause allocator, but is not as cache -// efficient, since the copying garbage collector can put clauses together -// which are likely accessed after each other. - -void Internal::delete_garbage_clauses () { - - flush_all_occs_and_watches (); - - LOG ("deleting garbage clauses"); -#ifndef CADICAL_QUIET - int64_t collected_bytes = 0, collected_clauses = 0; -#endif - const auto end = clauses.end (); - auto j = clauses.begin (), i = j; - while (i != end) { - Clause *c = *j++ = *i++; - if (!c->collect ()) - continue; -#ifndef CADICAL_QUIET - collected_bytes += c->bytes (); - collected_clauses++; -#endif - delete_clause (c); - j--; - } - clauses.resize (j - clauses.begin ()); - shrink_vector (clauses); - - PHASE ("collect", stats.collections, - "collected %" PRId64 " bytes of %" PRId64 " garbage clauses", - collected_bytes, collected_clauses); -} - -/*------------------------------------------------------------------------*/ - -// This is the start of the copying garbage collector using the arena. At -// the core is the following function, which copies a clause to the 'to' -// space of the arena. Be careful if this clause is a reason of an -// assignment. In that case update the reason reference. -// -void Internal::copy_clause (Clause *c) { - LOG (c, "moving"); - CADICAL_assert (!c->moved); - char *p = (char *) c; - char *q = arena.copy (p, c->bytes ()); - c->copy = (Clause *) q; - c->moved = true; - LOG ("copied clause[%" PRId64 "] from %p to %p", c->id, (void *) c, - (void *) c->copy); -} - -// This is the moving garbage collector. - -void Internal::copy_non_garbage_clauses () { - - size_t collected_clauses = 0, collected_bytes = 0; - size_t moved_clauses = 0, moved_bytes = 0; - - // First determine 'moved_bytes' and 'collected_bytes'. - // - for (const auto &c : clauses) - if (!c->collect ()) - moved_bytes += c->bytes (), moved_clauses++; - else - collected_bytes += c->bytes (), collected_clauses++; - - PHASE ("collect", stats.collections, - "moving %zd bytes %.0f%% of %zd non garbage clauses", moved_bytes, - percent (moved_bytes, collected_bytes + moved_bytes), - moved_clauses); - (void) moved_clauses, (void) collected_clauses, (void) collected_bytes; - // Prepare 'to' space of size 'moved_bytes'. - // - arena.prepare (moved_bytes); - - // Keep clauses in arena in the same order. - // - if (opts.arenacompact) - for (const auto &c : clauses) - if (!c->collect () && arena.contains (c)) - copy_clause (c); - - if (opts.arenatype == 1 || !watching ()) { - - // Localize according to current clause order. - - // If the option 'opts.arenatype == 1' is set, then this means the - // solver uses the original order of clauses. If there are no watches, - // we can not use the watched based copying policies below. This - // happens if garbage collection is triggered during bounded variable - // elimination. - - // Copy clauses according to the order of calling 'copy_clause', which - // in essence just gives a compacting garbage collector, since their - // relative order is kept, and actually already gives the largest - // benefit due to better cache locality. - - for (const auto &c : clauses) - if (!c->moved && !c->collect ()) - copy_clause (c); - - } else if (opts.arenatype == 2) { - - // Localize according to (original) variable order. - - // This is almost the version used by MiniSAT and descendants. - // Our version uses saved phases too. - - for (int sign = -1; sign <= 1; sign += 2) - for (auto idx : vars) - for (const auto &w : watches (sign * likely_phase (idx))) - if (!w.clause->moved && !w.clause->collect ()) - copy_clause (w.clause); - - } else { - - // Localize according to decision queue order. - - // This is the default for search. It allocates clauses in the order of - // the decision queue and also uses saved phases. It seems faster than - // the MiniSAT version and thus we keep 'opts.arenatype == 3'. - - CADICAL_assert (opts.arenatype == 3); - - for (int sign = -1; sign <= 1; sign += 2) - for (int idx = queue.last; idx; idx = link (idx).prev) - for (const auto &w : watches (sign * likely_phase (idx))) - if (!w.clause->moved && !w.clause->collect ()) - copy_clause (w.clause); - } - - // Do not forget to move clauses which are not watched, which happened in - // a rare situation, and now is only left as defensive code. - // - for (const auto &c : clauses) - if (!c->collect () && !c->moved) - copy_clause (c); - - flush_all_occs_and_watches (); - update_reason_references (); - - // Replace and flush clause references in 'clauses'. - // - const auto end = clauses.end (); - auto j = clauses.begin (), i = j; - for (; i != end; i++) { - Clause *c = *i; - if (c->collect ()) - delete_clause (c); - else - CADICAL_assert (c->moved), *j++ = c->copy, deallocate_clause (c); - } - clauses.resize (j - clauses.begin ()); - if (clauses.size () < clauses.capacity () / 2) - shrink_vector (clauses); - - if (opts.arenasort) - rsort (clauses.begin (), clauses.end (), pointer_rank ()); - - // Release 'from' space completely and then swap 'to' with 'from'. - // - arena.swap (); - - PHASE ("collect", stats.collections, - "collected %zd bytes %.0f%% of %zd garbage clauses", - collected_bytes, - percent (collected_bytes, collected_bytes + moved_bytes), - collected_clauses); -} - -/*------------------------------------------------------------------------*/ - -// Maintaining clause statistics is complex and error prone but necessary -// for proper scheduling of garbage collection, particularly during bounded -// variable elimination. With this function we can check whether these -// statistics are updated correctly. - -void Internal::check_clause_stats () { -#ifndef CADICAL_NDEBUG - int64_t irredundant = 0, redundant = 0, total = 0, irrlits = 0; - for (const auto &c : clauses) { - if (c->garbage) - continue; - if (c->redundant) - redundant++; - else - irredundant++; - if (!c->redundant) - irrlits += c->size; - total++; - } - CADICAL_assert (stats.current.irredundant == irredundant); - CADICAL_assert (stats.current.redundant == redundant); - CADICAL_assert (stats.current.total == total); - CADICAL_assert (stats.irrlits == irrlits); -#endif -} - -/*------------------------------------------------------------------------*/ - -// only delete binary clauses from watch list that are already mark as -// deleted. -void Internal::remove_garbage_binaries () { - if (unsat) - return; - START (collect); - - if (!protected_reasons) - protect_reasons (); - int backtrack_level = level + 1; - Watches saved; - for (auto v : vars) { - for (auto lit : {-v, v}) { - CADICAL_assert (saved.empty ()); - Watches &ws = watches (lit); - const const_watch_iterator end = ws.end (); - watch_iterator j = ws.begin (); - const_watch_iterator i; - for (i = j; i != end; i++) { - Watch w = *i; - *j++ = w; - Clause *c = w.clause; - COVER (!w.binary () && c->size == 2); - if (!w.binary ()) - continue; - if (c->reason && c->garbage) { - COVER (true); - CADICAL_assert (c->size == 2); - backtrack_level = - min (backtrack_level, var (c->literals[0]).level); - LOG ("need to backtrack to before level %d", backtrack_level); - --j; - continue; - } - if (!c->collect ()) - continue; - LOG (c, "removing from watch list"); - --j; - } - ws.resize (j - ws.begin ()); - shrink_vector (ws); - } - } - delete_garbage_clauses (); - unprotect_reasons (); - if (backtrack_level - 1 < level) - backtrack (backtrack_level - 1); - STOP (collect); -} - -/*------------------------------------------------------------------------*/ - -bool Internal::arenaing () { return opts.arena && (stats.collections > 1); } - -void Internal::garbage_collection () { - if (unsat) - return; - START (collect); - report ('G', 1); - stats.collections++; - mark_satisfied_clauses_as_garbage (); - if (!protected_reasons) - protect_reasons (); - if (arenaing ()) - copy_non_garbage_clauses (); - else - delete_garbage_clauses (); - check_clause_stats (); - check_var_stats (); - unprotect_reasons (); - report ('C', 1); - STOP (collect); -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_compact.cpp b/src/sat/cadical/cadical_compact.cpp deleted file mode 100644 index 6747218cb..000000000 --- a/src/sat/cadical/cadical_compact.cpp +++ /dev/null @@ -1,557 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -/*------------------------------------------------------------------------*/ - -// Compacting removes holes generated by inactive variables (fixed, -// eliminated, substituted or pure) by mapping active variables indices down -// to a contiguous interval of indices. - -/*------------------------------------------------------------------------*/ - -bool Internal::compacting () { - if (level) - return false; - if (!opts.compact) - return false; - if (stats.conflicts < lim.compact) - return false; - int inactive = max_var - active (); - CADICAL_assert (inactive >= 0); - if (!inactive) - return false; - if (inactive < opts.compactmin) - return false; - return inactive >= (1e-3 * opts.compactlim) * max_var; -} - -/*------------------------------------------------------------------------*/ - -struct Mapper { - - Internal *internal; - int new_max_var; // New 'max_var' after compacting. - int *table; // Old variable index to new literal map. - int first_fixed; // First fixed variable index. - int map_first_fixed; // Mapped literal of first fixed variable. - signed char first_fixed_val; // Value of first fixed variable. - size_t new_vsize; - - /*----------------------------------------------------------------------*/ - // We produce a compacting garbage collector like map of old 'src' to - // new 'dst' variables. Inactive variables are just skipped except for - // fixed ones which will be mapped to the first fixed variable (in the - // appropriate phase). This avoids to handle the case 'fixed value' - // separately as it is done in Lingeling, where fixed variables are - // mapped to the internal variable '1'. - // - Mapper (Internal *i) - : internal (i), new_max_var (0), first_fixed (0), map_first_fixed (0), - first_fixed_val (0) { - table = new int[internal->max_var + 1u]; - clear_n (table, internal->max_var + 1u); - - CADICAL_assert (!internal->level); - - for (auto src : internal->vars) { - const Flags &f = internal->flags (src); - if (f.active ()) - table[src] = ++new_max_var; - else if (f.fixed () && !first_fixed) - table[first_fixed = src] = map_first_fixed = ++new_max_var; - } - - first_fixed_val = first_fixed ? internal->val (first_fixed) : 0; - new_vsize = new_max_var + 1u; - } - - ~Mapper () { delete[] table; } - - /*----------------------------------------------------------------------*/ - // Map old variable indices. A result of zero means not mapped. - // - int map_idx (int src) { - CADICAL_assert (0 < src); - CADICAL_assert (src <= internal->max_var); - const int res = table[src]; - CADICAL_assert (res <= new_max_var); - return res; - } - - /*----------------------------------------------------------------------*/ - // The 'map_idx' above is just a look-up into the 'table'. Here we have - // to care about signedness of 'src', and in addition that fixed variables - // have all to be mapped to the first fixed variable 'first_fixed'. - // - int map_lit (int src) { - int res = map_idx (abs (src)); - if (!res) { - const signed char tmp = internal->val (src); - if (tmp) { - CADICAL_assert (first_fixed); - res = map_first_fixed; - if (tmp != first_fixed_val) - res = -res; - } - } else if ((src) < 0) - res = -res; - CADICAL_assert (abs (res) <= new_max_var); - return res; - } - - /*----------------------------------------------------------------------*/ - // Map positive variable indices in vector. - // - template void map_vector (vector &v) { - for (auto src : internal->vars) { - const int dst = map_idx (src); - if (!dst) - continue; - CADICAL_assert (0 < dst); - CADICAL_assert (dst <= src); - v[dst] = v[src]; - } - v.resize (new_vsize); - shrink_vector (v); - } - - /*----------------------------------------------------------------------*/ - // Map positive and negative variable indices in two-sided vector. - // - template void map2_vector (vector &v) { - for (auto src : internal->vars) { - const int dst = map_idx (src); - if (!dst) - continue; - CADICAL_assert (0 < dst); - CADICAL_assert (dst <= src); - v[2 * dst] = v[2 * src]; - v[2 * dst + 1] = v[2 * src + 1]; - } - v.resize (2 * new_vsize); - shrink_vector (v); - } - - /*----------------------------------------------------------------------*/ - // Map a vector of literals, flush inactive literals, then resize and - // shrink it to fit the new size after flushing. - // - void map_flush_and_shrink_lits (vector &v) { - const auto end = v.end (); - auto j = v.begin (), i = j; - for (; i != end; i++) { - const int src = *i; - int dst = map_idx (abs (src)); - CADICAL_assert (abs (dst) <= abs (src)); - if (!dst) - continue; - if (src < 0) - dst = -dst; - *j++ = dst; - } - v.resize (j - v.begin ()); - shrink_vector (v); - } -}; - -/*------------------------------------------------------------------------*/ - -static signed char *ignore_clang_analyze_memory_leak_warning; - -void Internal::compact () { - - START (compact); - - CADICAL_assert (active () < max_var); - - stats.compacts++; - - CADICAL_assert (!level); - CADICAL_assert (!unsat); - CADICAL_assert (!conflict); - CADICAL_assert (clause.empty ()); - CADICAL_assert (levels.empty ()); - CADICAL_assert (analyzed.empty ()); - CADICAL_assert (minimized.empty ()); - CADICAL_assert (control.size () == 1); - CADICAL_assert (propagated == trail.size ()); - - garbage_collection (); - - Mapper mapper (this); - - if (mapper.first_fixed) - LOG ("found first fixed %d", - sign (mapper.first_fixed_val) * mapper.first_fixed); - else - LOG ("no variable fixed"); - - if (!assumptions.empty ()) { - CADICAL_assert (!external->assumptions.empty ()); - LOG ("temporarily reset internal assumptions"); - reset_assumptions (); - } - - const bool is_constraint = !constraint.empty (); - if (is_constraint) { - CADICAL_assert (!external->constraint.empty ()); - LOG ("temporarily reset internal constraint"); - reset_constraint (); - } - - /*======================================================================*/ - // In this first part we only map stuff without reallocation / shrinking. - /*======================================================================*/ - - // Flush the external indices. This has to occur before we map 'vals'. - // Also fixes external units. - // - for (auto eidx : external->vars) { - int src = external->e2i[eidx]; - if (!src) { - continue; - } - if (lrat || frat) { - CADICAL_assert (eidx > 0); - CADICAL_assert (external->ext_units.size () >= (size_t) 2 * eidx + 1); - int64_t id1 = external->ext_units[2 * eidx]; - int64_t id2 = external->ext_units[2 * eidx + 1]; - CADICAL_assert (!id1 || !id2); - if (!id1 && !id2) { - int64_t new_id1 = unit_clauses (2 * src); - int64_t new_id2 = unit_clauses (2 * src + 1); - external->ext_units[2 * eidx] = new_id1; - external->ext_units[2 * eidx + 1] = new_id2; - } - } - int dst = mapper.map_lit (src); - LOG ("compact %" PRId64 - " maps external %d to internal %d from internal %d", - stats.compacts, eidx, dst, src); - external->e2i[eidx] = dst; - } - - // Delete garbage units. Needs to occur before resizing unit_clauses - // - if (lrat || frat) { - for (auto src : internal->vars) { - const int dst = mapper.map_idx (src); - CADICAL_assert (dst <= src); - const signed char tmp = internal->val (src); - if (!dst && !tmp) { - unit_clauses (2 * src) = 0; - unit_clauses (2 * src + 1) = 0; - continue; - } - if (!tmp || src == mapper.first_fixed) { - CADICAL_assert (0 < dst); - if (dst == src) - continue; - CADICAL_assert (!unit_clauses (2 * dst) && !unit_clauses (2 * dst + 1)); - unit_clauses (2 * dst) = unit_clauses (2 * src); - unit_clauses (2 * dst + 1) = unit_clauses (2 * src + 1); - unit_clauses (2 * src) = 0; - unit_clauses (2 * src + 1) = 0; - continue; - } - int64_t id = unit_clauses (2 * src); - int lit = src; - if (!id) { - id = unit_clauses (2 * src + 1); - lit = -lit; - } - unit_clauses (2 * src) = 0; - unit_clauses (2 * src + 1) = 0; - CADICAL_assert (id); - } - unit_clauses_idx.resize (2 * mapper.new_vsize); - shrink_vector (unit_clauses_idx); - } - // Map the literals in all clauses. - // - for (const auto &c : clauses) { - CADICAL_assert (!c->garbage); - for (auto &src : *c) { - CADICAL_assert (!val (src)); - int dst; - dst = mapper.map_lit (src); - CADICAL_assert (dst || c->garbage); - src = dst; - } - } - - // Map the blocking literals in all watches. - // - if (!wtab.empty ()) - for (auto lit : lits) - for (auto &w : watches (lit)) - w.blit = mapper.map_lit (w.blit); - - // We first flush inactive variables and map the links in the queue. This - // has to be done before we map the actual links data structure 'links'. - { - int prev = 0, mapped_prev = 0, next; - for (int idx = queue.first; idx; idx = next) { - next = links[idx].next; - if (idx == mapper.first_fixed) - continue; - const int dst = mapper.map_idx (idx); - if (!dst) - continue; - CADICAL_assert (active (idx)); - if (prev) - links[prev].next = dst; - else - queue.first = dst; - links[idx].prev = mapped_prev; - mapped_prev = dst; - prev = idx; - } - if (prev) - links[prev].next = 0; - else - queue.first = 0; - queue.unassigned = queue.last = mapped_prev; - } - - /*======================================================================*/ - // In the second part we map, flush and shrink arrays. - /*======================================================================*/ - - CADICAL_assert (trail.size () == num_assigned); - mapper.map_flush_and_shrink_lits (trail); - propagated = trail.size (); - num_assigned = trail.size (); - if (mapper.first_fixed) { - CADICAL_assert (trail.size () == 1); - var (mapper.first_fixed).trail = 0; // before mapping 'vtab' - } else - CADICAL_assert (trail.empty ()); - - if (!probes.empty ()) - mapper.map_flush_and_shrink_lits (probes); - - if (!sweep_schedule.empty ()) - mapper.map_flush_and_shrink_lits (sweep_schedule); - - /*======================================================================*/ - // In the third part we map stuff and also reallocate memory. - /*======================================================================*/ - - // Now we continue in reverse order of allocated bytes, e.g., see - // 'Internal::enlarge' which reallocates in order of allocated bytes. - - mapper.map_vector (ftab); - mapper.map_vector (parents); - mapper.map_vector (marks); - mapper.map_vector (phases.saved); - mapper.map_vector (phases.forced); - mapper.map_vector (phases.target); - mapper.map_vector (phases.best); - mapper.map_vector (phases.prev); - mapper.map_vector (phases.min); - - // Special code for 'frozentab'. - // - for (auto src : vars) { - const int dst = abs (mapper.map_lit (src)); - if (!dst) - continue; - if (src == dst) - continue; - CADICAL_assert (dst < src); - if ((size_t) src >= frozentab.size ()) - break; - if ((size_t) dst >= frozentab.size ()) - break; - frozentab[dst] += frozentab[src]; - frozentab[src] = 0; - } - frozentab.resize (min (frozentab.size (), mapper.new_vsize)); - shrink_vector (frozentab); - - // Special code for 'relevanttab'. - // - if (external) { - for (auto src : vars) { - const int dst = abs (mapper.map_lit (src)); - if (!dst) - continue; - if (src == dst) - continue; - CADICAL_assert (dst < src); - - relevanttab[dst] += relevanttab[src]; - relevanttab[src] = 0; - } - relevanttab.resize (mapper.new_vsize); - shrink_vector (relevanttab); - } - - /*----------------------------------------------------------------------*/ - - if (!external->assumptions.empty ()) { - - for (const auto &elit : external->assumptions) { - CADICAL_assert (elit); - CADICAL_assert (elit != INT_MIN); - int eidx = abs (elit); - CADICAL_assert (eidx <= external->max_var); - int ilit = external->e2i[eidx]; - CADICAL_assert (ilit); // Because we froze all!!! - if (elit < 0) - ilit = -ilit; - assume (ilit); - } - - PHASE ("compact", stats.compacts, "reassumed %zd external assumptions", - external->assumptions.size ()); - } - - // Special case for 'val' as for 'val' we trade branch less code for - // memory and always allocated an [-maxvar,...,maxvar] array. - { - signed char *new_vals = new signed char[2 * mapper.new_vsize]; - ignore_clang_analyze_memory_leak_warning = new_vals; - new_vals += mapper.new_vsize; - for (auto src : vars) - new_vals[-mapper.map_idx (src)] = vals[-src]; - for (auto src : vars) - new_vals[mapper.map_idx (src)] = vals[src]; - new_vals[0] = 0; - vals -= vsize; - delete[] vals; - vals = new_vals; - vsize = mapper.new_vsize; - } - - // 'constrain' uses 'val', so this code has to be after remapping that - if (is_constraint) { - CADICAL_assert (!level); - CADICAL_assert (!external->constraint.back ()); - for (auto elit : external->constraint) { - CADICAL_assert (elit != INT_MIN); - int eidx = abs (elit); - CADICAL_assert (eidx <= external->max_var); - int ilit = external->e2i[eidx]; - CADICAL_assert (!ilit == !elit); - if (elit < 0) - ilit = -ilit; - LOG ("re adding lit external %d internal %d to constraint", elit, - ilit); - constrain (ilit); - } - PHASE ("compact", stats.compacts, - "added %zd external literals to constraint", - external->constraint.size () - 1); - } - - mapper.map_vector (i2e); - mapper.map2_vector (ptab); - mapper.map_vector (btab); - mapper.map_vector (gtab); - mapper.map_vector (links); - mapper.map_vector (vtab); - if (!ntab.empty ()) - mapper.map2_vector (ntab); - if (!wtab.empty ()) - mapper.map2_vector (wtab); - if (!otab.empty ()) - mapper.map2_vector (otab); - if (!rtab.empty ()) - mapper.map2_vector (rtab); - if (!big.empty ()) - mapper.map2_vector (big); - - /*======================================================================*/ - // In the fourth part we map the binary heap for scores. - /*======================================================================*/ - - // The simplest way to map a binary heap is to get all elements from the - // heap and reinsert them. This could be slightly improved in terms of - // speed if we add a 'flush (int * map)' function to 'Heap', but that is - // pretty complicated and would require that the 'Heap' knows that mapped - // elements with 'zero' destination should be flushed. - - vector saved; - CADICAL_assert (saved.empty ()); - if (!scores.empty ()) { - while (!scores.empty ()) { - const int src = scores.front (); - scores.pop_front (); - const int dst = mapper.map_idx (src); - if (!dst) - continue; - if (src == mapper.first_fixed) - continue; - saved.push_back (dst); - } - scores.erase (); - } - mapper.map_vector (stab); - if (!saved.empty ()) { - for (const auto idx : saved) - scores.push_back (idx); - scores.shrink (); - } - - /*----------------------------------------------------------------------*/ - - PHASE ("compact", stats.compacts, - "reducing internal variables from %d to %d", max_var, - mapper.new_max_var); - - /*----------------------------------------------------------------------*/ - - // Need to adjust the target and best assigned counters too. - - size_t new_target_assigned = 0, new_best_assigned = 0; - - for (auto idx : Range (mapper.new_max_var)) { - if (phases.target[idx]) - new_target_assigned++; - if (phases.best[idx]) - new_best_assigned++; - } - - LOG ("reset target assigned from %zd to %zd", target_assigned, - new_target_assigned); - LOG ("reset best assigned from %zd to %zd", best_assigned, - new_best_assigned); - - target_assigned = new_target_assigned; - best_assigned = new_best_assigned; - no_conflict_until = 0; - notified = 0; - - INIT_EMA (averages.current.trail.fast, opts.ematrailfast); - INIT_EMA (averages.current.trail.slow, opts.ematrailslow); - - /*----------------------------------------------------------------------*/ - - max_var = mapper.new_max_var; - - stats.unused = 0; - stats.inactive = stats.now.fixed = mapper.first_fixed ? 1 : 0; - stats.now.substituted = stats.now.eliminated = stats.now.pure = 0; - - check_var_stats (); - - int64_t delta = opts.compactint * (stats.compacts + 1); - lim.compact = stats.conflicts + delta; - - PHASE ("compact", stats.compacts, - "new compact limit %" PRId64 " after %" PRId64 " conflicts", - lim.compact, delta); - - STOP (compact); -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_condition.cpp b/src/sat/cadical/cadical_condition.cpp deleted file mode 100644 index 8c2f72cf7..000000000 --- a/src/sat/cadical/cadical_condition.cpp +++ /dev/null @@ -1,946 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -/*------------------------------------------------------------------------*/ - -// Globally blocked clause elimination (which we call here 'conditioning') -// is described first in the PhD thesis of Benjamin Kiesl from 2019. An -// extended version, which in particular describes the algorithm implemented -// below is in our invited ATVA'19 paper [KieslHeuleBiere-ATVA'19]. This -// accordingly needs witnesses consisting potentially of more than one -// literal. It is the first technique implemented in CaDiCaL with this -// feature (PR clause elimination thus should work in principle too). - -// Basically globally blocked clauses are like set blocked clauses, except -// that the witness cube (of literals to be flipped during reconstruction) -// can contain variables which are not in the blocked clause. This -// can simulate some interesting global optimizations like 'headlines' from -// the FAN algorithm for ATPG. The technique was actually motivated to -// simulate this optimization. It turns out that globally blocked clauses -// can be seen as 'conditional autarkies', where in essence the condition -// cube is the negation of the globally blocked redundant clause (it -// needs to contain one autarky literal though) and the autarky part -// represents the witness. - -/*------------------------------------------------------------------------*/ - -// Elimination of globally blocked clauses is first tried in regular -// intervals in terms of the number of conflicts. Then the main heuristics -// is to trigger 'condition' if the decision level is above the current -// moving average of the back jump level. - -// TODO We might need to consider less frequent conditioning. - -bool Internal::conditioning () { - - if (!opts.condition) - return false; - if (!preprocessing && !opts.inprocessing) - return false; - if (preprocessing) - CADICAL_assert (lim.preprocessing); - - // Triggered in regular 'opts.conditionint' conflict intervals. - // - if (lim.condition > stats.conflicts) - return false; - - if (!level) - return false; // One decision necessary. - - if (level <= averages.current.jump) - return false; // Main heuristic. - - if (!stats.current.irredundant) - return false; - double remain = active (); - if (!remain) - return false; - double ratio = stats.current.irredundant / remain; - return ratio <= opts.conditionmaxrat; -} - -/*------------------------------------------------------------------------*/ - -// We start with the current assignment and then temporarily unassign -// literals. They are reassigned afterwards. The global state of the CDCL -// solver should not change though. Thus we copied from 'search_unassign' -// in 'backtrack.cpp' what is needed to unassign literals and then from -// 'search_assign' in 'propagate.cpp' what is needed for reassigning -// literals, but restricted the copied code to only updating the actual -// assignment (in 'vals') and not changing anything else. - -// We use temporarily unassigning for two purposes. First, if a conditional -// literal does not occur negated in a candidate clause it is unassigned. -// Second, as a minor optimization, we first unassign all root-level -// assigned (fixed) literals, to avoid checking the decision level of -// literals during the procedure. - -void Internal::condition_unassign (int lit) { - LOG ("condition unassign %d", lit); - CADICAL_assert (val (lit) > 0); - set_val (lit, 0); -} - -void Internal::condition_assign (int lit) { - LOG ("condition assign %d", lit); - CADICAL_assert (!val (lit)); - set_val (lit, 1); -} - -/*------------------------------------------------------------------------*/ - -// The current partition into conditional part and autarky part during -// refinement is represented through a conditional bit in 'marks'. - -inline bool Internal::is_conditional_literal (int lit) const { - return val (lit) > 0 && getbit (lit, 0); -} - -inline bool Internal::is_autarky_literal (int lit) const { - return val (lit) > 0 && !getbit (lit, 0); -} - -inline void Internal::mark_as_conditional_literal (int lit) { - LOG ("marking %d as conditional literal", lit); - CADICAL_assert (val (lit) > 0); - setbit (lit, 0); - CADICAL_assert (is_conditional_literal (lit)); - CADICAL_assert (!is_autarky_literal (lit)); -} - -inline void Internal::unmark_as_conditional_literal (int lit) { - LOG ("unmarking %d as conditional literal", lit); - CADICAL_assert (is_conditional_literal (lit)); - unsetbit (lit, 0); -} - -/*------------------------------------------------------------------------*/ - -// We also need to know the literals which are in the current clause. These -// are just marked (also in 'marks' but with the (signed) upper two bits). -// We need a signed mark here, since we have to distinguish positive and -// negative occurrences of literals in the candidate clause. - -inline bool Internal::is_in_candidate_clause (int lit) const { - return marked67 (lit) > 0; -} - -inline void Internal::mark_in_candidate_clause (int lit) { - LOG ("marking %d as literal of the candidate clause", lit); - mark67 (lit); - CADICAL_assert (is_in_candidate_clause (lit)); - CADICAL_assert (!is_in_candidate_clause (-lit)); -} - -inline void Internal::unmark_in_candidate_clause (int lit) { - LOG ("unmarking %d as literal of the candidate clause", lit); - CADICAL_assert (is_in_candidate_clause (lit)); - unmark67 (lit); -} - -/*------------------------------------------------------------------------*/ - -struct less_conditioned { - bool operator() (Clause *a, Clause *b) { - return !a->conditioned && b->conditioned; - } -}; - -// This is the function for eliminating globally blocked clauses. It is -// triggered during CDCL search according to 'conditioning' above and uses -// the current assignment as basis to find globally blocked clauses. - -long Internal::condition_round (long delta) { - - long limit; -#ifndef CADICAL_QUIET - long props = 0; -#endif - if (LONG_MAX - delta < stats.condprops) - limit = LONG_MAX; - else - limit = stats.condprops + delta; - - size_t initial_trail_level = trail.size (); - int initial_level = level; - - LOG ("initial trail level %zd", initial_trail_level); - - protect_reasons (); - -#if defined(LOGGING) || !defined(CADICAL_NDEBUG) - int additionally_assigned = 0; -#endif - - for (auto idx : vars) { - const signed char tmp = val (idx); - Var &v = var (idx); - if (tmp) { - if (v.level) { - const int lit = tmp < 0 ? -idx : idx; - if (!active (idx)) { - LOG ("temporarily unassigning inactive literal %d", lit); - condition_unassign (lit); - } - if (frozen (idx)) { - LOG ("temporarily unassigning frozen literal %d", lit); - condition_unassign (lit); - } - } - } else if (frozen (idx)) { - LOG ("keeping frozen literal %d unassigned", idx); - } else if (!active (idx)) { - LOG ("keeping inactive literal %d unassigned", idx); - } else { // if (preprocessing) { - if (initial_level == level) { - level++; - LOG ("new condition decision level"); - } - const int lit = decide_phase (idx, true); - condition_assign (lit); - v.level = level; - trail.push_back (lit); -#if defined(LOGGING) || !defined(CADICAL_NDEBUG) - additionally_assigned++; -#endif - } - } - LOG ("assigned %d additional literals", additionally_assigned); - - // We compute statistics about the size of the assignments. - // - // The initial assignment consists of the non-root-level assigned literals - // split into a conditional and an autarky part. The conditional part - // consists of literals assigned true and occurring negated in a clause - // (touch the clause), which does not contain another literal assigned to - // true. This initial partition is the same for all refinements used in - // checking whether a candidate clause is globally blocked. - // - // For each candidate clause some of the conditional literals have to be - // unassigned, and the autarky is shrunken by turning some of the autarky - // literals into conditional literals (which might get unassigned in a - // later refinement though). - // - // The fix-point of this procedure produces a final assignment, which - // consists of the remaining assigned literals, again split into a - // conditional and an autarky part. - // - struct { - size_t assigned, conditional, autarky; - } initial, remain; - - initial.assigned = 0; - for (auto idx : vars) { - const signed char tmp = val (idx); - if (!tmp) - continue; - if (!var (idx).level) - continue; - LOG ("initial assignment %ds", tmp < 0 ? -idx : idx); - initial.assigned++; - } - - PHASE ("condition", stats.conditionings, "initial assignment of size %zd", - initial.assigned); - - // For each candidate clause we refine the assignment (monotonically), - // by unassigning some conditional literals and turning some autarky - // literals into conditionals. - // - // As the conditional part is usually smaller than the autarky part our - // implementation only explicitly maintains the initial conditional part, - // with conditional bit set to true through 'mark_as_conditional_literal'. - // The autarky part consists of all literals assigned true which do not - // have their conditional bit set to true. Since in both cases the - // literal has to be assigned true, we only need a single bit for both the - // literal as well as its negation (it does not have to be 'signed'). - // - vector conditional; - - vector candidates; // Gather candidate clauses. -#ifndef CADICAL_QUIET - size_t watched = 0; // Number of watched clauses. -#endif - - initial.autarky = initial.assigned; // Initially all are in autarky - initial.conditional = 0; // and none in conditional part. - - // Upper bound on the number of watched clauses. In principle one could - // use 'SIZE_MAX' but this is not available by default (yet). - // - const size_t size_max = clauses.size () + 1; - - // Initialize additional occurrence lists. - // - init_occs (); - - // Number of previously conditioned and unconditioned candidates. - // - size_t conditioned = 0, unconditioned = 0; - - // Now go over all (non-garbage) irredundant clauses and check whether - // they are candidates, have to be watched, or whether they force the - // negation of some of their literals to be conditional initially. - // - for (const auto &c : clauses) { - if (c->garbage) - continue; // Can already be ignored. - if (c->redundant) - continue; // Ignore redundant clauses too. - - // First determine the following numbers for the candidate clause - // (restricted to non-root-level assignments). - // - int positive = 0; // Number true literals. - int negative = 0; // Number false literals. - int watch = 0; // True Literal to watch. - // - size_t minsize = size_max; // Number of occurrences of 'watch'. - // - // But also ignore root-level satisfied but not yet garbage clauses. - // - bool satisfied = false; // Root level satisfied. - // - for (const_literal_iterator l = c->begin (); - !satisfied && l != c->end (); l++) { - const int lit = *l; - const signed char tmp = val (lit); - if (tmp && !var (lit).level) - satisfied = (tmp > 0); - else if (tmp < 0) - negative++; - else if (tmp > 0) { - const size_t size = occs (lit).size (); - if (size < minsize) - watch = lit, minsize = size; - positive++; - } - } - if (satisfied) { // Ignore root-level satisfied clauses. - mark_garbage (c); // But mark them as garbage already now. - continue; // ... with next clause 'c'. - } - - // Candidates are clauses with at least a positive literal in it. - // - if (positive > 0) { - LOG (c, "found %d positive literals in candidate", positive); - candidates.push_back (c); - if (c->conditioned) - conditioned++; - else - unconditioned++; - } - - // Only one positive literal in each clauses with also at least one - // negative literal has to be watched in occurrence lists. These - // watched clauses will be checked to contain only negative literals as - // soon such a positive literal is unassigned. If this is the case - // these false literals have to be unassigned and potentially new - // conditional literals have to be determined. - // - // Note that only conditional literals are unassigned. However it does - // not matter that we might also watch autarky literals, because either - // such an autarky literal remains a witness that the clause is - // satisfied as long it remains an autarky literal. Otherwise at one - // point it becomes conditional and is unassigned, but then a - // replacement watch will be searched. - // - if (negative > 0 && positive > 0) { - LOG (c, "found %d negative literals in candidate", negative); - CADICAL_assert (watch); - CADICAL_assert (val (watch) > 0); - Occs &os = occs (watch); - CADICAL_assert (os.size () == minsize); - os.push_back (c); -#ifndef CADICAL_QUIET - watched++; -#endif - LOG (c, "watching %d with %zd occurrences in", watch, minsize); - } - - // The initial global conditional part for the current assignment is - // extracted from clauses with only negative literals. It is the same - // for all considered candidate clauses. These negative literals make up - // the global conditional part, are marked here. - // - if (negative > 0 && !positive) { - - size_t new_conditionals = 0; - - for (const_literal_iterator l = c->begin (); l != c->end (); l++) { - const int lit = *l; - signed char tmp = val (lit); - if (!tmp) - continue; - CADICAL_assert (tmp < 0); - if (!var (lit).level) - continue; // Not unassigned yet! - if (is_conditional_literal (-lit)) - continue; - mark_as_conditional_literal (-lit); - conditional.push_back (-lit); - new_conditionals++; - } - if (new_conditionals > 0) - LOG (c, "marked %zu negations of literals as conditional in", - new_conditionals); - - initial.conditional += new_conditionals; - CADICAL_assert (initial.autarky >= new_conditionals); - initial.autarky -= new_conditionals; - } - - } // End of loop over all clauses to collect candidates etc. - - PHASE ("condition", stats.conditionings, "found %zd candidate clauses", - candidates.size ()); - PHASE ("condition", stats.conditionings, - "watching %zu literals and clauses", watched); - PHASE ("condition", stats.conditionings, - "initially %zd conditional literals %.0f%%", initial.conditional, - percent (initial.conditional, initial.assigned)); - PHASE ("condition", stats.conditionings, - "initially %zd autarky literals %.0f%%", initial.autarky, - percent (initial.autarky, initial.assigned)); -#ifdef LOGGING - for (size_t i = 0; i < conditional.size (); i++) { - LOG ("initial conditional %d", conditional[i]); - CADICAL_assert (is_conditional_literal (conditional[i])); - } - for (size_t i = 0; i < trail.size (); i++) - if (is_autarky_literal (trail[i])) - LOG ("initial autarky %d", trail[i]); -#endif - CADICAL_assert (initial.conditional == conditional.size ()); - CADICAL_assert (initial.assigned == initial.conditional + initial.autarky); - - stats.condassinit += initial.assigned; - stats.condcondinit += initial.conditional; - stats.condautinit += initial.autarky; - stats.condassvars += active (); - - // To speed-up and particularly simplify the code we unassign all - // root-level variables temporarily, actually all inactive assigned - // variables. This allows us to avoid tests on whether an assigned - // literal is actually root-level assigned and thus should be ignored (not - // considered to be assigned). For this to work we have to ignore root - // level satisfied clauses as done above. These are neither candidates - // nor have to be watched. Remaining originally root-level assigned - // literals in clauses are only set to false. - // - for (const auto &lit : trail) - if (fixed (lit)) - condition_unassign (lit); - - // Stack to save temporarily unassigned (conditional) literals. - // - vector unassigned; - - // Make sure to focus on clauses not tried before by marking clauses which - // have been checked before using the 'conditioned' bit of clauses. If all - // candidates have their bit set, we have to reset it. Since the - // assignment might be completely different then last time and thus also - // the set of candidates this method does not really exactly lead to a - // round robin scheme of scheduling clauses. - // - // TODO consider computing conditioned and unconditioned over all clauses. - // - CADICAL_assert (conditioned + unconditioned == candidates.size ()); - if (conditioned && unconditioned) { - stable_sort (candidates.begin (), candidates.end (), - less_conditioned ()); - PHASE ("condition", stats.conditionings, - "focusing on %zd candidates %.0f%% not tried last time", - unconditioned, percent (unconditioned, candidates.size ())); - } else if (conditioned && !unconditioned) { - for (auto const &c : candidates) { - CADICAL_assert (c->conditioned); - c->conditioned = false; // Reset 'conditioned' bit. - } - PHASE ("condition", stats.conditionings, - "all %zd candidates tried before", conditioned); - } else { - CADICAL_assert (!conditioned); - PHASE ("condition", stats.conditionings, "all %zd candidates are fresh", - unconditioned); - } - - // TODO prune assignments further! - // And thus might result in less watched clauses. - // So watching should be done here and not earlier. - // Also, see below, we might need to consider the negation of unassigned - // literals in candidate clauses as being watched. - - // Now try to block all candidate clauses. - // - long blocked = 0; // Number of Successfully blocked clauses. - // -#ifndef CADICAL_QUIET - size_t untried = candidates.size (); -#endif - for (const auto &c : candidates) { - - if (initial.autarky <= 0) - break; - - if (c->reason) - continue; - - bool terminated_or_limit_hit = true; - if (terminated_asynchronously ()) - LOG ("asynchronous termination detected"); - else if (stats.condprops >= limit) - LOG ("condition propagation limit %ld hit", limit); - else - terminated_or_limit_hit = false; - - if (terminated_or_limit_hit) { - PHASE ("condition", stats.conditionings, - "%zd candidates %.0f%% not tried after %ld propagations", - untried, percent (untried, candidates.size ()), props); - break; - } -#ifndef CADICAL_QUIET - untried--; -#endif - CADICAL_assert (!c->garbage); - CADICAL_assert (!c->redundant); - - LOG (c, "candidate"); - c->conditioned = 1; // Next time later. - - // We watch an autarky literal in the clause, and can stop trying to - // globally block the clause as soon it turns into a conditional - // literal and we can not find another one. If the fix-point assignment - // is reached and we still have an autarky literal left the watched one - // is reported as witness for this clause being globally blocked. - // - int watched_autarky_literal = 0; - - // First mark all true literals in the candidate clause and find an - // autarky literal which witnesses that this clause has still a chance - // to be globally blocked. - // - for (const_literal_iterator l = c->begin (); l != c->end (); l++) { - const int lit = *l; - mark_in_candidate_clause (lit); - if (watched_autarky_literal) - continue; - if (!is_autarky_literal (lit)) - continue; - watched_autarky_literal = lit; - - // TODO assign non-assigned literals to false? - // Which might need to trigger watching additional clauses. - } - - if (!watched_autarky_literal) { - LOG ("no initial autarky literal found"); - for (const_literal_iterator l = c->begin (); l != c->end (); l++) - unmark_in_candidate_clause (*l); - continue; - } - - stats.condcands++; // Only now ... - - LOG ("watching first autarky literal %d", watched_autarky_literal); - - // Save assignment sizes for statistics, logging and checking. - // - remain = initial; - - // Position of next conditional and unassigned literal to process in the - // 'conditional' and the 'unassigned' stack. - // - struct { - size_t conditional, unassigned; - } next = {0, 0}; - - CADICAL_assert (unassigned.empty ()); - CADICAL_assert (conditional.size () == initial.conditional); - - while (watched_autarky_literal && stats.condprops < limit && - next.conditional < conditional.size ()) { - - CADICAL_assert (next.unassigned == unassigned.size ()); - - const int conditional_lit = conditional[next.conditional++]; - LOG ("processing next conditional %d", conditional_lit); - CADICAL_assert (is_conditional_literal (conditional_lit)); - - if (is_in_candidate_clause (-conditional_lit)) { - LOG ("conditional %d negated in candidate clause", conditional_lit); - continue; - } - - LOG ("conditional %d does not occur negated in candidate clause", - conditional_lit); - - condition_unassign (conditional_lit); - CADICAL_assert (!is_conditional_literal (conditional_lit)); - unassigned.push_back (conditional_lit); - - CADICAL_assert (remain.assigned > 0); - CADICAL_assert (remain.conditional > 0); - remain.conditional--; - remain.assigned--; - - while (watched_autarky_literal && stats.condprops < limit && - next.unassigned < unassigned.size ()) { - const int unassigned_lit = unassigned[next.unassigned++]; - LOG ("processing next unassigned %d", unassigned_lit); - CADICAL_assert (!val (unassigned_lit)); -#ifndef CADICAL_QUIET - props++; -#endif - stats.condprops++; - - Occs &os = occs (unassigned_lit); - if (os.empty ()) - continue; - - // Traverse all watched clauses of 'unassigned_lit' and find - // replacement watches or if none is found turn the negation of all - // false autarky literals in that clause into conditional literals. - // If one of those autarky literals is the watched autarky literal - // in the candidate clause, that one has to be updated too. - // - // We expect that this loop is a hot-spot for the procedure and thus - // are more careful about accessing end points for iterating. - // - auto i = os.begin (), j = i; - for (; watched_autarky_literal && j != os.end (); j++) { - Clause *d = *i++ = *j; - - int replacement = 0; // New watched literal in 'd'. - int negative = 0; // Negative autarky literals in 'd'. - - for (const_literal_iterator l = d->begin (); l != d->end (); - l++) { - const int lit = *l; - const signed char tmp = val (lit); - if (tmp > 0) - replacement = lit; - if (tmp < 0 && is_autarky_literal (-lit)) - negative++; - } - - if (replacement) { - LOG ("found replacement %d for unassigned %d", replacement, - unassigned_lit); - LOG (d, "unwatching %d in", unassigned_lit); - i--; // Drop watch! - LOG (d, "watching %d in", replacement); - - CADICAL_assert (replacement != unassigned_lit); - occs (replacement).push_back (d); - - continue; // ... with next watched clause 'd'. - } - - LOG ("no replacement found for unassigned %d", unassigned_lit); - - // Keep watching 'd' by 'unassigned_lit' if no replacement found. - - if (!negative) { - LOG (d, "no negative autarky literals left in"); - continue; // ... with next watched clause 'd'. - } - - LOG (d, "found %d negative autarky literals in", negative); - - for (const_literal_iterator l = d->begin (); - watched_autarky_literal && l != d->end (); l++) { - const int lit = *l; - if (!is_autarky_literal (-lit)) - continue; - mark_as_conditional_literal (-lit); - conditional.push_back (-lit); - - remain.conditional++; - CADICAL_assert (remain.autarky > 0); - remain.autarky--; - - if (-lit != watched_autarky_literal) - continue; - - LOG ("need to replace autarky literal %d in candidate", -lit); - replacement = 0; - - // TODO save starting point because we only move it forward? - - for (const_literal_iterator k = c->begin (); - !replacement && k != c->end (); k++) { - const int other = *k; - if (is_autarky_literal (other)) - replacement = other; - } - watched_autarky_literal = replacement; - - if (replacement) { - LOG (c, "watching autarky %d instead %d in candidate", - replacement, watched_autarky_literal); - watched_autarky_literal = replacement; - } else { - LOG ("failed to find an autarky replacement"); - watched_autarky_literal = 0; // Breaks out of 4 loops!!!!! - } - } // End of loop of turning autarky literals into conditionals. - } // End of loop of all watched clauses of an unassigned literal. - // - // We might abort the occurrence traversal early but already - // removed some watches, thus have to just copy the rest. - // - if (i < j) { - while (j != os.end ()) - *i++ = *j++; - LOG ("flushed %zd occurrences of %d", os.end () - i, - unassigned_lit); - os.resize (i - os.begin ()); - } - } // End of loop which goes over all unprocessed unassigned literals. - } // End of loop which goes over all unprocessed conditional literals. - - // We are still processing the candidate 'c' and now have reached a - // final fix-point assignment partitioned into a conditional and an - // autarky part, or during unassigned literals figured that there is no - // positive autarky literal left in 'c'. - - LOG ("remaining assignment of size %zd", remain.assigned); - LOG ("remaining conditional part of size %zd", remain.conditional); - LOG ("remaining autarky part of size %zd", remain.autarky); - // - CADICAL_assert (remain.assigned - remain.conditional == remain.autarky); - // -#if defined(LOGGING) || !defined(CADICAL_NDEBUG) - // - // This is a sanity check, that the size of our implicit representation - // of the autarky part matches our 'remain' counts. We need the same - // code for determining autarky literals as in the loop below which adds - // autarky literals to the extension stack. - // - struct { - size_t assigned, conditional, autarky; - } check; - check.assigned = check.conditional = check.autarky = 0; - for (size_t i = 0; i < trail.size (); i++) { - const int lit = trail[i]; - if (val (lit)) { - check.assigned++; - if (is_conditional_literal (lit)) { - LOG ("remaining conditional %d", lit); - CADICAL_assert (!is_autarky_literal (lit)); - check.conditional++; - } else { - CADICAL_assert (is_autarky_literal (lit)); - LOG ("remaining autarky %d", lit); - check.autarky++; - } - } else { - CADICAL_assert (!is_autarky_literal (lit)); - CADICAL_assert (!is_conditional_literal (lit)); - } - } - CADICAL_assert (remain.assigned == check.assigned); - CADICAL_assert (remain.conditional == check.conditional); - CADICAL_assert (remain.autarky == check.autarky); -#endif - - // Success if an autarky literal is left in the clause and - // we did not abort the loop too early because the propagation - // limit was hit. - // - if (watched_autarky_literal && stats.condprops < limit) { - CADICAL_assert (is_autarky_literal (watched_autarky_literal)); - CADICAL_assert (is_in_candidate_clause (watched_autarky_literal)); - - blocked++; - stats.conditioned++; - LOG (c, "positive autarky literal %d globally blocks", - watched_autarky_literal); - - LOG ("remaining %zd assigned literals %.0f%%", remain.assigned, - percent (remain.assigned, initial.assigned)); - LOG ("remaining %zd conditional literals %.0f%%", remain.conditional, - percent (remain.conditional, remain.assigned)); - LOG ("remaining %zd autarky literals %.0f%%", remain.autarky, - percent (remain.autarky, remain.assigned)); - - // A satisfying assignment of a formula after removing a globally - // blocked clause might not satisfy that clause. As for variable - // elimination and classical blocked clauses, we thus maintain an - // extension stack for reconstructing an assignment which both - // satisfies the remaining formula as well as the clause. - // - // For globally blocked clauses we simply have to flip all literals in - // the autarky part and thus save the autarky on the extension stack - // in addition to the removed clause. In the classical situation (in - // bounded variable elimination etc.) we simply save one literal on - // the extension stack. - // - // TODO find a way to shrink the autarky part or some other way to - // avoid pushing too many literals on the extension stack. - // - external->push_zero_on_extension_stack (); - for (const auto &lit : trail) - if (is_autarky_literal (lit)) - external->push_witness_literal_on_extension_stack (lit); - if (proof) - proof->weaken_minus (c); - external->push_clause_on_extension_stack (c); - - mark_garbage (c); - - stats.condassrem += remain.assigned; - stats.condcondrem += remain.conditional; - stats.condautrem += remain.autarky; - stats.condassirem += initial.assigned; - } - - // In this last part specific to one candidate clause, we have to get - // back to the initial assignment and reset conditionals. First we - // assign all the unassigned literals (if necessary). - // - if (!unassigned.empty ()) { - LOG ("reassigning %zd literals", unassigned.size ()); - while (!unassigned.empty ()) { - const int lit = unassigned.back (); - unassigned.pop_back (); - condition_assign (lit); - } - } - - // Then we remove from the conditional stack autarky literals which - // became conditional and also reset their 'conditional' bit. - // - if (initial.conditional < conditional.size ()) { - LOG ("flushing %zd autarky literals from conditional stack", - conditional.size () - initial.conditional); - while (initial.conditional < conditional.size ()) { - const int lit = conditional.back (); - conditional.pop_back (); - unmark_as_conditional_literal (lit); - } - } - - // Finally unmark all literals in the candidate clause. - // - for (const_literal_iterator l = c->begin (); l != c->end (); l++) - unmark_in_candidate_clause (*l); - - } // End of loop over all candidate clauses. - - PHASE ("condition", stats.conditionings, - "globally blocked %ld clauses %.0f%%", blocked, - percent (blocked, candidates.size ())); - - // Unmark initial conditional variables. - // - for (const auto &lit : conditional) - unmark_as_conditional_literal (lit); - - erase_vector (unassigned); - erase_vector (conditional); - erase_vector (candidates); - - // Unassign additionally assigned literals. - // -#if defined(LOGGING) || !defined(CADICAL_NDEBUG) - int additionally_unassigned = 0; -#endif - while (trail.size () > initial_trail_level) { - int lit = trail.back (); - trail.pop_back (); - condition_unassign (lit); -#if defined(LOGGING) || !defined(CADICAL_NDEBUG) - additionally_unassigned++; -#endif - } - LOG ("unassigned %d additionally assigned literals", - additionally_unassigned); - CADICAL_assert (additionally_unassigned == additionally_assigned); - - if (level > initial_level) { - LOG ("reset condition decision level"); - level = initial_level; - } - - reset_occs (); - delete_garbage_clauses (); - - // Reassign previously assigned variables again. - // - LOG ("reassigning previously assigned variables"); - for (size_t i = 0; i < initial_trail_level; i++) { - const int lit = trail[i]; - const signed char tmp = val (lit); - CADICAL_assert (tmp >= 0); - if (!tmp) - condition_assign (lit); - } - -#ifndef CADICAL_NDEBUG - for (const auto &lit : trail) - CADICAL_assert (!marked (lit)); -#endif - - unprotect_reasons (); - - return blocked; -} - -void Internal::condition (bool update_limits) { - - if (unsat) - return; - if (!stats.current.irredundant) - return; - - START_SIMPLIFIER (condition, CONDITION); - stats.conditionings++; - - // Propagation limit to avoid too much work in 'condition'. We mark - // tried candidate clauses after giving up, such that next time we run - // 'condition' we can try them. - // - long limit = stats.propagations.search; - limit *= opts.conditioneffort; - limit /= 1000; - if (limit < opts.conditionmineff) - limit = opts.conditionmineff; - if (limit > opts.conditionmaxeff) - limit = opts.conditionmaxeff; - CADICAL_assert (stats.current.irredundant); - limit *= 2.0 * active () / (double) stats.current.irredundant; - limit = max (limit, 2l * active ()); - - PHASE ("condition", stats.conditionings, - "started after %" PRIu64 " conflicts limited by %ld propagations", - stats.conflicts, limit); - - long blocked = condition_round (limit); - - STOP_SIMPLIFIER (condition, CONDITION); - report ('g', !blocked); - - if (!update_limits) - return; - - long delta = opts.conditionint * (stats.conditionings + 1); - lim.condition = stats.conflicts + delta; - - PHASE ("condition", stats.conditionings, - "next limit at %" PRIu64 " after %ld conflicts", lim.condition, - delta); -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_config.cpp b/src/sat/cadical/cadical_config.cpp deleted file mode 100644 index d4268790c..000000000 --- a/src/sat/cadical/cadical_config.cpp +++ /dev/null @@ -1,107 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -/*------------------------------------------------------------------------*/ - -struct NameVal { - const char *name; - int val; -}; - -/*------------------------------------------------------------------------*/ - -// These are dummy configurations, which require additional code. - -static NameVal default_config[1]; // With '-pedantic' just '[]' or -static NameVal plain_config[1]; // '[0]' gave a warning. - -/*------------------------------------------------------------------------*/ - -// Here we have the pre-defined default configurations. - -static NameVal sat_config[] = { - {"elimeffort", 10}, - {"stabilizeonly", 1}, - {"subsumeeffort", 60}, -}; - -static NameVal unsat_config[] = { - {"stabilize", 0}, - {"walk", 0}, -}; - -/*------------------------------------------------------------------------*/ - -#define CONFIGS \ -\ - CONFIG (default, "set default advanced internal options") \ - CONFIG (plain, "disable all internal preprocessing options") \ - CONFIG (sat, "set internal options to target satisfiable instances") \ - CONFIG (unsat, "set internal options to target unsatisfiable instances") - -static const char *configs[] = { -#define CONFIG(N, D) #N, - CONFIGS -#undef CONFIG -}; - -static size_t num_configs = sizeof configs / sizeof *configs; - -/*------------------------------------------------------------------------*/ - -bool Config::has (const char *name) { -#define CONFIG(N, D) \ - if (!strcmp (name, #N)) \ - return true; - CONFIGS -#undef CONFIG - return false; -} - -bool Config::set (Options &opts, const char *name) { - if (!strcmp (name, "default")) { - opts.reset_default_values (); - return true; - } - if (!strcmp (name, "plain")) { - opts.disable_preprocessing (); - return true; - } -#define CONFIG(N, D) \ - do { \ - if (strcmp (name, #N)) \ - break; \ - const NameVal *BEGIN = N##_config; \ - const NameVal *END = BEGIN + sizeof N##_config / sizeof (NameVal); \ - for (const NameVal *P = BEGIN; P != END; P++) { \ - CADICAL_assert (Options::has (P->name)); \ - opts.set (P->name, P->val); \ - } \ - return true; \ - } while (0); - CONFIGS -#undef CONFIG - return false; -} - -/*------------------------------------------------------------------------*/ - -void Config::usage () { -#define CONFIG(N, D) printf (" %-14s " D "\n", "--" #N); - CONFIGS -#undef CONFIG -} - -/*------------------------------------------------------------------------*/ - -const char **Config::begin () { return configs; } -const char **Config::end () { return &configs[num_configs]; } - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_congruence.cpp b/src/sat/cadical/cadical_congruence.cpp deleted file mode 100644 index 8fbceee24..000000000 --- a/src/sat/cadical/cadical_congruence.cpp +++ /dev/null @@ -1,7567 +0,0 @@ -#include "global.h" - -#include "congruence.hpp" -#include "internal.hpp" -#include -#include -#include -#include -#include - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -Closure::Closure (Internal *i) - : internal (i), table (128, Hash (nonces)) -#ifdef LOGGING - , - fresh_id (internal->clause_id) -#endif -{ -} - -char &Closure::lazy_propagated (int lit) { - return lazy_propagated_idx[internal->vidx (lit)]; -} - -void update_ite_flags (Gate *g) { - int8_t f = g->degenerated_ite; - const int lhs = g->lhs; - const int cond = g->rhs [0]; - const int then_lit = g->rhs[1]; - const int else_lit = g->rhs[2]; - - if (lhs == cond) { - f |= Special_ITE_GATE::NO_NEG_THEN; - f |= Special_ITE_GATE::NO_PLUS_ELSE; - } - if (lhs == -cond) { - f |= Special_ITE_GATE::NO_PLUS_THEN; - f |= Special_ITE_GATE::NO_NEG_ELSE; - } - if (lhs == then_lit) { - f |= Special_ITE_GATE::NO_PLUS_THEN; - f |= Special_ITE_GATE::NO_NEG_THEN; - } - if (lhs == else_lit) { - f |= Special_ITE_GATE::NO_PLUS_ELSE; - f |= Special_ITE_GATE::NO_NEG_ELSE; - } - g->degenerated_ite = f; - CADICAL_assert (lhs != -then_lit); - CADICAL_assert (lhs != -else_lit); - CADICAL_assert (cond != then_lit); - CADICAL_assert (cond != else_lit); - CADICAL_assert (cond != -then_lit); - CADICAL_assert (cond != -else_lit); -} - -void check_correct_ite_flags (const Gate *const g) { -#ifndef CADICAL_NDEBUG - const int8_t f = g->degenerated_ite; - const int lhs = g->lhs; - const int cond = g->rhs [0]; - const int then_lit = g->rhs[1]; - const int else_lit = g->rhs[2]; - CADICAL_assert (g->pos_lhs_ids.size () == 4); - if (g->pos_lhs_ids[0].clause == nullptr) - CADICAL_assert ((f & Special_ITE_GATE::NO_PLUS_THEN)); - if (g->pos_lhs_ids[1].clause == nullptr) - CADICAL_assert (f & Special_ITE_GATE::NO_NEG_THEN); - if (g->pos_lhs_ids[2].clause == nullptr) - CADICAL_assert (f & Special_ITE_GATE::NO_PLUS_ELSE); - if (g->pos_lhs_ids[3].clause == nullptr) - CADICAL_assert (f & Special_ITE_GATE::NO_NEG_ELSE); - if (lhs == cond) { - CADICAL_assert (f & Special_ITE_GATE::NO_NEG_THEN); - CADICAL_assert (f & Special_ITE_GATE::NO_PLUS_ELSE); - } - if (lhs == -cond) { - CADICAL_assert (f & Special_ITE_GATE::NO_PLUS_THEN); - CADICAL_assert (f & Special_ITE_GATE::NO_NEG_ELSE); - } - if (lhs == then_lit) { - CADICAL_assert (f & Special_ITE_GATE::NO_PLUS_THEN); - CADICAL_assert (f & Special_ITE_GATE::NO_NEG_THEN); - } - if (lhs == else_lit) { - CADICAL_assert (f & Special_ITE_GATE::NO_PLUS_ELSE); - CADICAL_assert (f & Special_ITE_GATE::NO_NEG_ELSE); - } - CADICAL_assert (lhs != -then_lit); - CADICAL_assert (lhs != -else_lit); - CADICAL_assert (cond != then_lit); - CADICAL_assert (cond != else_lit); - CADICAL_assert (cond != -then_lit); - CADICAL_assert (cond != -else_lit); -#else - (void)g; -#endif -} - -/*------------------------------------------------------------------------*/ - -static size_t hash_lits (std::array &nonces, - const vector &lits) { - size_t hash = 0; - const auto end_nonces = end (nonces); - const auto begin_nonces = begin (nonces); - auto n = begin_nonces; - for (auto lit : lits) { - hash += lit; - hash *= *n++; - hash = (hash << 4) | (hash >> 60); - if (n == end_nonces) - n = begin_nonces; - } - hash ^= hash >> 32; - return hash; -} - -size_t Hash::operator() (const Gate *const g) const { - CADICAL_assert (hash_lits (nonces, g->rhs) == g->hash); - return g->hash; -} - -bool gate_contains (Gate *g, int lit) { - return find (begin (g->rhs), end (g->rhs), lit) != end (g->rhs); -} -/*------------------------------------------------------------------------*/ -struct compact_binary_rank { - typedef uint64_t Type; - uint64_t operator() (const CompactBinary &a) { - return ((uint64_t) a.lit1 << 32) + a.lit2; - }; -}; - -struct compact_binary_order { - bool operator() (const CompactBinary &a, const CompactBinary &b) { - return compact_binary_rank () (a) < compact_binary_rank () (b); - }; -}; - -bool Closure::find_binary (int lit, int other) const { - const auto offsize = - offsetsize[internal->vlit (lit)]; // in C++17: [offset, size] = - const auto offset = offsize.first; - const auto size = offsize.second; - const auto begin = std::begin (binaries) + offset; - const auto end = std::begin (binaries) + size; - CADICAL_assert (end <= std::end (binaries)); - const CompactBinary target = CompactBinary (nullptr, 0, lit, other); - auto it = std::lower_bound (begin, end, target, compact_binary_order ()); - // search_binary only returns a bool - bool found = (it != end && it->lit1 == lit && it->lit2 == other); - if (found) { - LOG ("found binary [%zd] %d %d", it->id, lit, other); - if (internal->lrat) - lrat_chain.push_back (it->id); - } - return found; -} - -void Closure::extract_binaries () { - if (!internal->opts.congruencebinaries) - return; - START (extractbinaries); - offsetsize.resize (internal->max_var * 2 + 3, make_pair (0, 0)); - - // in kissat this is done during watch clearing. TODO: consider doing this - // too. - for (Clause *c : internal->clauses) { - if (c->garbage) - continue; - if (c->redundant && c->size != 2) - continue; - if (c->size > 2) - continue; - CADICAL_assert (c->size == 2); - const int lit = c->literals[0]; - const int other = c->literals[1]; - const bool already_sorted = - internal->vlit (lit) < internal->vlit (other); - binaries.push_back (CompactBinary (c, c->id, - already_sorted ? lit : other, - already_sorted ? other : lit)); - } - - MSORT (internal->opts.radixsortlim, begin (binaries), end (binaries), - compact_binary_rank (), compact_binary_order ()); - - { - const size_t size = binaries.size (); - size_t i = 0; - while (i < size) { - CompactBinary bin = binaries[i]; - const int lit = bin.lit1; - size_t j = i; - while (j < size && binaries[j].lit1 == lit) { - ++j; - } - CADICAL_assert (j >= i); - CADICAL_assert (j <= size); - offsetsize[internal->vlit (lit)] = make_pair (i, j); - i = j; - } - } - - size_t extracted = 0, already_present = 0, duplicated = 0; - - const size_t size = internal->clauses.size (); - for (size_t i = 0; i < size; ++i) { - Clause *d = internal->clauses[i]; // binary clauses are appended, so - // reallocation possible - if (d->garbage) - continue; - if (d->redundant) - continue; - if (d->size != 3) - continue; - const int *lits = d->literals; - const int a = lits[0]; - const int b = lits[1]; - const int c = lits[2]; // obfuscating d->literals[2] which triggers an error in pedandic mode - if (internal->val (a)) - continue; - if (internal->val (b)) - continue; - if (internal->val (c)) - continue; - int l = 0, k = 0; - if (find_binary (-a, b) || find_binary (-a, c)) { - l = b, k = c; - } else if (find_binary (-b, a) || find_binary (-b, c)) { - l = a, k = c; - } else if (find_binary (-c, a) || find_binary (-c, b)) { - l = a, k = b; - } else - continue; - LOG (d, "strengthening"); - if (!find_binary (l, k)) { - if (internal->lrat) - lrat_chain.push_back (d->id); - add_binary_clause (l, k); - ++extracted; - } else { - ++already_present; - if (internal->lrat) - lrat_chain.clear (); - } - } - lrat_chain.clear (); - - offsetsize.clear (); - - // kissat has code to remove duplicates, which we have already removed - // before starting congruence - MSORT (internal->opts.radixsortlim, begin (binaries), end (binaries), - compact_binary_rank (), compact_binary_order ()); - const size_t new_size = binaries.size (); - { - size_t i = 0; - for (size_t j = 1; j < new_size; ++j) { - CADICAL_assert (i < j); - if (binaries[i].lit1 == binaries[j].lit1 && - binaries[i].lit2 == binaries[j].lit2) { - // subsuming later clause - subsume_clause (binaries[i].clause, - binaries[j].clause); // the local one is specialized - ++duplicated; - } else { - binaries[++i] = binaries[j]; - } - } - CADICAL_assert (i <= new_size); - binaries.resize (i); - } - binaries.clear (); - STOP (extractbinaries); - LOG ("extracted %zu binaries (plus %zu already present and %zu " - "duplicates)", - extracted, already_present, duplicated); -} - -/*------------------------------------------------------------------------*/ -// marking structure for congruence closure, by reference -signed char &Closure::marked (int lit) { - CADICAL_assert (internal->vlit (lit) < marks.size ()); - return marks[internal->vlit (lit)]; -} - -void Closure::unmark_all () { - for (auto lit : internal->analyzed) { - CADICAL_assert (marked (lit)); - marked (lit) = 0; - } - internal->analyzed.clear (); -} - -void Closure::set_mu1_reason (int lit, Clause *c) { - CADICAL_assert (marked (lit) & 1); - LOG (c, "mu1 %d -> %zd", lit, c->id); - mu1_ids[internal->vlit (lit)] = LitClausePair (lit, c); -} - -void Closure::set_mu2_reason (int lit, Clause *c) { - CADICAL_assert (marked (lit) & 2); - if (!internal->lrat) - return; - LOG (c, "mu2 %d -> %zd", lit, c->id); - mu2_ids[internal->vlit (lit)] = LitClausePair (lit, c); -} - -void Closure::set_mu4_reason (int lit, Clause *c) { - CADICAL_assert (marked (lit) & 4); - if (!internal->lrat) - return; - LOG (c, "mu4 %d -> %zd", lit, c->id); - mu4_ids[internal->vlit (lit)] = LitClausePair (lit, c); -} - -LitClausePair Closure::marked_mu1 (int lit) { - return mu1_ids[internal->vlit (lit)]; -} - -LitClausePair Closure::marked_mu2 (int lit) { - return mu2_ids[internal->vlit (lit)]; -} - -LitClausePair Closure::marked_mu4 (int lit) { - return mu4_ids[internal->vlit (lit)]; -} - -struct sort_literals_by_var_rank { - CaDiCaL::Internal *internal; - sort_literals_by_var_rank (Internal *i) : internal (i) {} - - typedef uint64_t Type; - - Type operator() (const int &a) const { return internal->vlit (a); } -}; -struct sort_literals_by_var_rank_except { - CaDiCaL::Internal *internal; - int lhs; - int except; - sort_literals_by_var_rank_except (Internal *i, int my_lhs, int except2) - : internal (i), lhs (my_lhs), except (except2) {} - sort_literals_by_var_rank_except (Internal *i, int my_lhs) - : internal (i), lhs (my_lhs), except (0) {} - typedef uint64_t Type; - Type operator() (const int &a) const { - Type res = 0; - if (abs (a) == abs (except)) - res = 1 - (a > 0); - else if (abs (a) == abs (lhs)) - res = 3 - (a > 0); - else - res = internal->vlit (a) + 2; // probably +2 enough - return ~res; - } -}; - -struct sort_literals_by_var_smaller_except { - CaDiCaL::Internal *internal; - int lhs; - int except; - sort_literals_by_var_smaller_except (Internal *i, int my_lhs, int except2) - : internal (i), lhs (my_lhs), except (except2) {} - sort_literals_by_var_smaller_except (Internal *i, int my_lhs) - : internal (i), lhs (my_lhs), except (0) {} - bool operator() (const int &a, const int &b) const { - return sort_literals_by_var_rank_except (internal, lhs, except) (a) < - sort_literals_by_var_rank_except (internal, lhs, except) (b); - if (abs (a) == abs (except) && abs (b) != abs (except)) - return false; - if (abs (a) != abs (except) && abs (b) == abs (except)) - return true; - if (abs (a) == abs (lhs) && abs (b) != abs (lhs)) - return false; - if (abs (a) != abs (lhs) && abs (b) == abs (lhs)) - return true; - return sort_literals_by_var_rank (internal) (a) > - sort_literals_by_var_rank (internal) (b); - } -}; -struct sort_literals_by_var_smaller { - CaDiCaL::Internal *internal; - sort_literals_by_var_smaller (Internal *i) : internal (i) {} - bool operator() (const int &a, const int &b) const { - return sort_literals_by_var_rank (internal) (a) < - sort_literals_by_var_rank (internal) (b); - } -}; - -void Closure::sort_literals_by_var_except (vector &rhs, int lhs, - int except2) { - MSORT (internal->opts.radixsortlim, begin (rhs), end (rhs), - sort_literals_by_var_rank_except (internal, lhs, except2), - sort_literals_by_var_smaller_except (internal, lhs, except2)); -} -void Closure::sort_literals_by_var (vector &rhs) { - MSORT (internal->opts.radixsortlim, begin (rhs), end (rhs), - sort_literals_by_var_rank (internal), - sort_literals_by_var_smaller (internal)); -} -/*------------------------------------------------------------------------*/ -int &Closure::representative (int lit) { - CADICAL_assert (internal->vlit (lit) < representant.size ()); - return representant[internal->vlit (lit)]; -} -int Closure::representative (int lit) const { - CADICAL_assert (internal->vlit (lit) < representant.size ()); - return representant[internal->vlit (lit)]; -} - -int &Closure::eager_representative (int lit) { - CADICAL_assert (internal->vlit (lit) < eager_representant.size ()); - return eager_representant[internal->vlit (lit)]; -} - -int Closure::eager_representative (int lit) const { - CADICAL_assert (internal->vlit (lit) < eager_representant.size ()); - return eager_representant[internal->vlit (lit)]; -} - -int Closure::find_lrat_representative_with_marks (int lit) { - int res = lit; - int nxt = lit; - do { - res = nxt; - nxt = representative (nxt); - if (nxt != res) { - LOG ("%d has reason %" PRIu64, res, representative_id (res)); - lrat_chain.push_back (representative_id (res)); - } - } while (nxt != res || marked (nxt) || marked (-nxt)); - - return nxt; -} -int Closure::find_representative (int lit) { - int res = lit; - int nxt = lit; - do { - res = nxt; - nxt = representative (nxt); - } while (nxt != res); - - return res; -} - -int Closure::find_representative_and_compress (int lit, bool update_eager) { - LOG ("finding representative of %d", lit); - int res = lit; - int nxt = lit; - int path_length = 0; - do { - res = nxt; - nxt = representative (nxt); - ++path_length; - LOG ("updating %d -> %d", res, nxt); - } while (nxt != res); - - if (path_length > 2) { - LOG ("learning new rewriting from %d to %d (current path length: %d)", - lit, res, path_length); - if (update_eager) - eager_representative (lit) = res; - if (internal->lrat) { - produce_representative_lrat (lit); - Clause *equiv = add_tmp_binary_clause (-lit, res); - - if (equiv) { - representative_id (lit) = equiv->id; - if (update_eager) - eager_representative_id (lit) = equiv->id; - } - } - if (internal->lrat) - lrat_chain.clear (); - } else if (path_length == 2) { - if (update_eager) { - LOG ("updating information %d -> %d in eager", lit, res); - eager_representative (lit) = res; - if (internal->lrat) - eager_representative_id (lit) = representative_id (lit); - CADICAL_assert (!internal->lrat || eager_representative_id (lit)); - } - } - - if (lit != res) { - representative (lit) = res; - } - LOG ("representative of %d is %d", lit, res); - return res; -} - -void Closure::push_lrat_unit (int lit) { - if (!internal->lrat) - return; - CADICAL_assert (internal->val (lit) > 0); - LRAT_ID id = internal->unit_id (lit); - lrat_chain.push_back (id); -} - -int Closure::find_eager_representative (int lit) { - int res = lit; - int nxt = lit; - do { - res = nxt; - nxt = eager_representative (nxt); - } while (nxt != res); - - return res; -} - -int Closure::find_eager_representative_and_compress (int lit) { - if (!internal->lrat) - return find_representative (lit); - int res = lit; - int nxt = lit; - int path_length = 0; - do { - res = nxt; - nxt = eager_representative (nxt); - ++path_length; - } while (nxt != res); - - // CADICAL_assert (res == find_representative (lit)); - // we have to do path compression to support LRAT proofs - if (path_length > 2) { - LOG ("learning new rewriting from %d to %d (current path length: %d)", - lit, res, path_length); - std::vector tmp_lrat_chain; - if (internal->lrat) { - tmp_lrat_chain = std::move (lrat_chain); - lrat_chain.clear (); - produce_eager_representative_lrat (lit); - } - eager_representative (lit) = res; - Clause *equiv = add_tmp_binary_clause (-lit, res); - equiv->hyper = true; - - if (internal->lrat && equiv) { - eager_representative_id (lit) = equiv->id; - } - if (internal->lrat) { - lrat_chain = std::move (tmp_lrat_chain); - } - } else if (path_length == 2) { - LOG ("duplicated information %d -> %d to eager with clause %" PRIu64, - lit, res, eager_representative_id (lit)); - CADICAL_assert (eager_representative (lit) == res); - CADICAL_assert (!internal->lrat || eager_representative_id (lit)); - } - CADICAL_assert (internal->clause.empty ()); - return res; -} - -void Closure::find_representative_and_compress_both (int lit) { - find_representative_and_compress (lit, false); - find_representative_and_compress (-lit, false); -} - -void Closure::import_lazy_and_find_eager_representative_and_compress_both ( - int lit) { - find_representative_and_compress (lit); - find_eager_representative_and_compress (lit); - find_representative_and_compress (-lit); - find_eager_representative_and_compress (-lit); -} - -void Closure::produce_representative_lrat (int lit) { - CADICAL_assert (internal->lrat); - LOG ("production of LRAT chain for %d with representative %" PRIu64, lit, - representative_id (lit)); - CADICAL_assert (internal->lrat); - CADICAL_assert (lrat_chain.empty ()); - int res = lit; - int nxt = lit; - CADICAL_assert (nxt != representative (nxt)); - do { - res = nxt; - nxt = representative (nxt); - if (nxt != res) { - LOG ("%d has reason %" PRIu64, res, representative_id (res)); - lrat_chain.push_back (representative_id (res)); - } - } while (nxt != res); -} - -void Closure::produce_eager_representative_lrat (int lit) { - CADICAL_assert (internal->lrat); - LOG ("production of LRAT chain for %d with representative %" PRIu64, lit, - eager_representative_id (lit)); - CADICAL_assert (internal->lrat); - CADICAL_assert (lrat_chain.empty ()); - int res = lit; - int nxt = lit; - CADICAL_assert (nxt != eager_representative (nxt)); - do { - res = nxt; - nxt = eager_representative (nxt); - if (nxt != res) { - LOG ("%d has reason %" PRIu64, res, eager_representative_id (res)); - lrat_chain.push_back (eager_representative_id (res)); - } - } while (nxt != res); -} - -LRAT_ID Closure::find_representative_lrat (int lit) { - if (!internal->lrat) - return 0; - int res = lit; -#ifndef CADICAL_NDEBUG - int nxt = representative (res); - CADICAL_assert (nxt == representative (res)); -#endif - LOG ("checking for existing LRAT chain for %d with clause %" PRIu64, lit, - eager_representative_id (res)); - CADICAL_assert (representative_id (res)); - return representative_id (res); -} - -LRAT_ID Closure::find_eager_representative_lrat (int lit) { - if (!internal->lrat) - return 0; - int res = lit; -#ifndef CADICAL_NDEBUG - int nxt = eager_representative (res); - CADICAL_assert (nxt == eager_representative (res)); -#endif - LOG ("checking for existing LRAT chain for %d with clause %" PRIu64, lit, - eager_representative_id (res)); - CADICAL_assert (eager_representative_id (res)); - return eager_representative_id (res); -} - -LRAT_ID &Closure::eager_representative_id (int lit) { - CADICAL_assert (internal->vlit (lit) < eager_representant_id.size ()); - return eager_representant_id[internal->vlit (lit)]; -} -LRAT_ID Closure::eager_representative_id (int lit) const { - CADICAL_assert (internal->vlit (lit) < eager_representant_id.size ()); - return eager_representant_id[internal->vlit (lit)]; -} - -LRAT_ID &Closure::representative_id (int lit) { - CADICAL_assert (internal->vlit (lit) < representant_id.size ()); - return representant_id[internal->vlit (lit)]; -} -LRAT_ID Closure::representative_id (int lit) const { - CADICAL_assert (internal->vlit (lit) < representant_id.size ()); - return representant_id[internal->vlit (lit)]; -} - -void Closure::mark_garbage (Gate *g) { - LOG (g, "marking as garbage"); - CADICAL_assert (!g->garbage); - g->garbage = true; - garbage.push_back (g); -} - -bool Closure::remove_gate (GatesTable::iterator git) { - CADICAL_assert (git != end (table)); - CADICAL_assert (!internal->unsat); - (*git)->indexed = false; - LOG ((*git), "removing from hash table"); - table.erase (git); - return true; -} - -bool Closure::remove_gate (Gate *g) { - if (!g->indexed) - return false; - CADICAL_assert (!internal->unsat); - CADICAL_assert (table.find (g) != end (table)); - table.erase (table.find (g)); - g->indexed = false; - LOG (g, "removing from hash table"); - return true; -} - -void Closure::index_gate (Gate *g) { - CADICAL_assert (!g->indexed); - CADICAL_assert (!internal->unsat); - CADICAL_assert (g->arity () > 1); - CADICAL_assert (g->hash == hash_lits (nonces, g->rhs)); - LOG (g, "adding to hash table"); - table.insert (g); - g->indexed = true; -} - -void Closure::produce_rewritten_clause_lrat_and_clean ( - std::vector &litIds, int except_lhs, bool remove_units) { - CADICAL_assert (internal->lrat_chain.empty ()); - for (auto &litId : litIds) { - CADICAL_assert (litId.clause); - litId.clause = produce_rewritten_clause_lrat (litId.clause, except_lhs, - remove_units); - litId.current_lit = find_eager_representative (litId.current_lit); - } - litIds.erase ( - std::remove_if (begin (litIds), end (litIds), - [] (const LitClausePair &p) { return !p.clause; }), - end (litIds)); -} - -void Closure::produce_rewritten_clause_lrat_and_clean ( - std::vector &litIds, int except_lhs, - size_t &old_position1, size_t &old_position2, bool remove_units) { - CADICAL_assert (internal->lrat_chain.empty ()); - CADICAL_assert (old_position1 != old_position2); - size_t j = 0; - for (size_t i = 0; i < litIds.size (); ++i) { - CADICAL_assert (j <= i); - litIds[j].clause = produce_rewritten_clause_lrat ( - litIds[i].clause, except_lhs, remove_units); - litIds[j].current_lit = - find_eager_representative (litIds[i].current_lit); - if (i == old_position1) { - if (litIds[j].clause) - old_position1 = j; - else - old_position1 = -1; - } - if (i == old_position2) { - if (litIds[j].clause) - old_position2 = j; - else - old_position2 = -1; - } - if (litIds[j].clause) - ++j; - } - litIds.resize (j); -} - -void Closure::compute_rewritten_clause_lrat_simple (Clause *c, int except) { - CADICAL_assert (internal->clause.empty ()); - CADICAL_assert (internal->lrat_chain.empty ()); - CADICAL_assert (clause.empty ()); - CADICAL_assert (lrat_chain.empty ()); - bool changed = false; - bool tautology = false; - for (auto lit : *c) { - LOG ("checking if %d is required", lit); - if (internal->marked2 (lit)) { - continue; - } - if (internal->marked2 (-lit)) { - tautology = true; - break; - } - if (lit == except || lit == -except) { - internal->mark2 (lit); - clause.push_back (lit); - continue; - } - if (internal->val (lit) < 0) { -#if 1 - LOG ("found unit %d, removing it", -lit); - LRAT_ID id = internal->unit_id (-lit); - lrat_chain.push_back (id); - changed = true; - continue; -#else - LOG ("found unit %d, but ignoring it", -lit); -#endif - } - if (internal->val (lit) > 0) { - LOG ("found positive unit, so clause is subsumed by unit"); - tautology = true; - } - const int other = find_eager_representative_and_compress (lit); - const bool marked = internal->marked2 (other); - const bool neg_marked = internal->marked2 (-other); - if (!marked) - internal->mark2 (other); - if (neg_marked) { - tautology = true; - LOG ("tautology due to %d -> %d", lit, other); - } else if (lit == other && marked) { - changed = true; - LOG ("%d -> %d already in", lit, other); - } else if (lit != other) { - if (!marked) - clause.push_back (other); - changed = true; - lrat_chain.push_back (eager_representative_id (lit)); - } else if (!marked) - clause.push_back (lit); - } - - for (auto lit : *c) { - internal->unmark (lit); - } - - for (auto lit : clause) { - internal->unmark (lit); - } - - lrat_chain.push_back (c->id); - if (tautology) { - LOG ("generated clause is a tautology"); - lrat_chain.clear (); - clause.clear (); - } else if (changed && clause.size () == 1) { - LOG (lrat_chain, "LRAT chain"); - } else { - LOG (c, "oops this should not happen"); - CADICAL_assert (false); - } -} - -Clause *Closure::new_tmp_clause (std::vector &clause) { - CADICAL_assert (internal->lrat); - CADICAL_assert (!clause.empty ()); - CADICAL_assert (!lrat_chain.empty ()); - bool clear = false; - - LOG (clause, "learn new tmp clause"); - CADICAL_assert (clause.size () >= 2); - internal->external->check_learned_clause (); - - CADICAL_assert (internal->clause.size () <= (size_t) INT_MAX); - const int size = (int) clause.size (); - CADICAL_assert (size >= 2); - - size_t bytes = Clause::bytes (size); - Clause *c = (Clause *) new char[bytes]; - DeferDeleteArray clause_delete ((char *) c); - - c->id = ++internal->clause_id; - - c->conditioned = false; - c->covered = false; - c->enqueued = false; - c->frozen = false; - c->garbage = false; - c->gate = false; - c->hyper = false; - c->instantiated = false; - c->moved = false; - c->reason = false; - c->redundant = false; - c->transred = false; - c->subsume = false; - c->swept = false; - c->flushed = false; - c->vivified = false; - c->vivify = false; - c->used = 0; - - c->glue = size; - c->size = size; - c->pos = 2; - - for (int i = 0; i < size; i++) - c->literals[i] = clause[i]; - - // Just checking that we did not mess up our sophisticated memory layout. - // This might be compiler dependent though. Crucial for correctness. - // - CADICAL_assert (c->bytes () == bytes); - - clause_delete.release (); - LOG (c, "new pointer %p", (void *) c); - - if (clear) - clause.clear (); - - if (internal->proof) { - internal->proof->add_derived_clause (c, lrat_chain); - } - extra_clauses.push_back (c); - CADICAL_assert (internal->lrat_chain.empty ()); - return c; -} - -Clause *Closure::new_clause () { - CADICAL_assert (internal->clause.empty () || clause.empty ()); - bool clear = false; - if (internal->clause.empty ()) { - swap (internal->clause, clause); - clear = true; - } - - Clause *c = internal->new_clause (false); - - if (clear) - internal->clause.clear (); - - if (internal->proof) { - internal->proof->add_derived_clause (c, lrat_chain); - } - - return c; -} - -// TODO we here duplicate the arguments of push_id_and_rewriting_lrat but we -// probably do not need that. -void Closure::produce_rewritten_clause_lrat ( - std::vector &litIds, int except_lhs, bool remove_units) { - CADICAL_assert (internal->lrat_chain.empty ()); - for (auto &litId : litIds) { - if (!litId.clause) - continue; - litId.clause = produce_rewritten_clause_lrat (litId.clause, except_lhs, - remove_units); - litId.current_lit = find_eager_representative (litId.current_lit); - } -} - -Clause *Closure::produce_rewritten_clause_lrat (Clause *c, int except_lhs, - bool remove_units, bool fail_on_unit) { - CADICAL_assert (internal->clause.empty ()); - CADICAL_assert (internal->lrat_chain.empty ()); - auto tmp_lrat (std::move (lrat_chain)); - lrat_chain.clear (); - LOG (c, "rewriting clause for LRAT proof, except for rewriting %d", - except_lhs); - CADICAL_assert (internal->clause.empty ()); - CADICAL_assert (lrat_chain.empty ()); - bool changed = false; - bool tautology = false; - for (auto lit : *c) { - LOG ("checking if %d is required", lit); - if (internal->marked2 (lit)) { - continue; - } - if (internal->marked2 (-lit)) { - tautology = true; - break; - } - if (lit == except_lhs || lit == -except_lhs) { - internal->mark2 (lit); - clause.push_back (lit); - continue; - } - if (internal->val (lit) < 0) { - if (remove_units || lazy_propagated (lit)) { - LOG ("found unit %d, removing it", -lit); - LRAT_ID id = internal->unit_id (-lit); - lrat_chain.push_back (id); - changed = true; - continue; - } else - LOG ("found unit %d, but ignoring it", -lit); - } - if (internal->val (lit) > 0) { - LOG ("found positive unit %d, so clause is subsumed by unit", lit); - if (remove_units || lazy_propagated (lit)) - tautology = true; - } - const int other = find_eager_representative_and_compress (lit); - const bool marked = internal->marked2 (other); - const bool neg_marked = internal->marked2 (-other); - if (!marked) - internal->mark2 (other); - if (neg_marked) { - tautology = true; - LOG ("tautology due to %d -> %d", lit, other); - } else if (lit == other && marked) { - changed = true; - LOG ("%d -> %d already in", lit, other); - } else if (lit != other) { - if (!marked) - clause.push_back (other); - changed = true; - lrat_chain.push_back (eager_representative_id (lit)); - } else if (!marked) - clause.push_back (lit); - } - - for (auto lit : *c) { - internal->unmark (lit); - } - - for (auto lit : clause) { - internal->unmark (lit); - } - - lrat_chain.push_back (c->id); - Clause *d; - CADICAL_assert (internal->clause.empty ()); - if (tautology) { - LOG ("generated clause is a tautology"); - d = nullptr; - lrat_chain.clear (); - } else if (changed && clause.size () == 1) { - LOG (lrat_chain, "LRAT chain"); - if (fail_on_unit) { - d = nullptr; - CADICAL_assert (false && "rewriting produced a unit clause"); - } else { - d = c; - } - } else if (changed) { - LOG (lrat_chain, "LRAT Chain"); - d = new_tmp_clause (clause); - LOG (d, "rewritten clause to"); - } else { - LOG (c, "clause is unchanged, so giving up"); - lrat_chain.clear (); - d = c; - } - clause.clear (); - lrat_chain = std::move (tmp_lrat); - CADICAL_assert (internal->clause.empty ()); - return d; -} - -void Closure::push_id_on_chain (std::vector &chain, - Rewrite rewrite, int lit) { - LOG ("adding reason %zd for rewriting %d marked", - lit == rewrite.src ? rewrite.id1 : rewrite.id2, lit); - chain.push_back (lit == rewrite.src ? rewrite.id1 : rewrite.id2); -} - -void Closure::push_id_and_rewriting_lrat_unit (Clause *c, Rewrite rewrite1, - std::vector &chain, - bool insert_id_after, - Rewrite rewrite2, - int except_lhs, - int except_lhs2) { - LOG (c, - "computing normalized LRAT chain for clause to produce unit, " - "rewriting except for %d (%" PRIu64 ", %" PRIu64 ") and %d (%" PRIu64 - ", %" PRIu64 ") and skipping %d and %d", - rewrite1.src, rewrite1.id1, rewrite1.id2, rewrite2.src, rewrite2.id1, - rewrite2.id2, except_lhs, except_lhs2); - CADICAL_assert (c); - std::vector units, rewriting; - for (auto other : *c) { - // unclear how to achieve this in the simplify context where other == - // g->lhs might be set CADICAL_assert (internal->val (other) <= 0 || other == - // except); - if (other == except_lhs || other == -except_lhs) { - // do nothing; - } else if (other == except_lhs2 || other == -except_lhs2) { - // do nothing; - } else if (internal->val (other) < 0) { - LOG ("found unit %d", -other); - LRAT_ID id = internal->unit_id (-other); - units.push_back (id); - } else if (other == rewrite1.src && rewrite1.id1) { - push_id_on_chain (rewriting, rewrite1, other); - } else if (other == -rewrite1.src && rewrite1.id2) { - push_id_on_chain (rewriting, rewrite1, other); - } else if (other == rewrite2.src && rewrite2.id1) { - push_id_on_chain (rewriting, rewrite2, other); - } else if (other == -rewrite2.src && rewrite2.id2) { - push_id_on_chain (rewriting, rewrite2, other); - } else if (other != find_eager_representative_and_compress (other)) { -#if defined(LOGGING) || !defined(CADICAL_NDEBUG) - const int rewritten_other = eager_representative (other); - CADICAL_assert (other != rewritten_other); - LOG ("reason for representative of %d %d is %" PRIu64 "", other, - rewritten_other, find_eager_representative_lrat (other)); -#endif - rewriting.push_back (find_eager_representative_lrat (other)); - } else { - LOG ("no rewriting needed for %d", other); - } - } - for (auto id : units) - chain.push_back (id); - - if (!insert_id_after) - chain.push_back (c->id); - for (auto id : rewriting) - chain.push_back (id); - - if (insert_id_after) - chain.push_back (c->id); -} - -// Note: it is important that the Rewrite takes over the normal rewriting, -// because we can force rewriting that way that have not been done eagerly -// yet. -void Closure::push_id_and_rewriting_lrat_full (Clause *c, Rewrite rewrite1, - std::vector &chain, - bool insert_id_after, - Rewrite rewrite2, - int except_lhs, - int except_lhs2) { - LOG (c, - "computing normalized LRAT chain for clause, rewriting except for " - "%d (%" PRIu64 ", %" PRIu64 ") and %d (%" PRIu64 ", %" PRIu64 - ") and skipping %d and %d", - rewrite1.src, rewrite1.id1, rewrite1.id2, rewrite2.src, rewrite2.id1, - rewrite2.id2, except_lhs, except_lhs2); - CADICAL_assert (c); - if (!insert_id_after) - chain.push_back (c->id); - for (auto other : *c) { - // unclear how to achieve this in the simplify context where other == - // g->lhs might be set CADICAL_assert (internal->val (other) <= 0 || other == - // except); - if (other == except_lhs) { - // do nothing; - } else if (other == except_lhs2) { - // do nothing; - } else if (internal->val (other) < 0) { - LOG ("found unit %d", -other); - LRAT_ID id = internal->unit_id (-other); - CADICAL_assert (id); - chain.push_back (id); - } else if (other == rewrite1.src && rewrite1.id1) { - push_id_on_chain (chain, rewrite1, other); - } else if (other == -rewrite1.src && rewrite1.id2) { - push_id_on_chain (chain, rewrite1, other); - } else if (other == rewrite2.src && rewrite2.id1) { - push_id_on_chain (chain, rewrite2, other); - } else if (other == -rewrite2.src && rewrite2.id2) { - push_id_on_chain (chain, rewrite2, other); - } else { - CADICAL_assert (other == find_eager_representative (other)); - LOG ("no rewriting needed for %d", other); - } - } - if (insert_id_after) - chain.push_back (c->id); -} - -// Note: it is important that the Rewrite takes over the normal rewriting, -// because we can force rewriting that way that have not been done eagerly -// yet. -void Closure::push_id_on_chain (std::vector &chain, Clause *c) { - CADICAL_assert (c); - chain.push_back (c->id); - LOG (lrat_chain, "chain"); -} - -void Closure::push_id_on_chain (std::vector &chain, - const std::vector &reasons) { - for (auto litId : reasons) { - LOG (litId.clause, "found lrat in gate %d from %zd", litId.current_lit, - litId.clause->id); - push_id_on_chain (chain, litId.clause); - } - LOG (lrat_chain, "chain from %zd reasons", reasons.size ()); -} - -void Closure::learn_congruence_unit_when_lhs_set (Gate *g, int src, - LRAT_ID id1, LRAT_ID id2, - int dst) { - if (!internal->lrat) - return; - LOG ("calculating LRAT chain learn_congruence_unit_when_lhs_set"); - CADICAL_assert (!g->pos_lhs_ids.empty ()); - CADICAL_assert (internal->analyzed.empty ()); - CADICAL_assert (internal->val (g->lhs) < 0); - switch (g->tag) { - case Gate_Type::And_Gate: - LOG (lrat_chain, "lrat"); - LOG (lrat_chain, "lrat"); - for (auto litId : g->neg_lhs_ids) - push_id_and_rewriting_lrat_unit ( - litId.clause, Rewrite (src, dst, id1, id2), lrat_chain); - LOG (lrat_chain, "lrat"); - break; - default: - CADICAL_assert (false); - } -} - -// Something very important here: as we are producing a unit, we cannot -// simplify or rewrite the clauses as this will produce units. -void Closure::learn_congruence_unit_falsifies_lrat_chain ( - Gate *g, int src, int dst, int clashing, int falsified, int unit) { - if (!internal->lrat) - return; - CADICAL_assert (!g->pos_lhs_ids.empty ()); - CADICAL_assert (internal->analyzed.empty ()); - CADICAL_assert (lrat_chain.empty ()); - std::vector proof_chain; - switch (g->tag) { - case Gate_Type::And_Gate: - if (clashing) { - LOG ("clashing %d where -lhs=%d", clashing, -g->lhs); - // Example: -2 = 1&3 and 3=2 - // The proof consists in taking the binary clause of the clashing - // literal - if (clashing == -g->lhs) { - for (auto litId : g->pos_lhs_ids) { - LOG (litId.clause, - "found lrat in gate %d from %zd (looking for %d)", - litId.current_lit, litId.clause->id, falsified); - if (litId.current_lit == clashing) { - push_id_and_rewriting_lrat_unit ( - litId.clause, Rewrite (), proof_chain, true, Rewrite (), - g->degenerated_and_neg || g->degenerated_and_pos ? 0 : -g->lhs); - } - } - } else { - // Example: 3 = (-1&2) and 2=1 - // The proof consists in taking the binary clause with the rewrites - // Example where the rewrite must be before: - // 2: 3v2 - // 9: -2v1 - // 6: 3v1 - // The chain cannot start by 9 - if (g->degenerated_and_neg || g->degenerated_and_pos) { - LOG ("%d %d %d", src, dst, g->lhs); - if (src == g->lhs || dst == g->lhs) { - LOG ("degenerated AND gate with dst=lhs"); - for (const auto &litId : g->pos_lhs_ids) { - LOG (litId.clause, "definition clause %d ->", - litId.current_lit); - if (litId.current_lit == clashing) { - push_id_and_rewriting_lrat_unit (litId.clause, Rewrite (), - proof_chain, true, - Rewrite (), 0); - LOG (proof_chain, "produced lrat chain so far"); - } - } - CADICAL_assert (!proof_chain.empty ()); - } else { - LOG ("degenerated AND gate with conflict without LHS"); - for (const auto &litId : g->pos_lhs_ids) { - LOG (litId.clause, "definition clause %d ->", - litId.current_lit); - push_id_and_rewriting_lrat_unit (litId.clause, Rewrite (), - proof_chain, false, - Rewrite (), -g->lhs); - LOG (proof_chain, "produced lrat chain so far"); - } - } - } else { - LOG ("normal AND gate"); - for (const auto &litId : g->pos_lhs_ids) { - push_id_and_rewriting_lrat_unit (litId.clause, Rewrite (), - proof_chain, false, Rewrite (), - g->degenerated_and_neg || g->degenerated_and_pos ? 0 : -g->lhs); - LOG (proof_chain, "produced lrat chain so far"); - } - } - } - LOG (proof_chain, "produced lrat chain"); - } else if (falsified) { - LOG ("falsifies %d", falsified); - // Example is 3=(1&2) with 2=false or 3=(1&4) with 4=2 and 2=false - // (can happen when the unit was derived in the middle of the - // rewriting) - for (auto litId : g->pos_lhs_ids) { - LOG (litId.clause, - "found lrat in gate %d from %zd (looking for %d)", - litId.current_lit, litId.clause->id, falsified); - if (litId.current_lit == falsified || - (litId.current_lit == src && dst == falsified)) { - push_id_and_rewriting_lrat_unit (litId.clause, Rewrite (), - proof_chain, true, Rewrite (), - -dst, -g->lhs); - } - } - } else { - CADICAL_assert (unit); - // Example is 1 = 2&3 where 2 and 3 are false - for (auto litId : g->neg_lhs_ids) { - push_id_and_rewriting_lrat_unit (litId.clause, Rewrite (), - proof_chain); - } - LOG (proof_chain, "produced lrat chain"); - break; - } - lrat_chain = std::move (proof_chain); - break; - default: - CADICAL_assert (false); - } - (void) unit; -} - -bool Closure::fully_propagate () { - if (internal->unsat) - return false; - LOG ("fully propagating"); - CADICAL_assert (internal->watching ()); - CADICAL_assert (full_watching); - bool no_conflict = internal->propagate (); - - if (no_conflict) - return true; - internal->learn_empty_clause (); - if (internal->lrat) - lrat_chain.clear (); - - return false; -} -bool Closure::learn_congruence_unit (int lit, bool delay_propagation, bool force_propagation) { - if (internal->unsat) - return false; - const signed char val_lit = internal->val (lit); - if (val_lit > 0) { - LOG ("already set lit %d", lit); - if (internal->lrat) - lrat_chain.clear (); - if (force_propagation) - return fully_propagate(); - return true; - } - LOG ("adding unit %s", LOGLIT (lit)); - ++internal->stats.congruence.units; - CADICAL_assert (!internal->lrat || !lrat_chain.empty ()); - if (val_lit < 0) { - if (internal->lrat) { - CADICAL_assert (internal->lrat_chain.empty ()); - LRAT_ID id = internal->unit_id (-lit); - internal->lrat_chain.push_back (id); - for (auto id : lrat_chain) - internal->lrat_chain.push_back (id); - lrat_chain.clear (); - } - internal->learn_empty_clause (); - return false; - } - - LOG (lrat_chain, "assigning due to LRAT chain"); - swap (lrat_chain, internal->lrat_chain); - internal->assign_unit (lit); - CADICAL_assert (lrat_chain.empty ()); - CADICAL_assert (internal->lrat_chain.empty ()); - if (delay_propagation) - return false; - else return fully_propagate (); -} - -// for merging the literals there are many cases -// TODO: LRAT does not work if the LHS is not in normal form and if the -// representative is also in the gate. -bool Closure::merge_literals_lrat ( - Gate *g, Gate *h, int lit, int other, - const std::vector &extra_reasons_lit, - const std::vector &extra_reasons_ulit) { - CADICAL_assert (!internal->unsat); - CADICAL_assert (g->lhs == lit); - CADICAL_assert (g == h || h->lhs == other); - (void) g, (void) h; - LOG ("merging literals %s and %s", LOGLIT(lit), LOGLIT(other)); - // TODO: this should not update_eager but still calculate the LRAT chain - // below! - const int repr_lit = find_representative_and_compress (lit, false); - const int repr_other = find_representative_and_compress (other, false); - find_representative_and_compress (-lit, false); - find_representative_and_compress (-other, false); - LOG ("merging literals %d [=%d] and %d [=%d]", lit, repr_lit, other, - repr_other); - - if (repr_lit == repr_other) { - LOG ("already merged %d and %d", lit, other); - if (internal->lrat) - lrat_chain.clear (); - return false; - } - - const int val_lit = internal->val (lit); - const int val_other = internal->val (other); - if (val_lit) { - if (val_lit == val_other) { - LOG ("not merging lits %d and %d assigned to same value", lit, other); - if (internal->lrat) - lrat_chain.clear (); - return false; - } - } - - // For LRAT we need to distinguish more cases for a more regular - // reconstruction. - // - // 1. if lit = -other, then we learn lit and -lit to derive false - // - // 2. otherwise, we learn the new clauses lit = -other (which are two real - // clauses). - // - // 2a. if repr_lit = -repr_other, we learn the units repr_lit and - // -repr_lit to derive false - // - // 2b. otherwise, we learn the equivalences repr_lit = -repr_other - // (which are two real clauses) - // - // Without LRAT this is easier, as we directly learn the conclusion - // (either false or the equivalence). The steps can also not be merged - // because repr_lit can appear in the gate and hence in the resolution - // chain. - int smaller_repr = repr_lit; - int larger_repr = repr_other; - int smaller = lit; - int larger = other; - const std::vector *smaller_chain = &extra_reasons_ulit; - const std::vector *larger_chain = &extra_reasons_lit; - - if (abs (smaller_repr) > abs (larger_repr)) { - swap (smaller_repr, larger_repr); - swap (smaller, larger); - swap (smaller_chain, larger_chain); - } - - CADICAL_assert (find_representative (smaller_repr) == smaller_repr); - CADICAL_assert (find_representative (larger_repr) == larger_repr); - if (lit == -other) { - CADICAL_assert (chain.empty ()); - LOG ("merging clashing %d and %d", lit, other); - if (internal->proof) { - if (internal->lrat) { - for (auto id : *smaller_chain) - lrat_chain.push_back (id); - } - unsimplified.push_back (smaller); - LRAT_ID id = simplify_and_add_to_proof_chain (unsimplified); - - if (internal->lrat) { - internal->lrat_chain.push_back (id); - for (auto id : *larger_chain) - internal->lrat_chain.push_back (id); - LOG (internal->lrat_chain, "lrat chain"); - } - } - internal->learn_empty_clause (); - delete_proof_chain (); - return false; - } - - LOG ("merging %d and %d first and then the equivalences of %d and %d " - "with LRAT", - lit, other, repr_lit, repr_other); - Clause *eq1_tmp = nullptr; - if (internal->lrat) { - lrat_chain = *smaller_chain; - eq1_tmp = add_tmp_binary_clause (-larger, smaller); - } - CADICAL_assert (!internal->lrat || eq1_tmp); - - Clause *eq2_tmp = nullptr; - if (internal->lrat) { - lrat_chain = *larger_chain; - LOG (lrat_chain, "lrat chain"); - - eq2_tmp = add_tmp_binary_clause (larger, -smaller); - // the order in the clause is important for the - // repr_lit == -repr_other to get the right chain - } - CADICAL_assert (!internal->lrat || eq2_tmp); - if (internal->lrat) - lrat_chain.clear (); - - if (repr_lit == -repr_other) { - // now derive empty clause - Rewrite rew1, rew2; - if (internal->lrat) { - // no need to calculate push_id_and_rewriting_lrat here because all - // the job is done by the arguments already - rew1 = Rewrite (lit == repr_lit ? 0 : lit, repr_lit, - lit == repr_lit ? 0 : representative_id (lit), - lit == repr_lit ? 0 : representative_id (-lit)); - rew2 = Rewrite (other == repr_other ? 0 : other, repr_other, - other == repr_other ? 0 : representative_id (other), - other == repr_other ? 0 : representative_id (-other)); - push_id_and_rewriting_lrat_unit (eq1_tmp, rew1, lrat_chain, true, - rew2); - swap (lrat_chain, internal->lrat_chain); - } - internal->assign_unit (-larger_repr); - if (internal->lrat) { - internal->lrat_chain.clear (); - - if (larger != larger_repr) - push_lrat_unit (-larger_repr); - push_id_and_rewriting_lrat_unit ( - eq2_tmp, rew1, lrat_chain, true, rew2, - larger != larger_repr ? larger_repr : 0); - LOG (lrat_chain, "lrat chain"); - swap (lrat_chain, internal->lrat_chain); - } - internal->learn_empty_clause (); - if (internal->lrat) - internal->lrat_chain.clear (); - return false; - } - - if (val_lit) { - if (val_lit == val_other) { - LOG ("not merging lits %d and %d assigned to same value", lit, other); - if (internal->lrat) - lrat_chain.clear (); - return false; - } - if (val_lit == -val_other) { - LOG ("merging lits %d and %d assigned to inconsistent value", lit, - other); - CADICAL_assert (lrat_chain.empty ()); - if (internal->lrat) { - Clause *c = val_lit ? eq2_tmp : eq1_tmp; - int pos = val_lit ? other : lit; - int neg = val_lit ? -lit : -other; - push_lrat_unit (pos); - push_lrat_unit (neg); - push_id_on_chain (lrat_chain, c); - } - internal->learn_empty_clause (); - if (internal->lrat) - lrat_chain.clear (); - return false; - } - - CADICAL_assert (!val_other); - LOG ("merging assigned %d and unassigned %d", lit, other); - CADICAL_assert (lrat_chain.empty ()); - const int unit = (val_lit < 0) ? -other : other; - if (internal->lrat) { - Clause *c; - if (lit == smaller) { - if (val_lit < 0) - c = eq1_tmp; - else - c = eq2_tmp; - } else { - if (val_lit < 0) - c = eq2_tmp; - else - c = eq1_tmp; - } - push_id_and_rewriting_lrat_unit (c, Rewrite (), lrat_chain, true, - Rewrite (), unit); - } - learn_congruence_unit (unit); - if (internal->lrat) - lrat_chain.clear (); - return false; - } - - if (!val_lit && val_other) { - LOG ("merging assigned %d and unassigned %d", lit, other); - CADICAL_assert (lrat_chain.empty ()); - const int unit = (val_other < 0) ? -lit : lit; - if (internal->lrat) { - Clause *c; - if (lit == smaller) { - if (val_lit < 0) - c = eq1_tmp; - else - c = eq2_tmp; - } else { - if (val_lit < 0) - c = eq2_tmp; - else - c = eq1_tmp; - } - push_id_and_rewriting_lrat_unit (c, Rewrite (), lrat_chain, true, - Rewrite (), lit, unit); - } - learn_congruence_unit (unit); - if (internal->lrat) - lrat_chain.clear (); - return false; - } - - Clause *eq1_repr, *eq2_repr; - if (smaller_repr != smaller || larger != larger_repr) { - if (internal->lrat) { - lrat_chain.clear (); - Rewrite rew1 = Rewrite ( - smaller_repr != smaller ? smaller : 0, - smaller_repr != smaller ? smaller_repr : 0, - smaller_repr != smaller ? representative_id (smaller) : 0, - smaller_repr != smaller ? representative_id (-smaller) : 0); - Rewrite rew2 = - Rewrite (larger_repr != larger ? larger : 0, - larger_repr != larger ? larger_repr : 0, - larger_repr != larger ? representative_id (larger) : 0, - larger_repr != larger ? representative_id (-larger) : 0); - push_id_and_rewriting_lrat_full (eq1_tmp, rew1, lrat_chain, true, - rew2); - } - eq1_repr = learn_binary_tmp_or_full_clause (-larger_repr, smaller_repr); - } else { - if (internal->lrat) - eq1_repr = maybe_promote_tmp_binary_clause (eq1_tmp); - else - eq1_repr = maybe_add_binary_clause (-larger_repr, smaller_repr); - } - - if (internal->lrat) { - lrat_chain.clear (); - } - - if (smaller_repr != smaller || larger != larger_repr) { - - if (internal->lrat) { - lrat_chain.clear (); - // eq2 = larger, -smaller - Rewrite rew1 = Rewrite ( - smaller_repr != smaller ? smaller : 0, - smaller_repr != smaller ? smaller_repr : 0, - smaller_repr != smaller ? representative_id (smaller) : 0, - smaller_repr != smaller ? representative_id (-smaller) : 0); - Rewrite rew2 = - Rewrite (larger_repr != larger ? larger : 0, - larger_repr != larger ? larger_repr : 0, - larger_repr != larger ? representative_id (larger) : 0, - larger_repr != larger ? representative_id (-larger) : 0); - push_id_and_rewriting_lrat_full (eq2_tmp, rew1, lrat_chain, true, - rew2); - } - - eq2_repr = learn_binary_tmp_or_full_clause (larger_repr, -smaller_repr); - - } else { - if (internal->lrat) - eq2_repr = maybe_promote_tmp_binary_clause (eq2_tmp); - else - eq2_repr = maybe_add_binary_clause (larger_repr, -smaller_repr); - } - lrat_chain.clear (); - - if (internal->lrat) { - representative_id (larger_repr) = eq1_repr->id; - CADICAL_assert (std::find (begin (*eq1_repr), end (*eq1_repr), -larger_repr) != - end (*eq1_repr)); - representative_id (-larger_repr) = eq2_repr->id; - CADICAL_assert (std::find (begin (*eq2_repr), end (*eq2_repr), larger_repr) != - end (*eq2_repr)); - } - LOG ("updating %d -> %d", larger_repr, smaller_repr); - representative (larger_repr) = smaller_repr; - representative (-larger_repr) = -smaller_repr; - schedule_literal (larger_repr); - ++internal->stats.congruence.congruent; - CADICAL_assert (lrat_chain.empty ()); - return true; -} - -// Variant when there are no gates -// TODO: this is exactly the same as the other function without the gates. -// Kill the arguments! -bool Closure::merge_literals_lrat ( - int lit, int other, const std::vector &extra_reasons_lit, - const std::vector &extra_reasons_ulit) { - CADICAL_assert (!internal->unsat); - LOG ("merging literals %s and %s", LOGLIT (lit), LOGLIT (other)); - // TODO: this should not update_eager but still calculate the LRAT chain - // below! - const int repr_lit = find_representative_and_compress (lit, false); - const int repr_other = find_representative_and_compress (other, false); - find_representative_and_compress (-lit, false); - find_representative_and_compress (-other, false); - LOG ("merging literals %s [=%d] and %s [=%d]", LOGLIT (lit), repr_lit, - LOGLIT (other), repr_other); - LOG (lrat_chain, "lrat chain beginning of merge"); - - if (repr_lit == repr_other) { - LOG ("already merged %s and %s", LOGLIT (lit), LOGLIT (other)); - if (internal->lrat) - lrat_chain.clear (); - return false; - } - - const int val_lit = internal->val (lit); - const int val_other = internal->val (other); - - // For LRAT we need to distinguish more cases for a more regular - // reconstruction. - // - // 1. if lit = -other, then we learn lit and -lit to derive false - // - // 2. otherwise, we learn the new clauses lit = -other (which are two real - // clauses). - // - // 2a. if repr_lit = -repr_other, we learn the units repr_lit and - // -repr_lit to derive false - // - // 2b. otherwise, we learn the equivalences repr_lit = -repr_other - // (which are two real clauses) - // - // Without LRAT this is easier, as we directly learn the conclusion - // (either false or the equivalence). The steps can also not be merged - // because repr_lit can appear in the gate and hence in the resolution - // chain. - int smaller_repr = repr_lit; - int larger_repr = repr_other; - int val_smaller = val_lit; - int val_larger = val_other; - int smaller = lit; - int larger = other; - const std::vector *smaller_chain = &extra_reasons_ulit; - const std::vector *larger_chain = &extra_reasons_lit; - - if (abs (smaller_repr) > abs (larger_repr)) { - swap (smaller_repr, larger_repr); - swap (smaller, larger); - swap (smaller_chain, larger_chain); - swap (val_smaller, val_larger); - } - - CADICAL_assert (find_representative (smaller_repr) == smaller_repr); - CADICAL_assert (find_representative (larger_repr) == larger_repr); - if (lit == -other) { - LOG ("merging clashing %d and %d", lit, other); - if (!val_smaller) { - if (internal->lrat) - internal->lrat_chain = *smaller_chain; - internal->assign_unit (smaller); - if (internal->lrat) - internal->lrat_chain.clear (); - - push_lrat_unit (smaller); - if (internal->lrat) { - CADICAL_assert (internal->lrat_chain.empty ()); - swap (internal->lrat_chain, lrat_chain); - for (auto id : *larger_chain) - internal->lrat_chain.push_back (id); - LOG (internal->lrat_chain, "lrat chain"); - } - internal->learn_empty_clause (); - return false; - } else { - if (internal->lrat) - internal->lrat_chain = - (val_smaller < 0 ? *smaller_chain : *larger_chain); - if (internal->lrat) - internal->lrat_chain.push_back ( - internal->unit_id (val_smaller > 0 ? smaller : -smaller)); - internal->learn_empty_clause (); - return false; - } - } - - if (val_lit && val_lit == val_other) { - LOG ("not merging lits %d and %d assigned to same value", lit, other); - return false; - } - - if (val_lit && val_lit == -val_other) { - if (internal->lrat) { - internal->lrat_chain.push_back ( - internal->unit_id (val_smaller < 0 ? -smaller : smaller)); - internal->lrat_chain.push_back ( - internal->unit_id (val_larger < 0 ? -larger : larger)); - for (auto id : (val_smaller < 0 ? *smaller_chain : *larger_chain)) { - internal->lrat_chain.push_back(id); - } - } - internal->learn_empty_clause (); - return false; - } - - LOG ("merging %d and %d first and then the equivalences of %d and %d " - "with LRAT", - lit, other, repr_lit, repr_other); - Clause *eq1_tmp = nullptr; - if (internal->lrat) { - lrat_chain = *smaller_chain; - eq1_tmp = add_tmp_binary_clause (-larger, smaller); - CADICAL_assert (eq1_tmp); - } - CADICAL_assert (!internal->lrat || eq1_tmp); - - Clause *eq2_tmp = nullptr; - if (internal->lrat) { - lrat_chain = *larger_chain; - LOG (lrat_chain, "lrat chain"); - // the order in the clause is important for the - // repr_lit == -repr_other to get the right chain - eq2_tmp = add_tmp_binary_clause (larger, -smaller); - CADICAL_assert (eq2_tmp); - } - - CADICAL_assert (!internal->lrat || eq2_tmp); - if (internal->lrat) - lrat_chain.clear (); - - if (repr_lit == -repr_other) { - // now derive empty clause - Rewrite rew1, rew2; - if (internal->lrat) { - // no need to calculate push_id_and_rewriting_lrat here because all - // the job is done by the arguments already - rew1 = Rewrite (lit == repr_lit ? 0 : lit, repr_lit, - lit == repr_lit ? 0 : representative_id (lit), - lit == repr_lit ? 0 : representative_id (-lit)); - rew2 = Rewrite (other == repr_other ? 0 : other, repr_other, - other == repr_other ? 0 : representative_id (other), - other == repr_other ? 0 : representative_id (-other)); - push_id_and_rewriting_lrat_unit (eq1_tmp, rew1, lrat_chain, true, - rew2); - swap (lrat_chain, internal->lrat_chain); - } - CADICAL_assert (val_larger == internal->val (larger_repr)); - if (!val_larger) { - // not assigned, first assign one - internal->assign_unit (-larger_repr); - if (internal->lrat) { - internal->lrat_chain.clear (); - - if (larger != larger_repr) - push_lrat_unit (-larger_repr); - // no need to calculate push_id_and_rewriting_lrat here because all - // the job is done by the arguments already - push_id_and_rewriting_lrat_unit ( - eq2_tmp, rew1, lrat_chain, true, rew2, - larger != larger_repr ? larger_repr : 0); - LOG (lrat_chain, "lrat chain"); - swap (lrat_chain, internal->lrat_chain); - } - } else { - // otherwise, no need to - if (internal->lrat) - lrat_chain.push_back (internal->unit_id (larger_repr)); - } - internal->learn_empty_clause (); - if (internal->lrat) - internal->lrat_chain.clear (); - return false; - } - - if (val_lit) { - if (val_lit == val_other) { - LOG ("not merging lits %d and %d assigned to same value", lit, other); - if (internal->lrat) - lrat_chain.clear (); - return false; - } - if (val_lit == -val_other) { - LOG ("merging lits %d and %d assigned to inconsistent value", lit, - other); - CADICAL_assert (lrat_chain.empty ()); - if (internal->lrat) { - Clause *c = val_lit ? eq2_tmp : eq1_tmp; - int pos = val_lit ? other : lit; - int neg = val_lit ? -lit : -other; - push_lrat_unit (pos); - push_lrat_unit (neg); - push_id_on_chain (lrat_chain, c); - } - internal->learn_empty_clause (); - if (internal->lrat) - lrat_chain.clear (); - return false; - } - - CADICAL_assert (!val_other); - LOG ("merging assigned %d and unassigned %d", lit, other); - CADICAL_assert (lrat_chain.empty ()); - const int unit = (val_lit < 0) ? -other : other; - if (internal->lrat) { - Clause *c; - if (lit == smaller) { - if (val_lit < 0) - c = eq1_tmp; - else - c = eq2_tmp; - } else { - if (val_lit < 0) - c = eq2_tmp; - else - c = eq1_tmp; - } - push_id_and_rewriting_lrat_unit (c, Rewrite (), lrat_chain, true, - Rewrite (), unit); - } - learn_congruence_unit (unit); - if (internal->lrat) - lrat_chain.clear (); - return false; - } - - if (!val_lit && val_other) { - LOG ("merging assigned %d and unassigned %d", lit, other); - CADICAL_assert (lrat_chain.empty ()); - const int unit = (val_other < 0) ? -lit : lit; - if (internal->lrat) { - Clause *c; - if (lit == smaller) { - CADICAL_assert (other == larger); - if (val_other > 0) - c = eq1_tmp; - else - c = eq2_tmp; - } else { - if (val_other > 0) - c = eq2_tmp; - else - c = eq1_tmp; - } - push_id_and_rewriting_lrat_unit (c, Rewrite (), lrat_chain, true, - Rewrite (), lit, unit); - } - learn_congruence_unit (unit); - if (internal->lrat) - lrat_chain.clear (); - return false; - } - - Clause *eq1_repr, *eq2_repr; - if (smaller_repr != smaller || larger != larger_repr) { - if (internal->lrat) { - lrat_chain.clear (); - Rewrite rew1 = Rewrite ( - smaller_repr != smaller ? smaller : 0, - smaller_repr != smaller ? smaller_repr : 0, - smaller_repr != smaller ? representative_id (smaller) : 0, - smaller_repr != smaller ? representative_id (-smaller) : 0); - Rewrite rew2 = - Rewrite (larger_repr != larger ? larger : 0, - larger_repr != larger ? larger_repr : 0, - larger_repr != larger ? representative_id (larger) : 0, - larger_repr != larger ? representative_id (-larger) : 0); - push_id_and_rewriting_lrat_full (eq1_tmp, rew1, lrat_chain, true, - rew2); - } - eq1_repr = learn_binary_tmp_or_full_clause (-larger_repr, smaller_repr); - } else { - if (internal->lrat) - eq1_repr = maybe_promote_tmp_binary_clause (eq1_tmp); - else - eq1_repr = maybe_add_binary_clause (-larger_repr, smaller_repr); - } - - if (internal->lrat) { - lrat_chain.clear (); - } - - if (smaller_repr != smaller || larger != larger_repr) { - - if (internal->lrat) { - lrat_chain.clear (); - // eq2 = larger, -smaller - Rewrite rew1 = Rewrite ( - smaller_repr != smaller ? smaller : 0, - smaller_repr != smaller ? smaller_repr : 0, - smaller_repr != smaller ? representative_id (smaller) : 0, - smaller_repr != smaller ? representative_id (-smaller) : 0); - Rewrite rew2 = - Rewrite (larger_repr != larger ? larger : 0, - larger_repr != larger ? larger_repr : 0, - larger_repr != larger ? representative_id (larger) : 0, - larger_repr != larger ? representative_id (-larger) : 0); - push_id_and_rewriting_lrat_full (eq2_tmp, rew1, lrat_chain, true, - rew2); - } - eq2_repr = learn_binary_tmp_or_full_clause (larger_repr, -smaller_repr); - } else { - if (internal->lrat) - eq2_repr = maybe_promote_tmp_binary_clause (eq2_tmp); - else - eq2_repr = maybe_add_binary_clause (larger_repr, -smaller_repr); - } - lrat_chain.clear (); - - if (internal->lrat) { - representative_id (larger_repr) = eq1_repr->id; - CADICAL_assert (std::find (begin (*eq1_repr), end (*eq1_repr), -larger_repr) != - end (*eq1_repr)); - representative_id (-larger_repr) = eq2_repr->id; - check_not_tmp_binary_clause (eq1_repr); - check_not_tmp_binary_clause (eq2_repr); - CADICAL_assert (std::find (begin (*eq2_repr), end (*eq2_repr), larger_repr) != - end (*eq2_repr)); - } - LOG ("updating %d -> %d", larger_repr, smaller_repr); - representative (larger_repr) = smaller_repr; - representative (-larger_repr) = -smaller_repr; - schedule_literal (larger_repr); - ++internal->stats.congruence.congruent; - CADICAL_assert (lrat_chain.empty ()); - return true; -} - -inline void Closure::promote_clause (Clause *c) { - if (internal->lrat) - check_not_tmp_binary_clause (c); - if (!c) - return; - if (!c->redundant) - return; - LOG (c, "turning redundant subsuming clause into irredundant clause"); - c->redundant = false; - if (internal->proof) - internal->proof->strengthen (c->id); - internal->stats.current.irredundant++; - internal->stats.added.irredundant++; - internal->stats.irrlits += c->size; - CADICAL_assert (internal->stats.current.redundant > 0); - internal->stats.current.redundant--; - CADICAL_assert (internal->stats.added.redundant > 0); - internal->stats.added.redundant--; - // ... and keep 'stats.added.total'. -} - -// This function is rather tricky for LRAT. If you have 2 = 1 and 3=4 you -// cannot add 2=3. You really to connect the representatives directly -// therefore you actually need to learn the clauses 2->3->4 and -2->1 and -// vice-versa -bool Closure::merge_literals_equivalence (int lit, int other, Clause *c1, - Clause *c2) { - CADICAL_assert (!internal->unsat); - LRAT_ID id1 = c1 ? c1->id : 0; - LRAT_ID id2 = c2 ? c2->id : 0; - if (internal->lrat) { - CADICAL_assert (c1); - CADICAL_assert (c2); - CADICAL_assert (c1->size == 2); - CADICAL_assert (c2->size == 2); - CADICAL_assert (c1->literals[0] == lit || c1->literals[1] == lit); - CADICAL_assert (c2->literals[0] == other || c2->literals[1] == other); - CADICAL_assert (c1->literals[0] == -other || c1->literals[1] == -other); - CADICAL_assert (c2->literals[0] == -lit || c2->literals[1] == -lit); - check_not_tmp_binary_clause (c1); - check_not_tmp_binary_clause (c2); - } - int repr_lit = find_representative (lit); - int repr_other = find_representative (other); - find_representative_and_compress_both (lit); - find_representative_and_compress_both (other); - LOG ("merging literals %d [=%d] and %d [=%d] lrat", lit, repr_lit, other, - repr_other); - - if (repr_lit == repr_other) { - LOG ("already merged %d and %d", lit, other); - return false; - } - const int val_lit = internal->val (lit); - const int val_other = internal->val (other); - - if (val_lit) { - if (val_lit == val_other) { - LOG ("not merging lits %d and %d assigned to same value", lit, other); - return false; - } - if (val_lit == -val_other) { - if (internal->lrat) - lrat_chain.push_back (internal->unit_id (lit)), - lrat_chain.push_back (internal->unit_id (other)); - LOG ("merging lits %d and %d assigned to inconsistent value", lit, - other); - internal->learn_empty_clause (); - return false; - } - - CADICAL_assert (!val_other); - LOG ("merging assigned %d and unassigned %d", lit, other); - const int unit = (val_lit < 0) ? -other : other; - if (internal->lrat) - lrat_chain.push_back (internal->unit_id (unit)); - if (val_lit < 0) - lrat_chain.push_back (c2->id); - else - lrat_chain.push_back (c1->id); - learn_congruence_unit (unit); - return false; - } - - if (!val_lit && val_other) { - LOG ("merging assigned %d and unassigned %d", other, lit); - const int unit = (val_other < 0) ? -lit : lit; - if (internal->lrat) - lrat_chain.push_back ( - internal->unit_id (val_other < 0 ? -other : other)); - if (val_lit < 0) - lrat_chain.push_back (c1->id); - else - lrat_chain.push_back (c2->id); - learn_congruence_unit (unit); - return false; - } - - int smaller_repr = repr_lit; - int larger_repr = repr_other; - int smaller = lit; - int larger = other; - - if (abs (smaller_repr) > abs (larger_repr)) { - swap (smaller_repr, larger_repr); - swap (smaller, larger); - } - - CADICAL_assert (find_representative (smaller_repr) == smaller_repr); - CADICAL_assert (find_representative (larger_repr) == larger_repr); - - if (repr_lit == -repr_other) { - LOG ("merging clashing %d [=%d] and %d[=%d], smaller: %d", lit, - repr_lit, other, repr_other, smaller); - if (internal->lrat) { - Rewrite rew1 = - Rewrite (lit, lit == repr_lit ? 0 : repr_lit, - lit == repr_lit ? 0 : find_representative_lrat (lit), - lit == repr_lit ? 0 : find_representative_lrat (-lit)); - Rewrite rew2 = Rewrite ( - other, other == repr_other ? 0 : repr_other, - other == repr_other ? 0 : find_representative_lrat (other), - other == repr_other ? 0 : find_representative_lrat (-other)); - push_id_and_rewriting_lrat_unit (c1, rew1, lrat_chain, true, rew2); - LOG (lrat_chain, "lrat chain"); - swap (internal->lrat_chain, lrat_chain); - } - internal->assign_unit (repr_lit); - if (internal->lrat) { - lrat_chain.clear (); - LRAT_ID id = internal->unit_id (repr_lit); - CADICAL_assert (id); - lrat_chain.push_back (id); - if (lit != repr_lit) { - const LRAT_ID repr_id2 = find_representative_lrat (-lit); - lrat_chain.push_back (repr_id2); - } - lrat_chain.push_back (id2); - if (other != repr_other) { - const LRAT_ID repr_larger_id2 = find_representative_lrat (other); - lrat_chain.push_back (repr_larger_id2); - } - LOG (lrat_chain, "lrat chain"); - swap (internal->lrat_chain, lrat_chain); - } - internal->learn_empty_clause (); - return false; - } - - LOG ("merging %d [=%d] and %d [=%d]", lit, repr_lit, other, repr_other); - promote_clause (c1), promote_clause (c2); - bool learn_clause = (lit != repr_lit) || (other != repr_other); - if (learn_clause) { - if (internal->lrat) { - if (lit != repr_lit) { - LOG ("adding chain for lit %d -> %d", lit, repr_lit); - lrat_chain.push_back (find_representative_lrat (lit)); - } - if (other != repr_other) { - LOG ("adding chain for lit %d -> %d", -other, -repr_other); - lrat_chain.push_back (find_representative_lrat (-other)); - } - lrat_chain.push_back (id1); - } - Clause *eq1 = learn_binary_tmp_or_full_clause (repr_lit, -repr_other); - - if (internal->lrat) { - lrat_chain.clear (); - if (lit != repr_lit) - lrat_chain.push_back (find_representative_lrat (-lit)); - if (other != repr_other) - lrat_chain.push_back (find_representative_lrat (other)); - lrat_chain.push_back (id2); - } - Clause *eq2 = learn_binary_tmp_or_full_clause (-repr_lit, repr_other); - if (internal->lrat) { - lrat_chain.clear (); - if (smaller_repr == repr_lit) { - CADICAL_assert (larger_repr == repr_other); - representative_id (-larger_repr) = eq2->id; - CADICAL_assert (std::find (eq2->begin (), eq2->end (), larger_repr) != - eq2->end ()); - representative_id (larger_repr) = eq1->id; - CADICAL_assert (std::find (eq1->begin (), eq1->end (), -larger_repr) != - eq1->end ()); - } else { - CADICAL_assert (larger_repr == repr_lit); - representative_id (-larger_repr) = eq1->id; - CADICAL_assert (std::find (eq1->begin (), eq1->end (), larger_repr) != - eq1->end ()); - representative_id (larger_repr) = eq2->id; - CADICAL_assert (std::find (eq2->begin (), eq2->end (), -larger_repr) != - eq2->end ()); - } - } - - } else if (internal->lrat) { - LOG ("not learning new clause, using already existing one"); - if (smaller_repr == repr_lit) { - LOG ("setting ids of %d: %" PRIu64 "; %d: %" PRIu64 " (case 1)", - larger, id1, -larger, id2); - representative_id (-larger_repr) = id2; - representative_id (larger_repr) = id1; - } else { - LOG ("setting ids of %d: %" PRIu64 "; %d: %" PRIu64 " (case 2)", - larger, id2, -larger, id1); - representative_id (-larger_repr) = id1; - representative_id (larger_repr) = id2; - } - } - - LOG ("updating %d -> %d", larger_repr, smaller_repr); - representative (larger_repr) = smaller_repr; - representative (-larger_repr) = -smaller_repr; - schedule_literal (larger_repr); - ++internal->stats.congruence.congruent; - return true; -} - -/*------------------------------------------------------------------------*/ -GOccs &Closure::goccs (int lit) { return gtab[internal->vlit (lit)]; } - -void Closure::connect_goccs (Gate *g, int lit) { - LOG (g, "connect %d to", lit); - // incorrect for ITE - // CADICAL_assert (std::find(begin (goccs (lit)), end (goccs (lit)), g) == - // std::end (goccs (lit))); - goccs (lit).push_back (g); -} - -uint64_t &Closure::largecount (int lit) { - CADICAL_assert (internal->vlit (lit) < glargecounts.size ()); - return glargecounts[internal->vlit (lit)]; -} - -/*------------------------------------------------------------------------*/ -// Initialization - -void Closure::init_closure () { - representant.resize (2 * internal->max_var + 3); - eager_representant.resize (2 * internal->max_var + 3); - if (internal->lrat) { - eager_representant_id.resize (2 * internal->max_var + 3); - representant_id.resize (2 * internal->max_var + 3); - lazy_propagated_idx.resize (internal->max_var + 1, false); - for (auto lit : internal->trail) - lazy_propagated (lit) = true; - } - marks.resize (2 * internal->max_var + 3); - mu1_ids.resize (2 * internal->max_var + 3); - if (internal->lrat) { - mu2_ids.resize (2 * internal->max_var + 3); - mu4_ids.resize (2 * internal->max_var + 3); - } -#ifndef CADICAL_NDEBUG - for (auto &it : mu1_ids) - it.current_lit = 0, it.clause = nullptr; - for (auto &it : mu2_ids) - it.current_lit = 0, it.clause = nullptr; - for (auto &it : mu4_ids) - it.current_lit = 0, it.clause = nullptr; -#endif - scheduled.resize (internal->max_var + 1); - gtab.resize (2 * internal->max_var + 3); - for (auto v : internal->vars) { - representative (v) = v; - representative (-v) = -v; - eager_representative (v) = v; - eager_representative (-v) = -v; - } - units = internal->propagated; - Random rand (internal->stats.congruence.rounds); - for (auto &n : nonces) { - n = 1 | rand.next (); - } -#ifdef LOGGING - fresh_id = internal->clause_id; -#endif - internal->init_noccs (); - internal->init_occs (); -} - -void Closure::init_and_gate_extraction () { - LOG ("[gate-extraction]"); - for (Clause *c : internal->clauses) { - if (c->garbage) - continue; - if (c->redundant && c->size != 2) - continue; - if (c->size > 2) - continue; - CADICAL_assert (c->size == 2); - const int lit = c->literals[0]; - const int other = c->literals[1]; - internal->noccs (lit)++; - internal->noccs (other)++; - internal->watch_clause (c); - } -} - -/*------------------------------------------------------------------------*/ -void Closure::check_and_gate_implied (Gate *g) { - CADICAL_assert (internal->clause.empty ()); - CADICAL_assert (g->tag == Gate_Type::And_Gate); - if (internal->lrat) - return; - LOG (g, "checking implied"); - const int lhs = g->lhs; - const int not_lhs = -lhs; - for (auto other : g->rhs) - check_binary_implied (not_lhs, other); - internal->clause = g->rhs; - check_implied (); - internal->clause.clear (); -} - -void Closure::delete_proof_chain () { - if (!internal->proof) { - CADICAL_assert (chain.empty ()); - return; - } - if (chain.empty ()) - return; - LOG ("starting deletion of proof chain"); - auto &clause = internal->clause; - CADICAL_assert (clause.empty ()); - uint32_t id1 = UINT32_MAX, id2 = UINT32_MAX; - LRAT_ID id = 0; - - LOG (chain, "chain:"); - for (auto lit : chain) { - LOG ("reading %d from chain", lit); - if (id1 == UINT32_MAX) { - id1 = lit; - id = (LRAT_ID) id1; - continue; - } - if (id2 == UINT32_MAX) { - id2 = lit; - id = ((LRAT_ID) id1 << 32) + id2; - continue; - } - if (lit) { // parsing the id first - LOG ("found %d as literal in chain", lit); - clause.push_back (lit); - } else { - CADICAL_assert (id); - internal->proof->delete_clause (id, false, clause); - clause.clear (); - id = 0, id1 = UINT32_MAX, id2 = UINT32_MAX; - } - } - CADICAL_assert (clause.empty ()); - chain.clear (); - LOG ("finished deletion of proof chain"); -} - -/*------------------------------------------------------------------------*/ -// Simplification -bool Closure::skip_and_gate (Gate *g) { - CADICAL_assert (g->tag == Gate_Type::And_Gate); - if (g->garbage) - return true; - const int lhs = g->lhs; - if (internal->val (lhs) > 0) { - mark_garbage (g); - return true; - } - - CADICAL_assert (g->arity () > 1); - return false; -} - -bool Closure::skip_xor_gate (Gate *g) { - CADICAL_assert (g->tag == Gate_Type::XOr_Gate); - if (g->garbage) - return true; - CADICAL_assert (g->arity () > 1); - return false; -} - -void Closure::shrink_and_gate (Gate *g, int falsifies, int clashing) { - if (falsifies) { - g->rhs.resize (1); - g->rhs[0] = falsifies; - g->hash = hash_lits (nonces, g->rhs); - } else if (clashing) { - LOG (g, "gate before clashing on %d", clashing); - g->rhs.resize (2); - g->rhs[0] = clashing; - g->rhs[1] = -clashing; - g->hash = hash_lits (nonces, g->rhs); - LOG (g, "gate after clashing on %d", clashing); - } - g->shrunken = true; -} - -void Closure::update_and_gate_unit_build_lrat_chain ( - Gate *g, int src, LRAT_ID id1, LRAT_ID id2, int dst, - std::vector &extra_reasons_lit, - std::vector &extra_reasons_ulit) { - LOG ("generate chain for gate boiling down to unit"); - if (g->neg_lhs_ids.size () != 1) { - - if (g->degenerated_and_neg || g->degenerated_and_pos) { - // can happen for 4 = AND 3 4 (degenerated with only the clause -4 3) - // with a rewriting 4 -> 1 (unchanged clause) - // and later 1 -> 3 (unchanged clause) - // but you do not know anymore from the gate that it is degenerated - CADICAL_assert (g->pos_lhs_ids.size () == 1); - push_id_and_rewriting_lrat_unit (g->pos_lhs_ids[0].clause, Rewrite (), - extra_reasons_ulit, true, Rewrite ()); - return; - } - CADICAL_assert (g->lhs == g->rhs[0] || (g->lhs == src && g->rhs[0] == dst)); - CADICAL_assert (g->pos_lhs_ids.size () <= 1); // either degenerated or empty A = A - return; - } - CADICAL_assert (g->neg_lhs_ids.size () == 1); - CADICAL_assert (!g->pos_lhs_ids.empty ()); - - const int repr_lit = find_representative (g->lhs); - const int repr_other = find_representative (g->rhs[0]); - if (repr_lit == repr_other) { - LOG ("skipping already merged"); - return; - } - - push_id_and_rewriting_lrat_unit (g->neg_lhs_ids[0].clause, Rewrite (), - extra_reasons_ulit, true, Rewrite (), - g->lhs, -dst); - LOG (extra_reasons_ulit, "lrat chain for negative side"); - - lrat_chain.clear (); - - CADICAL_assert (!g->pos_lhs_ids.empty ()); - for (auto litId : g->pos_lhs_ids) - push_id_and_rewriting_lrat_unit ( - litId.clause, Rewrite (src, dst, id1, id2), extra_reasons_lit, true, - Rewrite (), -g->lhs, dst); - LOG (extra_reasons_lit, "lrat chain for positive side"); -} - -void Closure::update_and_gate_build_lrat_chain ( - Gate *g, Gate *h, std::vector &extra_reasons_lit, - std::vector &extra_reasons_ulit, bool remove_units) { - CADICAL_assert (g != h); - LOG (g, "merging"); - LOG (h, "with"); - // If the LHS are identical, do not even attempt to build the LRAT chain - if (find_representative (g->lhs) == find_representative (h->lhs)) - return; - // set to same value, don't do anything - if (internal->val (g->lhs) && internal->val (g->lhs) == internal->val (h->lhs)) - return; - const bool g_tautology = gate_contains (g, g->lhs); - const bool h_tautology = gate_contains (h, h->lhs); - if (g_tautology && h_tautology) { - LOG ("both gates are a tautology"); - // special case: actually we have an equivalence due to binary clauses - // and all gate clauses (except one binary) are actually tautologies - for (auto &litId : g->pos_lhs_ids) { - if (litId.current_lit == h->lhs) { - CADICAL_assert (extra_reasons_lit.empty ()); - LOG (litId.clause, "binary clause to push into the reason"); - litId.clause = produce_rewritten_clause_lrat (litId.clause, g->lhs, - remove_units); - CADICAL_assert (litId.clause); - extra_reasons_lit.push_back (litId.clause->id); - } - } - CADICAL_assert (!extra_reasons_lit.empty ()); - CADICAL_assert (extra_reasons_lit.size () == 1); - - for (auto &litId : h->pos_lhs_ids) { - if (litId.current_lit == g->lhs) { - CADICAL_assert (extra_reasons_ulit.empty ()); - CADICAL_assert (litId.clause); - LOG (litId.clause, "binary clause to push into the reason"); - litId.clause = produce_rewritten_clause_lrat (litId.clause, h->lhs, - remove_units); - CADICAL_assert (litId.clause); - extra_reasons_ulit.push_back (litId.clause->id); - } - } - CADICAL_assert (!extra_reasons_ulit.empty ()); - CADICAL_assert (extra_reasons_ulit.size () == 1); - return; - } - if (g_tautology || h_tautology) { - // special case: actually we have an equivalence due to binary clauses - // and some of the clauses from the gate are actually tautologies - CADICAL_assert (g_tautology != h_tautology); - Gate *tauto = (g_tautology ? g : h); - Gate *other = (g_tautology ? h : g); - LOG (tauto, "one gate is a tautology"); - CADICAL_assert (tauto != other); - CADICAL_assert (tauto == h || tauto == g); - - auto &extra_reasons_tauto = - (!g_tautology ? extra_reasons_lit : extra_reasons_ulit); - auto &extra_reasons_other = - (!g_tautology ? extra_reasons_ulit : extra_reasons_lit); - - // one direction: the binary clause already exists - for (auto &litId : other->pos_lhs_ids) { - if (litId.current_lit == tauto->lhs) { - CADICAL_assert (litId.clause); - CADICAL_assert (extra_reasons_tauto.empty ()); - LOG (litId.clause, "binary clause to push into the reason"); - litId.clause = produce_rewritten_clause_lrat ( - litId.clause, other->lhs, remove_units); - CADICAL_assert (litId.clause); - extra_reasons_tauto.push_back (litId.clause->id); - } - } - CADICAL_assert (!extra_reasons_tauto.empty ()); - - // other direction, we have to resolve - LOG (tauto, "now the other direction"); - for (auto &litId : tauto->pos_lhs_ids) { - CADICAL_assert (litId.clause); - LOG (litId.clause, - "binary clause from %d to push into the reason [avoiding %d]", - litId.current_lit, tauto->lhs); - if (litId.current_lit != tauto->lhs) { - LOG (litId.clause, "binary clause to push into the reason"); - CADICAL_assert (litId.clause); - litId.clause = produce_rewritten_clause_lrat ( - litId.clause, tauto->lhs, remove_units); - if (!litId.clause) // degenerated but does not know yet - continue; - CADICAL_assert (litId.clause); - extra_reasons_other.push_back (litId.clause->id); - } - tauto->pos_lhs_ids.erase (std::remove_if (begin (tauto->pos_lhs_ids), - end (tauto->pos_lhs_ids), - [] (const LitClausePair &p) { - return !p.clause; - }), - end (tauto->pos_lhs_ids)); - } - CADICAL_assert (!extra_reasons_other.empty ()); - produce_rewritten_clause_lrat_and_clean (other->neg_lhs_ids, other->lhs, - remove_units); - push_id_on_chain (extra_reasons_other, other->neg_lhs_ids); - CADICAL_assert (!extra_reasons_tauto.empty ()); - CADICAL_assert (!extra_reasons_other.empty ()); - return; - } - // default: resolve all clauses - // first rewrite - // TODO: do we really need dest as second exclusion? - produce_rewritten_clause_lrat_and_clean (h->pos_lhs_ids, -h->lhs, - remove_units); - CADICAL_assert (internal->clause.empty ()); - produce_rewritten_clause_lrat_and_clean (h->neg_lhs_ids, -h->lhs, - remove_units); - CADICAL_assert (internal->clause.empty ()); - produce_rewritten_clause_lrat_and_clean (g->pos_lhs_ids, -g->lhs, - remove_units); - CADICAL_assert (internal->clause.empty ()); - produce_rewritten_clause_lrat_and_clean (g->neg_lhs_ids, -g->lhs, - remove_units); - CADICAL_assert (internal->clause.empty ()); - - push_id_on_chain (extra_reasons_ulit, h->pos_lhs_ids); - push_id_on_chain (extra_reasons_ulit, g->neg_lhs_ids[0].clause); - lrat_chain.clear (); - LOG (extra_reasons_ulit, "lrat chain for negative side"); - - push_id_on_chain (extra_reasons_lit, g->pos_lhs_ids); - push_id_on_chain (extra_reasons_lit, h->neg_lhs_ids); - - lrat_chain.clear (); - LOG (extra_reasons_lit, "lrat chain for positive side"); - CADICAL_assert (!extra_reasons_lit.empty ()); - CADICAL_assert (!extra_reasons_ulit.empty ()); -} - -void Closure::update_and_gate (Gate *g, GatesTable::iterator it, int src, - int dst, LRAT_ID id1, LRAT_ID id2, - int falsifies, int clashing) { - LOG (g, "update and gate of arity %ld", g->arity ()); - CADICAL_assert (lrat_chain.empty ()); - bool garbage = true; - if (falsifies || clashing) { - if (internal->lrat) - learn_congruence_unit_falsifies_lrat_chain (g, src, dst, clashing, - falsifies, 0); - int unit = -g->lhs; - if (unit == src) - unit = dst; - else if (unit == -src) - unit = -dst; - learn_congruence_unit (unit); - if (internal->lrat) - lrat_chain.clear (); - } else if (g->arity () == 1) { - const signed char v = internal->val (g->lhs); - if (v > 0) { - if (internal->lrat) - learn_congruence_unit_falsifies_lrat_chain (g, src, dst, 0, 0, - g->lhs); - learn_congruence_unit (g->rhs[0]); - if (internal->lrat) - lrat_chain.clear (); - } else if (v < 0) { - if (internal->lrat) - learn_congruence_unit_when_lhs_set (g, src, id1, id2, dst); - learn_congruence_unit (-g->rhs[0]); - if (internal->lrat) - lrat_chain.clear (); - } else { - std::vector extra_reasons_lit; - std::vector extra_reasons_ulit; - if (internal->lrat) - update_and_gate_unit_build_lrat_chain (g, src, id1, id2, g->rhs[0], - extra_reasons_lit, - extra_reasons_ulit); - if (merge_literals_lrat (g, g, g->lhs, g->rhs[0], extra_reasons_lit, - extra_reasons_ulit)) { - ++internal->stats.congruence.unaries; - ++internal->stats.congruence.unary_and; - } - } - } else { - CADICAL_assert (g->arity () > 1); - sort_literals_by_var (g->rhs); - Gate *h = find_and_lits (g->rhs, g); - CADICAL_assert (g != h); - if (h) { - CADICAL_assert (garbage); - std::vector extra_reasons_lit2; - std::vector extra_reasons_ulit2; - if (internal->lrat) - update_and_gate_build_lrat_chain (g, h, extra_reasons_lit2, - extra_reasons_ulit2); - if (merge_literals_lrat (g, h, g->lhs, h->lhs, extra_reasons_lit2, - extra_reasons_ulit2)) - ++internal->stats.congruence.ands; - } else { - if (g->indexed) { - LOG (g, "removing from table"); - (void) table.erase (it); - } - g->hash = hash_lits (nonces, g->rhs); - LOG (g, "inserting gate into table"); - CADICAL_assert (table.count (g) == 0); - table.insert (g); - g->indexed = true; - garbage = false; - if (internal->lrat) - lrat_chain.clear (); - } - } - - if (garbage && !internal->unsat) - mark_garbage (g); -} - -void Closure::update_xor_gate (Gate *g, GatesTable::iterator git) { - CADICAL_assert (g->tag == Gate_Type::XOr_Gate); - CADICAL_assert (!internal->unsat && chain.empty ()); - LOG (g, "updating"); - bool garbage = true; - // TODO Florian LRAT for learn_congruence_unit - CADICAL_assert (g->arity () == 0 || internal->clause.empty ()); - CADICAL_assert (clause.empty ()); - if (g->arity () == 0) { - if (internal->clause.size ()) { - CADICAL_assert (!internal->proof || (internal->clause.size () == 1 && - internal->clause.back () == -g->lhs)); - CADICAL_assert (!internal->lrat || lrat_chain.size ()); - internal->clause.clear (); - - } else if (internal->lrat) { - simplify_unit_xor_lrat_clauses (g->pos_lhs_ids, g->lhs); - CADICAL_assert (clause.size () && clause.back () == -g->lhs); - clause.clear (); - } - - if (internal->lrat && internal->val (-g->lhs) < 0) { - internal->lrat_chain.push_back (internal->unit_id (g->lhs)); - for (auto id : lrat_chain) - internal->lrat_chain.push_back (id); - lrat_chain.clear (); - internal->learn_empty_clause(); - } else - learn_congruence_unit (-g->lhs); - - CADICAL_assert (clause.empty ()); - } else if (g->arity () == 1) { - std::vector reasons_implication, reasons_back; - if (internal->lrat) { - vector first; - simplify_and_sort_xor_lrat_clauses (g->pos_lhs_ids, first, g->lhs); - g->pos_lhs_ids = first; - CADICAL_assert (g->pos_lhs_ids.size () == 2); - reasons_implication.push_back (g->pos_lhs_ids[0].clause->id); - reasons_back.push_back (g->pos_lhs_ids[1].clause->id); - } - const signed char v = internal->val (g->lhs); - if (v > 0) { - if (internal->lrat) { - push_lrat_unit (g->lhs); - lrat_chain.push_back (g->pos_lhs_ids[0].clause->id); - } - learn_congruence_unit (g->rhs[0]); - } else if (v < 0) { - if (internal->lrat) { - push_lrat_unit (-g->lhs); - lrat_chain.push_back (g->pos_lhs_ids[1].clause->id); - } - learn_congruence_unit (-g->rhs[0]); - } else if (merge_literals_lrat ( - g->lhs, g->rhs[0], reasons_implication, - reasons_back)) { // TODO Florian merge with LRAT - ++internal->stats.congruence.unaries; - ++internal->stats.congruence.unary_and; - } - CADICAL_assert (clause.empty ()); - } else { - Gate *h = find_xor_gate (g); - if (h) { - CADICAL_assert (garbage); - std::vector reasons_implication, reasons_back; - add_xor_matching_proof_chain (g, g->lhs, h->pos_lhs_ids, h->lhs, - reasons_implication, reasons_back); - if (merge_literals_lrat (g->lhs, h->lhs, reasons_implication, - reasons_back)) - ++internal->stats.congruence.xors; - delete_proof_chain (); - } else { - if (g->indexed) { - remove_gate (git); - } - g->hash = hash_lits (nonces, g->rhs); - LOG (g, "reinserting in table"); - table.insert (g); - g->indexed = true; - CADICAL_assert (table.find (g) != end (table)); - garbage = false; - } - CADICAL_assert (clause.empty ()); - } - if (garbage && !internal->unsat) - mark_garbage (g); - CADICAL_assert (clause.empty ()); -} - -void Closure::simplify_and_gate (Gate *g) { - if (skip_and_gate (g)) - return; - GatesTable::iterator git = (g->indexed ? table.find (g) : end (table)); - CADICAL_assert (!g->indexed || git != end (table)); - LOG (g, "simplifying"); - int falsifies = 0; - std::vector::iterator it = begin (g->rhs); - bool ulhs_in_rhs = false; - for (auto lit : g->rhs) { - const signed char v = internal->val (lit); - if (v > 0) { - continue; - } - if (v < 0) { - falsifies = lit; - continue; - } - if (lit == -g->lhs) - ulhs_in_rhs = true; - *it++ = lit; - if (lit == g->lhs) - g->degenerated_and_pos = true; - if (lit == -g->lhs) - g->degenerated_and_neg = true; - } - - if (internal->lrat) { // updating reasons - size_t i = 0, size = g->pos_lhs_ids.size (); - for (size_t j = 0; j < size; ++j) { - LOG ("looking at %d [%ld %ld]", g->pos_lhs_ids[j].current_lit, i, j); - g->pos_lhs_ids[i] = g->pos_lhs_ids[j]; - if (!g->degenerated_and_pos && - internal->val (g->pos_lhs_ids[i].current_lit) && - g->pos_lhs_ids[i].current_lit != falsifies) - continue; - LOG ("keeping %d [%ld %ld]", g->pos_lhs_ids[i].current_lit, i, j); - ++i; - } - LOG ("resizing to %ld", i); - g->pos_lhs_ids.resize (i); - } - - CADICAL_assert (it <= end (g->rhs)); // can be equal when ITE are converted to - // ands leading to - CADICAL_assert (it >= begin (g->rhs)); - LOG (g, "shrunken"); - - g->shrunken = true; - g->rhs.resize (it - std::begin (g->rhs)); - g->hash = hash_lits (nonces, g->rhs); - - LOG (g, "shrunken"); - shrink_and_gate (g, falsifies); - std::vector reasons_lrat_src, reasons_lrat_usrc; - - update_and_gate (g, git, 0, 0, 0, 0, falsifies, 0); - ++internal->stats.congruence.simplified_ands; - ++internal->stats.congruence.simplified; - - if (ulhs_in_rhs) { // missing in Kissat, TODO: port back - CADICAL_assert (gate_contains (g, -g->lhs)); - if (internal->lrat) { - for (auto litId : g->pos_lhs_ids) { - if (litId.current_lit == g->lhs) { - compute_rewritten_clause_lrat_simple (litId.clause, 0); - break; - } - } - } - learn_congruence_unit (-g->lhs); - } -} - -bool Closure::simplify_gate (Gate *g) { - switch (g->tag) { - case Gate_Type::And_Gate: - simplify_and_gate (g); - break; - case Gate_Type::XOr_Gate: - simplify_xor_gate (g); - break; - case Gate_Type::ITE_Gate: - simplify_ite_gate (g); - break; - default: - CADICAL_assert (false); - break; - } - CADICAL_assert (lrat_chain.empty ()); - return !internal->unsat; -} - -bool Closure::simplify_gates (int lit) { - const auto &occs = goccs (lit); - for (Gate *g : occs) { - CADICAL_assert (lrat_chain.empty ()); - CADICAL_assert (clause.empty ()); - if (!simplify_gate (g)) - return false; - } - return true; -} -/*------------------------------------------------------------------------*/ -// AND gates - -Gate *Closure::find_and_lits (const vector &rhs, Gate *except) { - CADICAL_assert (is_sorted (begin (rhs), end (rhs), - sort_literals_by_var_smaller (internal))); - return find_gate_lits (rhs, Gate_Type::And_Gate, except); -} - -// search for the gate in the hash-table. We cannot use find, as we might -// be changing a gate, so there might be 2 gates with the same LHS (the one -// we are changing and the other we are looking for) -Gate *Closure::find_gate_lits (const vector &rhs, Gate_Type typ, - Gate *except) { - Gate *g = new Gate; - g->tag = typ; - g->rhs = rhs; - g->hash = hash_lits (nonces, g->rhs); - g->lhs = 0; - g->garbage = false; -#ifdef LOGGING - g->id = 0; -#endif - const auto &its = table.equal_range (g); - Gate *h = nullptr; - for (auto it = its.first; it != its.second; ++it) { - LOG ((*it), "checking gate in the table"); - if (*it == except) - continue; - CADICAL_assert ((*it)->lhs != g->lhs); - if ((*it)->tag != g->tag) - continue; - if ((*it)->rhs != g->rhs) - continue; - h = *it; - break; - } - - if (h) { - LOG (g, "searching"); - LOG (h, "already existing"); - delete g; - return h; - } - - else { - LOG (g->rhs, "gate not found in table"); - delete g; - return nullptr; - } -} - -Gate *Closure::new_and_gate (Clause *base_clause, int lhs) { - rhs.clear (); - auto &lits = this->lits; - - for (auto lit : lits) { - if (lhs != lit) { - CADICAL_assert (lhs != -lit); - rhs.push_back (-lit); - } - } - - CADICAL_assert (rhs.size () + 1 == lits.size ()); - sort_literals_by_var (this->rhs); - - Gate *h = find_and_lits (this->rhs); - Gate *g = new Gate; - g->lhs = lhs; - g->tag = Gate_Type::And_Gate; - if (internal->lrat) { - g->neg_lhs_ids.push_back (LitClausePair (lhs, base_clause)); - for (auto i : lrat_chain_and_gate) - g->pos_lhs_ids.push_back (i); -#ifdef LOGGING - std::vector result; - transform (begin (g->pos_lhs_ids), end (g->pos_lhs_ids), - back_inserter (result), - [] (const LitClausePair &x) { return x.clause->id; }); - LOG (result, "lrat chain positive (%d):", lhs); - result.clear (); - transform (begin (g->neg_lhs_ids), end (g->neg_lhs_ids), - back_inserter (result), - [] (const LitClausePair &x) { return x.clause->id; }); - LOG (result, "lrat chain negative (%d):", lhs); -#endif - } - - if (internal->lrat) - lrat_chain_and_gate.clear (); - - if (h) { - std::vector reasons_lrat_src, reasons_lrat_usrc; - if (internal->lrat) - merge_and_gate_lrat_produce_lrat (g, h, reasons_lrat_src, - reasons_lrat_usrc); - if (merge_literals_lrat (g, h, lhs, h->lhs, reasons_lrat_src, - reasons_lrat_usrc)) { - LOG ("found merged literals"); - ++internal->stats.congruence.ands; - } - return nullptr; - } else { - g->rhs = {rhs}; - CADICAL_assert (!internal->lrat || - g->pos_lhs_ids.size () == - g->arity ()); // otherwise we need intermediate clauses - g->garbage = false; - g->indexed = true; - g->shrunken = false; - g->hash = hash_lits (nonces, g->rhs); - - table.insert (g); - ++internal->stats.congruence.gates; -#ifdef LOGGING - g->id = fresh_id++; -#endif - LOG (g, "creating new"); - for (auto lit : g->rhs) { - connect_goccs (g, lit); - } - } - return g; -} - -Gate *Closure::find_first_and_gate (Clause *base_clause, int lhs) { - CADICAL_assert (internal->analyzed.empty ()); - const int not_lhs = -lhs; - LOG ("trying to find AND gate with first LHS %d", (lhs)); - LOG ("negated LHS %d occurs in %zd binary clauses", (not_lhs), - internal->occs (not_lhs).size ()); - unsigned matched = 0; - - const size_t arity = lits.size () - 1; - - for (auto w : internal->watches (not_lhs)) { - LOG (w.clause, "checking clause for candidates"); - CADICAL_assert (w.binary ()); - CADICAL_assert (w.clause->size == 2); - CADICAL_assert (w.clause->literals[0] == -lhs || w.clause->literals[1] == -lhs); - const int other = w.blit; - signed char &mark = marked (other); - if (mark) { - LOG ("marking %d mu2", other); - ++matched; - CADICAL_assert (~(mark & 2)); - mark |= 2; - internal->analyzed.push_back (other); - set_mu2_reason (other, w.clause); - if (internal->lrat) - lrat_chain_and_gate.push_back (LitClausePair (other, w.clause)); - } - } - - LOG ("found %zd initial LHS candidates", internal->analyzed.size ()); - if (matched < arity) { - if (internal->lrat) - lrat_chain_and_gate.clear (); - return nullptr; - } - - Gate *g = new_and_gate (base_clause, lhs); - - if (internal->lrat) { - lrat_chain_and_gate.clear (); - } - return g; -} - -Clause *Closure::learn_binary_tmp_or_full_clause (int a, int b) { - Clause *eq1; - if (internal->lrat) { - eq1 = add_tmp_binary_clause (a, b); - eq1 = maybe_promote_tmp_binary_clause (eq1); - } else - eq1 = maybe_add_binary_clause (a, b); - return eq1; -} - -Clause *Closure::maybe_add_binary_clause (int a, int b) { - CADICAL_assert (internal->clause.empty ()); - CADICAL_assert (internal->lrat_chain.empty ()); - CADICAL_assert (!internal->lrat); - CADICAL_assert (lrat_chain.empty ()); - LOG ("learning binary clause %d %d", a, b); - if (internal->unsat) - return nullptr; - if (a == -b) - return nullptr; - if (!internal->lrat) { - const signed char a_value = internal->val (a); - if (a_value > 0) - return nullptr; - const signed char b_value = internal->val (b); - if (b_value > 0) - return nullptr; - int unit = 0; - if (a == b) - unit = a; - else if (a_value < 0 && !b_value) { - unit = b; - } else if (!a_value && b_value < 0) - unit = a; - if (unit) { - LOG ("clause reduced to unit %d", unit); - learn_congruence_unit (unit); - return nullptr; - } - CADICAL_assert (!a_value), CADICAL_assert (!b_value); - } - return add_binary_clause (a, b); -} - -Clause *Closure::add_binary_clause (int a, int b) { - CADICAL_assert (internal->clause.empty ()); - internal->clause.push_back (a); - internal->clause.push_back (b); - if (internal->lrat) { - CADICAL_assert (lrat_chain.size () >= 1); - CADICAL_assert (internal->lrat_chain.empty ()); - swap (internal->lrat_chain, lrat_chain); - } - LOG (internal->lrat_chain, "chain"); - Clause *res = internal->new_hyper_ternary_resolved_clause_and_watch ( - false, full_watching); - const bool already_sorted = internal->vlit (a) < internal->vlit (b); - binaries.push_back (CompactBinary (res, res->id, already_sorted ? a : b, - already_sorted ? b : a)); - if (!full_watching) - new_unwatched_binary_clauses.push_back (res); - LOG (res, "learning clause"); - internal->clause.clear (); - if (internal->lrat) { - internal->lrat_chain.clear (); - } - CADICAL_assert (internal->clause.empty ()); - CADICAL_assert (internal->lrat_chain.empty ()); - return res; -} - -void Closure::check_not_tmp_binary_clause (Clause *c) { -#ifndef CADICAL_NDEBUG - CADICAL_assert (internal->lrat); - CADICAL_assert (internal->lrat_chain.empty ()); - CADICAL_assert (c->size == 2); - if (internal->val (c->literals[0]) || internal->val (c->literals[1])) - return; - CADICAL_assert (std::find (begin (extra_clauses), end (extra_clauses), c) == - end (extra_clauses)); -#else - (void) c; -#endif -}; - -Clause *Closure::maybe_promote_tmp_binary_clause (Clause *c) { - CADICAL_assert (internal->lrat); - CADICAL_assert (internal->lrat_chain.empty ()); - CADICAL_assert (c->size == 2); - LOG (c, "promoting tmp"); -#ifndef CADICAL_NDEBUG - CADICAL_assert (std::find (begin (extra_clauses), end (extra_clauses), c) != - end (extra_clauses)); -#endif - if (internal->val (c->literals[0]) || internal->val (c->literals[1])) - return c; - lrat_chain.push_back (c->id); - Clause *res = add_binary_clause (c->literals[0], c->literals[1]); - LOG (res, "promoted to"); - return res; -}; - -Clause *Closure::add_tmp_binary_clause (int a, int b) { - CADICAL_assert (internal->clause.empty ()); - CADICAL_assert (internal->lrat_chain.empty ()); - CADICAL_assert (internal->lrat); - LOG ("learning tmp binary clause %d %d", a, b); - if (internal->unsat) - return nullptr; - if (a == -b) - return nullptr; - CADICAL_assert (internal->clause.empty ()); - internal->clause.push_back (a); - internal->clause.push_back (b); - if (internal->lrat) { - CADICAL_assert (lrat_chain.size () >= 1); - CADICAL_assert (internal->lrat_chain.empty ()); - } - LOG (lrat_chain, "chain"); - Clause *res = new_tmp_clause (internal->clause); - internal->clause.clear (); - if (internal->lrat) { - lrat_chain.clear (); - } - CADICAL_assert (internal->clause.empty ()); - CADICAL_assert (internal->lrat_chain.empty ()); - LOG (res, "promoted to"); - return res; -} - -Gate *Closure::find_remaining_and_gate (Clause *base_clause, int lhs) { - const int not_lhs = -lhs; - - if (marked (not_lhs) < 2) { - LOG ("skipping no-candidate LHS %d (%d)", lhs, marked (not_lhs)); - return nullptr; - } - - LOG ("trying to find AND gate with remaining LHS %d", (lhs)); - LOG ("negated LHS %d occurs times in %zd binary clauses", (not_lhs), - internal->noccs (-lhs)); - - const size_t arity = lits.size () - 1; - size_t matched = 0; - CADICAL_assert (1 < arity); - - for (auto w : internal->watches (not_lhs)) { - CADICAL_assert (w.binary ()); -#ifdef LOGGING - Clause *c = w.clause; - LOG (c, "checking"); - CADICAL_assert (c->size == 2); - CADICAL_assert (c->literals[0] == not_lhs || c->literals[1] == not_lhs); -#endif - const int other = w.blit; - signed char &mark = marked (other); - if (!mark) - continue; - ++matched; - if (!(mark & 2)) { - lrat_chain_and_gate.push_back (LitClausePair (other, w.clause)); - LOG ("pushing %d -> %zd", other, w.clause->id); - continue; - } - LOG ("marking %d mu4", other); - CADICAL_assert (!(mark & 4)); - mark |= 4; - lrat_chain_and_gate.push_back (LitClausePair (other, w.clause)); - if (internal->lrat) - set_mu4_reason (other, w.clause); - } - - { - auto q = begin (internal->analyzed); - CADICAL_assert (!internal->analyzed.empty ()); - CADICAL_assert (marked (not_lhs) == 3); - for (auto lit : internal->analyzed) { - signed char &mark = marked (lit); - if (lit == not_lhs) { - mark = 1; - continue; - } - - CADICAL_assert ((mark & 3) == 3); - if (mark & 4) { - mark = 3; - *q = lit; - ++q; - LOG ("keeping LHS candidate %d", -lit); - } else { - LOG ("dropping LHS candidate %d", -lit); - mark = 1; - } - } - CADICAL_assert (q != end (internal->analyzed)); - CADICAL_assert (marked (not_lhs) == 1); - internal->analyzed.resize (q - begin (internal->analyzed)); - LOG ("after filtering %zu LHS candidate remain", - internal->analyzed.size ()); - } - - if (matched < arity) { - if (internal->lrat) - lrat_chain_and_gate.clear (); - return nullptr; - } - - if (!internal->lrat) - lrat_chain_and_gate.clear (); - return new_and_gate (base_clause, lhs); -} - -struct congruence_occurrences_rank { - Internal *internal; - congruence_occurrences_rank (Internal *s) : internal (s) {} - typedef uint64_t Type; - Type operator() (int a) { - uint64_t res = internal->noccs (-a); - res <<= 32; - res |= a; - return res; - } -}; - -struct congruence_occurrences_larger { - Internal *internal; - congruence_occurrences_larger (Internal *s) : internal (s) {} - bool operator() (const int &a, const int &b) const { - return congruence_occurrences_rank (internal) (a) < - congruence_occurrences_rank (internal) (b); - } -}; - -void Closure::extract_and_gates_with_base_clause (Clause *c) { - CADICAL_assert (!c->garbage); - CADICAL_assert (lrat_chain.empty ()); - LOG (c, "extracting and gates with clause"); - unsigned size = 0; - const unsigned arity_limit = - min (internal->opts.congruenceandarity, MAX_ARITY); - const unsigned size_limit = arity_limit + 1; - size_t max_negbincount = 0; - lits.clear (); - - for (int lit : *c) { - signed char v = internal->val (lit); - if (v < 0) { - // push_lrat_unit (-lit); - continue; - } - if (v > 0) { - CADICAL_assert (!internal->level); - LOG (c, "found satisfied clause"); - internal->mark_garbage (c); - if (internal->lrat) - lrat_chain.clear (); - return; - } - if (++size > size_limit) { - LOG (c, "clause is actually too large, thus skipping"); - if (internal->lrat) - lrat_chain.clear (); - return; - } - const size_t count = internal->noccs (-lit); - if (!count) { - LOG (c, - "%d negated does not occur in any binary clause, thus skipping", - lit); - if (internal->lrat) - lrat_chain.clear (); - return; - } - - if (count > max_negbincount) - max_negbincount = count; - lits.push_back (lit); - } - - if (size < 3) { - LOG (c, "is actually too small, thus skipping"); - if (internal->lrat) - lrat_chain.clear (); - CADICAL_assert (lrat_chain.empty ()); - return; - } - - const size_t arity = size - 1; - if (max_negbincount < arity) { - LOG (c, - "all literals have less than %lu negated occurrences" - "thus skipping", - arity); - if (internal->lrat) - lrat_chain.clear (); - return; - } - - internal->analyzed.clear (); - size_t reduced = 0; - const size_t clause_size = lits.size (); - for (size_t i = 0; i < clause_size; ++i) { - const int lit = lits[i]; - const unsigned count = internal->noccs (-lit); - marked (-lit) = 1; - set_mu1_reason (-lit, c); - if (count < arity) { - if (reduced < i) { - lits[i] = lits[reduced]; - lits[reduced++] = lit; - } else if (reduced == i) - ++reduced; - } - } - const size_t reduced_size = clause_size - reduced; - CADICAL_assert (reduced_size); - LOG (c, "trying as base arity %lu AND gate", arity); - CADICAL_assert (begin (lits) + reduced_size <= end (lits)); - MSORT (internal->opts.radixsortlim, begin (lits), - begin (lits) + reduced_size, - congruence_occurrences_rank (internal), - congruence_occurrences_larger (internal)); - bool first = true; - unsigned extracted = 0; - - for (size_t i = 0; i < clause_size; ++i) { - CADICAL_assert (lrat_chain.empty ()); - if (internal->unsat) - break; - if (c->garbage) - break; - const int lhs = lits[i]; - LOG ("trying LHS candidate literal %d with %ld negated occurrences", - (lhs), internal->noccs (-lhs)); - - if (first) { - first = false; - CADICAL_assert (internal->analyzed.empty ()); - if (find_first_and_gate (c, lhs) != nullptr) { - CADICAL_assert (lrat_chain.empty ()); - ++extracted; - } - } else if (internal->analyzed.empty ()) { - LOG ("early abort AND gate search"); - break; - } else if (find_remaining_and_gate (c, lhs)) { - CADICAL_assert (lrat_chain.empty ()); - ++extracted; - } - } - - unmark_all (); - LOG (lits, "finish unmarking"); - for (auto lit : lits) { - marked (-lit) = 0; - } - lrat_chain_and_gate.clear (); - if (extracted) - LOG (c, "extracted %u with arity %lu AND base", extracted, arity); -} - -void Closure::reset_and_gate_extraction () { - internal->clear_noccs (); - internal->clear_watches (); -} - -void Closure::extract_and_gates () { - CADICAL_assert (!full_watching); - if (!internal->opts.congruenceand) - return; - START (extractands); - marks.resize (internal->max_var * 2 + 3); - init_and_gate_extraction (); - - const size_t size = internal->clauses.size (); - for (size_t i = 0; i < size && !internal->terminated_asynchronously (); - ++i) { // we can learn new binary clauses, but no for loop - CADICAL_assert (lrat_chain.empty ()); - Clause *c = internal->clauses[i]; - if (c->garbage) - continue; - if (c->size == 2) - continue; - if (c->hyper) - continue; - if (c->redundant) - continue; - extract_and_gates_with_base_clause (c); - CADICAL_assert (lrat_chain.empty ()); - } - - reset_and_gate_extraction (); - STOP (extractands); -} - -/*------------------------------------------------------------------------*/ -// XOR gates - -uint64_t &Closure::new_largecounts (int lit) { - CADICAL_assert (internal->vlit (lit) < gnew_largecounts.size ()); - return gnew_largecounts[internal->vlit (lit)]; -} - -uint64_t &Closure::largecounts (int lit) { - CADICAL_assert (internal->vlit (lit) < glargecounts.size ()); - return glargecounts[internal->vlit (lit)]; -} - -bool parity_lits (const vector &lits) { - unsigned res = 0; - for (auto lit : lits) - res ^= (lit < 0); - return res; -} - -void inc_lits (vector &lits) { - bool carry = true; - for (size_t i = 0; i < lits.size () && carry; ++i) { - int lit = lits[i]; - carry = (lit < 0); - lits[i] = -lit; - } -} - -void Closure::check_ternary (int a, int b, int c) { - CADICAL_assert (internal->clause.empty ()); - if (internal->lrat) - return; - auto &clause = internal->clause; - CADICAL_assert (clause.empty ()); - clause.push_back (a); - clause.push_back (b); - clause.push_back (c); - internal->external->check_learned_clause (); - if (internal->proof) { - const LRAT_ID id = internal->clause_id++; - internal->proof->add_derived_clause (id, false, clause, {}); - internal->proof->delete_clause (id, false, clause); - } - - clause.clear (); -} - -void Closure::check_binary_implied (int a, int b) { - CADICAL_assert (internal->clause.empty ()); - if (internal->lrat) - return; - auto &clause = internal->clause; - CADICAL_assert (clause.empty ()); - clause.push_back (a); - clause.push_back (b); - check_implied (); - clause.clear (); -} - -void Closure::check_implied () { - if (internal->lrat) - return; - internal->external->check_learned_clause (); -} - -void Closure::add_xor_shrinking_proof_chain (Gate *g, int pivot) { - CADICAL_assert (internal->clause.empty ()); - CADICAL_assert (clause.empty ()); - if (!internal->proof) - return; - LOG (g, "starting XOR shrinking proof chain"); - vector first; - vector newclauses; - if (internal->lrat) { - simplify_and_sort_xor_lrat_clauses (g->pos_lhs_ids, first, g->lhs, - pivot); - gate_sort_lrat_reasons (first, pivot, g->lhs); - } - - auto &clause = internal->clause; - - const int lhs = g->lhs; - clause.push_back (-lhs); - for (auto lit : g->rhs) - clause.push_back (lit); - - const bool parity = (lhs > 0); - CADICAL_assert (parity == parity_lits (clause)); - const size_t size = clause.size (); - const unsigned end = 1u << (size - 1); - CADICAL_assert (!internal->lrat || first.size () == 2 * end); -#ifdef LOGGING - for (auto pair : first) { - LOG (pair.clause, "key %d", pair.current_lit); - } -#endif - // TODO Florian adjust indices of first depending on order... - // - for (unsigned i = 0; i != end; ++i) { - while (i && parity != parity_lits (clause)) - inc_lits (clause); - LOG (clause, "xor shrinking clause"); - if (!internal->lrat) { - clause.push_back (pivot); - check_and_add_to_proof_chain (clause); - clause.pop_back (); - clause.push_back (-pivot); - check_and_add_to_proof_chain (clause); - clause.pop_back (); - } - if (internal->lrat) { - CADICAL_assert (lrat_chain.empty ()); - lrat_chain.push_back (first[2 * i].clause->id); - lrat_chain.push_back (first[2 * i + 1].clause->id); - } - if (clause.size () > 1) { - if (internal->lrat) { - Clause *c = new_tmp_clause (clause); - newclauses.push_back (LitClausePair (0, c)); - lrat_chain.clear (); - } else { - check_and_add_to_proof_chain (clause); - } - } - if (clause.size () == 1) - return; - inc_lits (clause); - } - g->pos_lhs_ids.swap (newclauses); - - clause.clear (); -} - -void Closure::check_xor_gate_implied (Gate const *const g) { - CADICAL_assert (internal->clause.empty ()); - CADICAL_assert (g->tag == Gate_Type::XOr_Gate); - if (internal->lrat) { - return; - } - const int lhs = g->lhs; - LOG (g, "checking implied"); - auto &clause = internal->clause; - CADICAL_assert (clause.empty ()); - for (auto other : g->rhs) { - CADICAL_assert (other > 0); - clause.push_back (other); - } - clause.push_back (-lhs); - const unsigned arity = g->arity (); - const unsigned end = 1u << arity; - const bool parity = (lhs > 0); - - for (unsigned i = 0; i != end; ++i) { - while (i && parity_lits (clause) != parity) - inc_lits (clause); - internal->external->check_learned_clause (); - if (internal->proof) { - internal->proof->add_derived_clause (internal->clause_id, false, - clause, {}); - internal->proof->delete_clause (internal->clause_id, false, clause); - } - inc_lits (clause); - } - clause.clear (); -} - -Gate *Closure::find_xor_lits (const vector &rhs) { - CADICAL_assert (is_sorted (begin (rhs), end (rhs), - sort_literals_by_var_smaller (internal))); - return find_gate_lits (rhs, Gate_Type::XOr_Gate); -} - -Gate *Closure::find_xor_gate (Gate *g) { - CADICAL_assert (g->tag == Gate_Type::XOr_Gate); - CADICAL_assert (is_sorted (begin (g->rhs), end (g->rhs), - sort_literals_by_var_smaller (internal))); - return find_gate_lits (g->rhs, Gate_Type::XOr_Gate); -} - -void Closure::reset_xor_gate_extraction () { internal->clear_occs (); } - -bool Closure::normalize_ite_lits_gate (Gate *g) { - auto &rhs = g->rhs; - CADICAL_assert (rhs.size () == 3); - if (internal->lrat) - check_correct_ite_flags (g); - LOG (rhs, "RHS = "); - if (rhs[0] < 0) { - rhs[0] = -rhs[0]; - std::swap (rhs[1], rhs[2]); - if (internal->lrat) { - CADICAL_assert (g->pos_lhs_ids.size () == 4); - std::swap (g->pos_lhs_ids[0], g->pos_lhs_ids[2]); - std::swap (g->pos_lhs_ids[1], g->pos_lhs_ids[3]); - const int8_t flag = g->degenerated_ite; - const int8_t plus_then = flag & NO_PLUS_THEN; - const int8_t neg_then = flag & NO_NEG_THEN; - const int8_t plus_else = flag & NO_PLUS_ELSE; - const int8_t neg_else = flag & NO_NEG_ELSE; - g->degenerated_ite = (plus_then ? Special_ITE_GATE::NO_PLUS_ELSE - : Special_ITE_GATE::NORMAL) | - (neg_then ? Special_ITE_GATE::NO_NEG_ELSE - : Special_ITE_GATE::NORMAL) | - (plus_else ? Special_ITE_GATE::NO_PLUS_THEN - : Special_ITE_GATE::NORMAL) | - (neg_else ? Special_ITE_GATE::NO_NEG_THEN - : Special_ITE_GATE::NORMAL); - CADICAL_assert (g->pos_lhs_ids[0].current_lit == rhs[1]); - CADICAL_assert (g->pos_lhs_ids[2].current_lit == rhs[2]); - if (internal->lrat) - check_correct_ite_flags (g); - } - } - if (rhs[1] > 0) - return false; - if (internal->lrat) - check_correct_ite_flags (g); - rhs[1] = -rhs[1]; - rhs[2] = -rhs[2]; - LOG (rhs, "RHS = "); - if (internal->lrat) { - CADICAL_assert (g->pos_lhs_ids.size () == 4); - std::swap (g->pos_lhs_ids[0], g->pos_lhs_ids[1]); - std::swap (g->pos_lhs_ids[2], g->pos_lhs_ids[3]); - const int8_t flag = g->degenerated_ite; - const int8_t plus_then = flag & NO_PLUS_THEN; - const int8_t neg_then = flag & NO_NEG_THEN; - const int8_t plus_else = flag & NO_PLUS_ELSE; - const int8_t neg_else = flag & NO_NEG_ELSE; - g->degenerated_ite = (plus_then ? Special_ITE_GATE::NO_NEG_THEN - : Special_ITE_GATE::NORMAL) | - (neg_then ? Special_ITE_GATE::NO_PLUS_THEN - : Special_ITE_GATE::NORMAL) | - (plus_else ? Special_ITE_GATE::NO_NEG_ELSE - : Special_ITE_GATE::NORMAL) | - (neg_else ? Special_ITE_GATE::NO_PLUS_ELSE - : Special_ITE_GATE::NORMAL); - CADICAL_assert (g->pos_lhs_ids[0].current_lit == rhs[1]); - CADICAL_assert (g->pos_lhs_ids[2].current_lit == rhs[2]); - // incorrect as we have not negated the LHS yet! - // check_correct_ite_flags (g); - } - - LOG (g->rhs, "g/RHS = "); - return true; -} - -#ifndef CADICAL_NDEBUG -bool is_tautological_ite_gate (Gate *g) { - CADICAL_assert (g->tag == Gate_Type::ITE_Gate); - CADICAL_assert (g->rhs.size () == 3); - const int cond_lit = g->rhs[0]; - const int then_lit = g->rhs[1]; - const int else_lit = g->rhs[2]; - return cond_lit == then_lit || cond_lit == else_lit; -} -#endif - -Gate *Closure::find_ite_gate (Gate *g, bool &negate_lhs) { - negate_lhs = normalize_ite_lits_gate (g); - LOG (g, "post normalize"); - return find_gate_lits (g->rhs, Gate_Type::ITE_Gate, g); -} - -LRAT_ID Closure::check_and_add_to_proof_chain (vector &clause) { - internal->external->check_learned_clause (); - const LRAT_ID id = ++internal->clause_id; - if (internal->proof) { - if (internal->lrat) { - CADICAL_assert (internal->lrat_chain.empty ()); - CADICAL_assert (lrat_chain.size () >= 1); - } - internal->proof->add_derived_clause (id, true, clause, lrat_chain); - lrat_chain.clear (); - } - return id; -} - -void Closure::add_clause_to_chain (std::vector unsimplified, - LRAT_ID id) { - const uint32_t id2_higher = (id >> 32); - const uint32_t id2_lower = (uint32_t) (id & (LRAT_ID) (uint32_t) (-1)); - CADICAL_assert (id == ((LRAT_ID) id2_higher << 32) + (LRAT_ID) id2_lower); - chain.push_back (id2_higher); - chain.push_back (id2_lower); - LOG (unsimplified, "pushing to chain"); - chain.insert (end (chain), begin (unsimplified), end (unsimplified)); - chain.push_back (0); -} - -LRAT_ID Closure::simplify_and_add_to_proof_chain (vector &unsimplified, - LRAT_ID delete_id) { - vector &clause = internal->clause; - CADICAL_assert (clause.empty ()); -#ifndef CADICAL_NDEBUG - for (auto lit : unsimplified) { - CADICAL_assert (!(marked (lit) & 4)); - } -#endif - - bool trivial = false; - for (auto lit : unsimplified) { - signed char &lit_mark = marked (lit); - if (lit_mark & 4) - continue; - signed char ¬_lit_mark = marked (-lit); - if (not_lit_mark & 4) { - trivial = true; - break; - } - lit_mark |= 4; - clause.push_back (lit); - } - for (auto lit : clause) { - signed char &mark = marked (lit); - CADICAL_assert (mark & 4); - mark &= ~4u; - } - - LRAT_ID id = 0; - if (!trivial) { - if (delete_id) { - if (internal->proof) { - internal->proof->delete_clause (delete_id, true, clause); - lrat_chain.clear (); - } - } else { - id = check_and_add_to_proof_chain (clause); - add_clause_to_chain (clause, id); - } - } else { - LOG ("skipping trivial proof"); - lrat_chain.clear (); - } - clause.clear (); - return id; -} -/*------------------------------------------------------------------------*/ -void Closure::add_ite_turned_and_binary_clauses (Gate *g) { - if (!internal->proof) - return; - if (internal->lrat) - return; - LOG ("starting ITE turned AND supporting binary clauses"); - CADICAL_assert (unsimplified.empty ()); - CADICAL_assert (chain.empty ()); - int not_lhs = -g->lhs; - unsimplified.push_back (not_lhs); - unsimplified.push_back (g->rhs[0]); - simplify_and_add_to_proof_chain (unsimplified); - unsimplified.pop_back (); - unsimplified.push_back (g->rhs[1]); - simplify_and_add_to_proof_chain (unsimplified); - unsimplified.clear (); -} -void Closure::simplify_unit_xor_lrat_clauses ( - const vector &source, int lhs) { - CADICAL_assert (internal->lrat); - for (auto pair : source) { - compute_rewritten_clause_lrat_simple (pair.clause, lhs); - if (lrat_chain.size ()) - break; - } - CADICAL_assert (clause.size () == 1); -} -void Closure::simplify_and_sort_xor_lrat_clauses ( - const vector &source, vector &target, - int lhs, int except2, bool flip) { - CADICAL_assert (internal->lrat); - for (auto pair : source) { - Clause *c = produce_rewritten_clause_lrat (pair.clause, lhs); - if (c) { - target.push_back (LitClausePair (0, c)); - } - } - gate_sort_lrat_reasons (target, lhs, except2, flip); -} -void Closure::add_xor_matching_proof_chain ( - Gate *g, int lhs1, const vector &clauses2, int lhs2, - vector &to_lrat, vector &back_lrat) { - if (lhs1 == lhs2) - return; - if (!internal->proof) - return; - CADICAL_assert (unsimplified.empty ()); - unsimplified = g->rhs; - vector first; - vector second; - if (internal->lrat) { - simplify_and_sort_xor_lrat_clauses (g->pos_lhs_ids, first, lhs1); - simplify_and_sort_xor_lrat_clauses (clauses2, second, lhs2, 0, 1); - g->pos_lhs_ids = first; - } - LOG ("starting XOR matching proof"); - // for lrat - vector first_ids; - vector second_ids; - for (auto pair : first) { - bool first = pair.current_lit & 1; - int rest = pair.current_lit >> 1; - rest &= ~(1 << (g->rhs.size () - 1)); - if (first == (lhs1 > 0)) { - first_ids.push_back (LitIdPair (rest, pair.clause->id)); - } else { - second_ids.push_back (LitIdPair (rest, pair.clause->id)); - } - LOG (pair.clause, "key %d", pair.current_lit); - } - for (auto pair : second) { - bool first = pair.current_lit & 1; - int rest = pair.current_lit >> 1; - rest &= ~(1 << (g->rhs.size () - 1)); - if (first == (lhs2 < 0)) { - first_ids.push_back (LitIdPair (rest, pair.clause->id)); - } else { - second_ids.push_back (LitIdPair (rest, pair.clause->id)); - } - LOG (pair.clause, "key %d", pair.current_lit); - } - // TODO Florian: resort and ids after every round - do { - vector first_tmp; - vector second_tmp; - CADICAL_assert (!unsimplified.empty ()); - unsimplified.pop_back (); - const size_t size = unsimplified.size (); - CADICAL_assert (size < 32); - const size_t off = 1u << size; - for (size_t i = 0; i != off; ++i) { - int32_t n = 0; - if (internal->lrat) { - n = number_from_xor_reason_reversed (unsimplified); - CADICAL_assert (lrat_chain.empty ()); - for (auto pair : first_ids) { - if (pair.lit == n) - lrat_chain.push_back (pair.id); - } - CADICAL_assert (lrat_chain.size () == 2); - } - unsimplified.push_back (-lhs1); - unsimplified.push_back (lhs2); - const LRAT_ID id1 = simplify_and_add_to_proof_chain (unsimplified); - unsimplified.resize (unsimplified.size () - 2); - if (internal->lrat) { - int32_t rest = n &= ~(1 << (unsimplified.size () - 1)); - first_tmp.push_back (LitIdPair (rest, id1)); - n = number_from_xor_reason_reversed (unsimplified); - lrat_chain.clear (); - for (auto pair : second_ids) { - if (pair.lit == n) - lrat_chain.push_back (pair.id); - } - CADICAL_assert (lrat_chain.size () == 2); - } - unsimplified.push_back (lhs1); - unsimplified.push_back (-lhs2); - const LRAT_ID id2 = simplify_and_add_to_proof_chain (unsimplified); - unsimplified.resize (unsimplified.size () - 2); - if (internal->lrat) { - lrat_chain.clear (); - int32_t rest = n &= ~(1 << (unsimplified.size () - 1)); - second_tmp.push_back (LitIdPair (rest, id2)); - } - inc_lits (unsimplified); - } - if (internal->lrat) { - first_ids.swap (first_tmp); - second_ids.swap (second_tmp); - } - } while (!unsimplified.empty ()); - if (internal->lrat) { - CADICAL_assert (first_ids.size () == 1); - CADICAL_assert (second_ids.size () == 1); - to_lrat.push_back (first_ids.back ().id); - back_lrat.push_back (second_ids.back ().id); - } - CADICAL_assert (!internal->lrat || to_lrat.size () == 1); - CADICAL_assert (!internal->lrat || back_lrat.size () == 1); - LOG ("finished XOR matching proof"); - CADICAL_assert (unsimplified.empty ()); -} - -// this function needs to either put the clauses from -// lrat_chain_and_gate into g->pos_neg_ids or clear it or do something with -// it if you merge gates. -Gate *Closure::new_xor_gate (const vector &glauses, - int lhs) { - rhs.clear (); - - for (auto lit : lits) { - if (lhs != lit && -lhs != lit) { - CADICAL_assert (lit > 0); - rhs.push_back (lit); - } - } - CADICAL_assert (rhs.size () + 1 == lits.size ()); - sort_literals_by_var (rhs); - Gate *g = find_xor_lits (this->rhs); - if (g) { - check_xor_gate_implied (g); - std::vector reasons_implication, reasons_back; - add_xor_matching_proof_chain (g, g->lhs, glauses, lhs, - reasons_implication, reasons_back); - if (merge_literals_lrat (g->lhs, lhs, reasons_implication, - reasons_back)) { - ++internal->stats.congruence.xors; - } - delete_proof_chain (); - CADICAL_assert (internal->unsat || chain.empty ()); - } else { - g = new Gate; - g->lhs = lhs; - g->tag = Gate_Type::XOr_Gate; - g->rhs = {rhs}; - g->garbage = false; - g->indexed = true; - g->shrunken = false; - g->hash = hash_lits (nonces, g->rhs); - for (auto pair : glauses) - g->pos_lhs_ids.push_back (pair); - table.insert (g); - ++internal->stats.congruence.gates; -#ifdef LOGGING - g->id = fresh_id++; -#endif - LOG (g, "creating new"); - check_xor_gate_implied (g); - for (auto lit : g->rhs) { - connect_goccs (g, lit); - } - } - return g; -} -uint32_t -Closure::number_from_xor_reason_reversed (const std::vector &rhs) { - uint32_t n = 0; - CADICAL_assert (is_sorted (rhs.rbegin (), rhs.rend (), - sort_literals_by_var_smaller_except (internal, 0, 0))); - CADICAL_assert (rhs.size () <= 32); - for (auto r = rhs.rbegin (); r != rhs.rend (); r++) { - int lit = *r; - n *= 2; - n += !(lit > 0); - } - return n; -} - -uint32_t Closure::number_from_xor_reason (const std::vector &rhs, - int lhs, int except, bool flip) { - uint32_t n = 0; - CADICAL_assert (is_sorted ( - begin (rhs), end (rhs), - sort_literals_by_var_smaller_except (internal, lhs, except))); - (void) lhs, (void) except; - CADICAL_assert (rhs.size () <= 32); - for (auto lit : rhs) { - n *= 2; - n += !(lit > 0) ^ flip; - flip = 0; - } - return n; -} - -// this is how I planned to sort it and produce the number -// Look at this first -void Closure::gate_sort_lrat_reasons (LitClausePair &litId, int lhs, - int except2, bool flip) { - CADICAL_assert (clause.empty ()); - std::copy (begin (*litId.clause), end (*litId.clause), - back_inserter (clause)); - sort_literals_by_var_except (clause, lhs, except2); - litId.current_lit = number_from_xor_reason (clause, lhs, except2, flip); - clause.clear (); -} - -struct smaller_pair_first_rank { - typedef size_t Type; - Type operator() (const LitClausePair &a) { return a.current_lit; } -}; - -// this is how I planned to sort it and produce the number -// Look at this first -void Closure::gate_sort_lrat_reasons (std::vector &xs, - int lhs, int except2, bool flip) { - CADICAL_assert (clause.empty ()); - CADICAL_assert (!xs.empty ()); - for (auto &litId : xs) { - gate_sort_lrat_reasons (litId, lhs, except2, flip); - } - - rsort (begin (xs), end (xs), smaller_pair_first_rank ()); - -#ifndef CADICAL_NDEBUG - std::for_each (begin (xs), end (xs), [&xs] (const LitClausePair &x) { - CADICAL_assert (x.clause->size == xs[1].clause->size); - }); -#endif -} - -void Closure::init_xor_gate_extraction (std::vector &candidates) { - const unsigned arity_limit = internal->opts.congruencexorarity; - CADICAL_assert (arity_limit < 32); // we use unsigned int. - const unsigned size_limit = arity_limit + 1; - glargecounts.resize (2 * internal->vsize, 0); - - for (auto c : internal->clauses) { - LOG (c, "considering clause for XOR"); - if (c->redundant) - continue; - if (c->garbage) - continue; - if (c->size < 3) - continue; - unsigned size = 0; - for (auto lit : *c) { - const signed char v = internal->val (lit); - if (v < 0) - continue; - if (v > 0) { - LOG (c, "satisfied by %d", lit); - internal->mark_garbage (c); - goto CONTINUE_COUNTING_NEXT_CLAUSE; - } - if (size == size_limit) - goto CONTINUE_COUNTING_NEXT_CLAUSE; - ++size; - } - - if (size < 3) - continue; - for (auto lit : *c) { - if (internal->val (lit)) - continue; - ++largecounts (lit); - } - - LOG (c, "considering clause for XOR as candidate"); - candidates.push_back (c); - CONTINUE_COUNTING_NEXT_CLAUSE:; - } - - LOG ("considering %zd out of %zd", candidates.size (), - internal->irredundant ()); - const unsigned rounds = internal->opts.congruencexorcounts; -#ifdef LOGGING - const size_t original_size = candidates.size (); -#endif - LOG ("resizing glargecounts to size %zd", glargecounts.size ()); - for (unsigned round = 0; round < rounds; ++round) { - LOG ("round %d of XOR extraction", round); - size_t removed = 0; - gnew_largecounts.resize (2 * internal->vsize); - unsigned cand_size = candidates.size (); - size_t j = 0; - for (size_t i = 0; i < cand_size; ++i) { - Clause *c = candidates[i]; - LOG (c, "considering"); - unsigned size = 0; - for (auto lit : *c) { - if (!internal->val (lit)) - ++size; - } - CADICAL_assert (3 <= size); - CADICAL_assert (size <= size_limit); - const unsigned arity = size - 1; - const unsigned needed_clauses = 1u << (arity - 1); - for (auto lit : *c) { - if (largecounts (lit) < needed_clauses) { - LOG (c, "not enough occurrences, so ignoring"); - removed++; - goto CONTINUE_WITH_NEXT_CANDIDATE_CLAUSE; - } - } - for (auto lit : *c) - if (!internal->val (lit)) - new_largecounts (lit)++; - candidates[j++] = candidates[i]; - - CONTINUE_WITH_NEXT_CANDIDATE_CLAUSE:; - } - candidates.resize (j); - glargecounts = std::move (gnew_largecounts); - gnew_largecounts.clear (); - LOG ("moving counts %zd", glargecounts.size ()); - if (!removed) - break; - - LOG ("after round %d, %zd (%ld %%) remain", round, candidates.size (), - candidates.size () / (1 + original_size) * 100); - } - - for (auto c : candidates) { - for (auto lit : *c) - internal->occs (lit).push_back (c); - } -} - -Clause *Closure::find_large_xor_side_clause (std::vector &lits) { - unsigned least_occurring_literal = 0; - unsigned count_least_occurring = UINT_MAX; - const size_t size_lits = lits.size (); -#if defined(LOGGING) || !defined(CADICAL_NDEBUG) - const unsigned arity = size_lits - 1; -#endif -#ifndef CADICAL_NDEBUG - const unsigned count_limit = 1u << (arity - 1); -#endif - LOG (lits, "trying to find arity %u XOR side clause", arity); - for (auto lit : lits) { - CADICAL_assert (!internal->val (lit)); - marked (lit) = 1; - unsigned count = largecount (lit); - CADICAL_assert (count_limit <= count); - if (count >= count_least_occurring) - continue; - count_least_occurring = count; - least_occurring_literal = lit; - } - Clause *res = 0; - CADICAL_assert (least_occurring_literal); - LOG ("searching XOR side clause watched by %d#%u", - least_occurring_literal, count_least_occurring); - LOG ("searching for size %ld", size_lits); - for (auto c : internal->occs (least_occurring_literal)) { - LOG (c, "checking"); - CADICAL_assert (c->size != 2); // TODO kissat has break - if (c->garbage) - continue; - if ((size_t) c->size < size_lits) - continue; - size_t found = 0; - for (auto other : *c) { - const signed char value = internal->val (other); - if (value < 0) - continue; - if (value > 0) { - LOG (c, "found satisfied %d in", other); - internal->mark_garbage (c); - CADICAL_assert (c->garbage); - break; - } - if (marked (other)) - found++; - else { - LOG ("not marked %d", other); - found = 0; - break; - } - } - if (found == size_lits && !c->garbage) { - res = c; - break; - } else { - LOG ("too few literals"); - } - } - for (auto lit : lits) - marked (lit) = 0; - if (res) - LOG (res, "found matching XOR side"); - else - LOG ("no matching XOR side clause found"); - return res; -} - -void Closure::extract_xor_gates_with_base_clause (Clause *c) { - LOG (c, "checking clause"); - lits.clear (); - int smallest = 0; - int largest = 0; - const unsigned arity_limit = internal->opts.congruencexorarity; - const unsigned size_limit = arity_limit + 1; - unsigned negated = 0, size = 0; - bool first = true; - for (auto lit : *c) { - const signed char v = internal->val (lit); - if (v < 0) - continue; - if (v > 0) { - internal->mark_garbage (c); - return; - } - if (size == size_limit) { - LOG (c, "size limit reached"); - return; - } - - if (first) { - largest = smallest = lit; - first = false; - } else { - CADICAL_assert (smallest); - CADICAL_assert (largest); - if (internal->vlit (lit) < internal->vlit (smallest)) { - LOG ("new smallest %d", lit); - smallest = lit; - } - if (internal->vlit (lit) > internal->vlit (largest)) { - if (largest < 0) { - LOG (c, "not largest %d (largest: %d) occurs negated in XOR base", - lit, largest); - return; - } - largest = lit; - } - } - if (lit < 0 && internal->vlit (lit) < internal->vlit (largest)) { - LOG (c, "negated literal %d not largest in XOR base", lit); - return; - } - if (lit < 0 && negated++) { - LOG (c, "more than one negated literal in XOR base"); - return; - } - lits.push_back (lit); - ++size; - } - CADICAL_assert (size == lits.size ()); - if (size < 3) { - LOG (c, "short XOR base clause"); - return; - } - - LOG ("double checking if possible"); - const unsigned arity = size - 1; - const unsigned needed_clauses = 1u << (arity - 1); - for (auto lit : lits) { - for (int sign = 0; sign != 2; ++sign, lit = -lit) { - unsigned count = largecount (lit); - if (count >= needed_clauses) - continue; - LOG (c, - "literal %d in XOR base clause only occurs %u times in large " - "clause thus skipping", - lit, count); - return; - } - } - - LOG ("checking for XOR side clauses"); - CADICAL_assert (smallest && largest); - const unsigned end = 1u << arity; - CADICAL_assert (negated == parity_lits (lits)); - unsigned found = 0; - vector glauses; - glauses.push_back (LitClausePair (0, c)); - for (unsigned i = 0; i != end; ++i) { - while (i && parity_lits (lits) != negated) - inc_lits (lits); - if (i) { - // the clause must be stored - // you can use `lrat_chain_and_gate` for this - Clause *d = find_large_xor_side_clause (lits); - if (!d) - return; - CADICAL_assert (!d->redundant); - glauses.push_back (LitClausePair (i, d)); - } else - CADICAL_assert (!c->redundant); - inc_lits (lits); - ++found; - } - - while (parity_lits (lits) != negated) - inc_lits (lits); - LOG (lits, "found all needed %u matching clauses:", found); - CADICAL_assert (found == 1u << arity); - if (negated) { - auto p = begin (lits); - int lit; - while ((lit = *p) > 0) - p++; - LOG ("flipping RHS literal %d", (lit)); - *p = -lit; - } - LOG (lits, "normalized negations"); - unsigned extracted = 0; - for (auto lhs : lits) { - if (!negated) - lhs = -lhs; - Gate *g = new_xor_gate (glauses, lhs); - if (g) - extracted++; - if (internal->unsat) - break; - } - if (!extracted) - LOG ("no arity %u XOR gate extracted", arity); -} -void Closure::extract_xor_gates () { - CADICAL_assert (!full_watching); - if (!internal->opts.congruencexor) - return; - START (extractxors); - LOG ("starting extracting XOR"); - std::vector candidates = {}; - init_xor_gate_extraction (candidates); - for (auto c : candidates) { - if (internal->unsat) - break; - if (c->garbage) - continue; - extract_xor_gates_with_base_clause (c); - } - reset_xor_gate_extraction (); - STOP (extractxors); -} - -/*------------------------------------------------------------------------*/ -void Closure::find_units () { - size_t units = 0; - for (auto v : internal->vars) { - RESTART: - if (!internal->flags (v).active ()) - continue; - for (int sgn = -1; sgn < 1; sgn += 2) { - int lit = v * sgn; - for (auto w : internal->watches (lit)) { - if (!w.binary ()) - continue; // todo check that binaries first - const int other = w.blit; - if (marked (-other)) { - LOG (w.clause, "binary clause %d %d and %d %d give unit %d", lit, - other, lit, -other, lit); - ++units; - if (internal->lrat) { - lrat_chain.push_back (w.clause->id); - lrat_chain.push_back (marked_mu1 (-other).clause->id); - } - bool failed = !learn_congruence_unit (lit); - unmark_all (); - if (failed) - return; - else - goto RESTART; - } - if (marked (other)) - continue; - marked (other) = 1; - set_mu1_reason (other, w.clause); - internal->analyzed.push_back (other); - } - unmark_all (); - } - CADICAL_assert (internal->analyzed.empty ()); - } - LOG ("found %zd units", units); -} - -void Closure::find_equivalences () { - CADICAL_assert (!internal->unsat); - - for (auto v : internal->vars) { - RESTART: - if (!internal->flags (v).active ()) - continue; - int lit = v; - for (auto w : internal->watches (lit)) { - if (!w.binary ()) - break; - CADICAL_assert (w.size == 2); - const int other = w.blit; - if (internal->vlit (lit) > internal->vlit (other)) - continue; - if (marked (other)) - continue; - internal->analyzed.push_back (other); - marked (other) = true; - set_mu1_reason (other, w.clause); - } - - if (internal->analyzed.empty ()) - continue; - - for (auto w : internal->watches (-lit)) { - if (!w.binary ()) - break; // binary clauses are first - const int other = w.blit; - if (internal->vlit (-lit) > internal->vlit (other)) - continue; - CADICAL_assert (-lit != other); - LOG ("binary clause %d %d", -lit, other); - if (marked (-other)) { - int lit_repr = find_representative (lit); - int other_repr = find_representative (other); - LOG ("found equivalence %d %d with %d and %d as the representative", - lit, other, lit_repr, other_repr); - if (lit_repr != other_repr) { - // if (internal->lrat) { - // // This cannot work - // // if you have 2 = 1 and 3=4 - // // you cannot add 2=3. You really to connect the - // representatives directly - // // therefore you actually need to learn the clauses 2->3->4 - // and -2->1 and vice-versa eager_representative_id (other) = - // marked_mu1 (-other).clause->id; eager_representative_id - // (-other) = w.clause->id; CADICAL_assert (eager_representative_id - // (other) != -1); LOG ("lrat: %d (%zd) %d (%zd)", other, - // eager_representative_id (other), -other, - // eager_representative_id (-other)); - // } - promote_clause (marked_mu1 (-other).clause); - promote_clause (w.clause); - LOG (w.clause, "merging"); - LOG (marked_mu1 (-other).clause, "with"); - if (merge_literals_equivalence ( - lit, other, - internal->lrat ? marked_mu1 (-other).clause : nullptr, - w.clause)) { - ++internal->stats.congruence.congruent; - } - unmark_all (); - if (internal->unsat) - return; - else - goto RESTART; - } - } - } - unmark_all (); - } - CADICAL_assert (internal->analyzed.empty ()); - LOG ("found %zd equivalences", schedule.size ()); -} - -/*------------------------------------------------------------------------*/ -// Initialization - -void Closure::rewrite_and_gate (Gate *g, int dst, int src, LRAT_ID id1, - LRAT_ID id2) { - if (skip_and_gate (g)) - return; - if (!gate_contains (g, src)) - return; - if (internal->val (src)) { - // In essence the code below does the same thing as simplify_and_gate - // but the necessary LRAT chain are different. - simplify_and_gate (g); - return; - } - CADICAL_assert (src); - CADICAL_assert (dst); - CADICAL_assert (internal->val (src) == internal->val (dst)); - GatesTable::iterator git = (g->indexed ? table.find (g) : end (table)); - LOG (g, "rewriting %d into %d in", src, dst); - int clashing = 0, falsifies = 0; - unsigned dst_count = 0, not_dst_count = 0; - auto q = begin (g->rhs); - for (int &lit : g->rhs) { - if (lit == src) - lit = dst; - if (lit == -g->lhs) { - LOG ("found negated LHS literal %d", lit); - clashing = lit; - g->degenerated_and_neg = true; - break; - } - if (lit == g->lhs) - g->degenerated_and_pos = true; - const signed char val = internal->val (lit); - if (val > 0) { - continue; - } - if (val < 0) { - LOG ("found falsifying literal %d", (lit)); - falsifies = lit; - break; - } - if (lit == dst) { - if (not_dst_count) { - LOG ("clashing literals %d and %d", (-dst), (dst)); - clashing = -dst; - break; - } - if (dst_count++) - continue; - } - if (lit == -dst) { - if (dst_count) { - CADICAL_assert (!not_dst_count); - LOG ("clashing literals %d and %d", (dst), (-dst)); - clashing = -dst; - break; - } - CADICAL_assert (!not_dst_count); - ++not_dst_count; - } - *q++ = lit; - } - LOG (lrat_chain, "lrat chain after rewriting"); - - if (internal->lrat) { // updating reasons in the chain. -#ifdef LOGGING - for (auto litId : g->pos_lhs_ids) { - LOG (litId.clause, "%d ->", litId.current_lit); - } -#endif - // We remove all assigned literals except the falsified literal such - // that we can produce an LRAT chain - size_t i = 0, size = g->pos_lhs_ids.size (); - bool found = false; - CADICAL_assert (!falsifies || !clashing); - const int orig_falsifies = falsifies == dst ? src : falsifies; - const int orig_clashing = - clashing == -dst ? -src : (clashing == dst ? src : clashing); - int keep_clashing = clashing; - LOG ("keeping chain for falsifies: %d aka %d and clashing: %d aka %d", - falsifies, orig_falsifies, clashing, orig_clashing); - for (size_t j = 0; j < size; ++j) { - LOG (g->pos_lhs_ids[j].clause, "looking at %d [%zd %zd] with val %d", - g->pos_lhs_ids[j].current_lit, i, j, - internal->val (g->pos_lhs_ids[i].current_lit)); - g->pos_lhs_ids[i] = g->pos_lhs_ids[j]; - if (keep_clashing && g->pos_lhs_ids[i].current_lit != orig_clashing && - g->pos_lhs_ids[i].current_lit != -orig_clashing && - g->pos_lhs_ids[i].current_lit != keep_clashing && - g->pos_lhs_ids[i].current_lit != -keep_clashing) - continue; - if (internal->val (g->pos_lhs_ids[i].current_lit) && - g->pos_lhs_ids[i].current_lit != src && - g->pos_lhs_ids[i].current_lit != orig_falsifies) - continue; - if (g->pos_lhs_ids[i].current_lit == dst) { - if (!found) - found = true; - else - continue; // we have already one defining clause - } - - LOG ("maybe keeping %d [%zd %zd], src: %d, found: %d", - g->pos_lhs_ids[i].current_lit, i, j, src, found); - if (g->pos_lhs_ids[i].current_lit == src) { - if (!found) - g->pos_lhs_ids[i].current_lit = dst, found = true; - else - continue; // we have already one defining clause - } - LOG ("keeping %d [%zd %zd]", g->pos_lhs_ids[i].current_lit, i, j); - ++i; - } - LOG ("resizing to %zd", i); - CADICAL_assert (i); - g->pos_lhs_ids.resize (i); - } - - if (q != end (g->rhs)) { - g->rhs.resize (q - begin (g->rhs)); - g->shrunken = true; - } - CADICAL_assert (dst_count <= 2); - CADICAL_assert (not_dst_count <= 1); - - std::vector reasons_lrat_src, reasons_lrat_usrc; - shrink_and_gate (g, falsifies, clashing); - LOG (g, "rewritten as"); - CADICAL_assert (!internal->lrat || !g->pos_lhs_ids.empty ()); - // check_and_gate_implied (g); - update_and_gate (g, git, src, dst, id1, id2, falsifies, clashing); - ++internal->stats.congruence.rewritten_ands; -} - -bool Closure::rewrite_gate (Gate *g, int dst, int src, LRAT_ID id1, - LRAT_ID id2) { - switch (g->tag) { - case Gate_Type::And_Gate: - rewrite_and_gate (g, dst, src, id1, id2); - break; - case Gate_Type::XOr_Gate: - rewrite_xor_gate (g, dst, src); - break; - case Gate_Type::ITE_Gate: - rewrite_ite_gate (g, dst, src); - break; - default: - CADICAL_assert (false); - break; - } - CADICAL_assert (internal->unsat || lrat_chain.empty ()); - return !internal->unsat; -} - -bool Closure::rewrite_gates (int dst, int src, LRAT_ID id1, LRAT_ID id2) { - const auto &occs = goccs (src); - for (auto g : occs) { - CADICAL_assert (lrat_chain.empty ()); - if (!rewrite_gate (g, dst, src, id1, id2)) - return false; - else if (!g->garbage && gate_contains (g, dst)) - goccs (dst).push_back (g); - } - goccs (src).clear (); - -#ifndef CADICAL_NDEBUG - for (const auto &occs : gtab) { - for (auto g : occs) { - CADICAL_assert (g); - CADICAL_assert (g->garbage || !gate_contains (g, src)); - } - } -#endif - CADICAL_assert (lrat_chain.empty ()); - return true; -} - -bool Closure::rewriting_lhs (Gate *g, int dst) { - if (dst != g->lhs && dst != -g->lhs) - return false; - mark_garbage (g); - return true; -} - -// update to produce proofs -void Closure::rewrite_xor_gate (Gate *g, int dst, int src) { - if (skip_xor_gate (g)) - return; - if (rewriting_lhs (g, dst)) - return; - if (!gate_contains (g, src)) - return; - LOG (g, "rewriting (%d -> %d)", src, dst); - check_xor_gate_implied (g); - GatesTable::iterator git = (g->indexed ? table.find (g) : end (table)); - size_t j = 0, dst_count = 0; - bool original_dst_negated = (dst < 0); - dst = abs (dst); - unsigned negate = original_dst_negated; - const size_t size = g->rhs.size (); - for (size_t i = 0; i < size; ++i) { - int lit = g->rhs[i]; - CADICAL_assert (lit > 0); - if (lit == src) - lit = dst; - const signed char v = internal->val (lit); - if (v > 0) { - negate ^= true; - } - if (v) - continue; - if (lit == dst) - dst_count++; - LOG ("keeping value %d", lit); - g->rhs[j++] = lit; - } - if (negate) { - LOG ("flipping LHS %d", g->lhs); - g->lhs = -g->lhs; - } - CADICAL_assert (dst_count <= 2); - if (dst_count == 2) { - LOG ("destination found twice, removing"); - size_t k = 0; - for (size_t i = 0; i < j; ++i) { - const int lit = g->rhs[i]; - if (lit != dst) - g->rhs[k++] = g->rhs[i]; - } - CADICAL_assert (k == j - 2); - g->rhs.resize (k); - g->shrunken = true; - CADICAL_assert (is_sorted (begin (g->rhs), end (g->rhs), - sort_literals_by_var_smaller (internal))); - g->hash = hash_lits (nonces, g->rhs); - } else if (j != size) { - g->shrunken = true; - g->rhs.resize (j); - sort_literals_by_var (g->rhs); - g->hash = hash_lits ( - nonces, - g->rhs); // all but one (the dst) is sorted correctly actually - } else { - CADICAL_assert (j == size); - sort_literals_by_var (g->rhs); - } - - CADICAL_assert (clause.empty ()); - // LRAT for add_xor_shrinking_proof_chain - // this should be unnecessary... - // TODO check if really unnecessary - if (dst_count > 1) - add_xor_shrinking_proof_chain (g, dst); - CADICAL_assert (internal->clause.size () <= 1); - update_xor_gate (g, git); - - if (!g->garbage && !internal->unsat && original_dst_negated && - dst_count == 1) { - connect_goccs (g, dst); - } - - check_xor_gate_implied (g); - // TODO stats -} - -// update to produce proofs -void Closure::simplify_xor_gate (Gate *g) { - LOG (g, "simplifying"); - if (skip_xor_gate (g)) - return; - check_xor_gate_implied (g); - unsigned negate = 0; - GatesTable::iterator git = (g->indexed ? table.find (g) : end (table)); - const size_t size = g->rhs.size (); - size_t j = 0; - for (size_t i = 0; i < size; ++i) { - int lit = g->rhs[i]; - CADICAL_assert (lit > 0); - const signed char v = internal->val (lit); - if (v > 0) - negate ^= 1; - if (!v) { - g->rhs[j++] = lit; - } - } - if (negate) { - LOG ("flipping LHS literal %d", (g->lhs)); - g->lhs = -(g->lhs); - } - if (j != size) { - LOG ("shrunken gate"); - g->shrunken = true; - g->rhs.resize (j); - CADICAL_assert (is_sorted (begin (g->rhs), end (g->rhs), - sort_literals_by_var_smaller (internal))); - g->hash = hash_lits (nonces, g->rhs); - } else { - CADICAL_assert (g->hash == hash_lits (nonces, g->rhs)); - } - - check_xor_gate_implied (g); - CADICAL_assert (clause.empty ()); - update_xor_gate (g, git); - LOG (g, "simplified"); - check_xor_gate_implied (g); - internal->stats.congruence.simplified++; - internal->stats.congruence.simplified_xors++; -} - -/*------------------------------------------------------------------------*/ -// propagation of clauses and simplification -void Closure::schedule_literal (int lit) { - const int idx = abs (lit); - if (scheduled[idx]) - return; - scheduled[idx] = true; - schedule.push (lit); - CADICAL_assert (lit != find_representative (lit)); - LOG ("scheduled literal %d", lit); -} - -bool Closure::propagate_unit (int lit) { - LOG ("propagation of congruence unit %d", lit); - if (internal->lrat) - lazy_propagated (lit) = true; - return simplify_gates (lit) && simplify_gates (-lit); -} - -bool Closure::propagate_units () { - while (units != - internal->trail - .size ()) { // units are added during propagation, so reloading - LOG ("propagating %d over gates", internal->trail[units]); - if (!propagate_unit (internal->trail[units++])) - return false; - } - return true; -} - -// The replacement has to be done eagerly, not lazily to make sure that the -// gates are in normalized form. Otherwise, some merges might be missed. -bool Closure::propagate_equivalence (int lit) { - if (internal->val (lit)) - return true; - LOG ("propagating literal %d", lit); - import_lazy_and_find_eager_representative_and_compress_both (lit); - const int repr = find_eager_representative_and_compress (lit); - const LRAT_ID id1 = find_eager_representative_lrat (lit); - const LRAT_ID id2 = find_eager_representative_lrat (-lit); - CADICAL_assert (lrat_chain.empty ()); - return rewrite_gates (repr, lit, id1, id2) && - rewrite_gates (-repr, -lit, id2, id1); -} - -size_t Closure::propagate_units_and_equivalences () { - START (congruencemerge); - size_t propagated = 0; - LOG ("propagating at least %zd units", schedule.size ()); - CADICAL_assert (lrat_chain.empty ()); - while (propagate_units () && !schedule.empty ()) { - CADICAL_assert (!internal->unsat); - CADICAL_assert (lrat_chain.empty ()); - ++propagated; - int lit = schedule.front (); - schedule.pop (); - scheduled[abs (lit)] = false; - if (!propagate_equivalence (lit)) - break; - } - - CADICAL_assert (internal->unsat || schedule.empty ()); - CADICAL_assert (internal->unsat || lrat_chain.empty ()); - - LOG ("propagated %zu congruence units", units); - LOG ("propagated %zu congruence equivalences", propagated); - -#ifndef CADICAL_NDEBUG - if (!internal->unsat) { - for (const auto &occs : gtab) { - for (auto g : occs) { - if (g->garbage) - continue; - CADICAL_assert (g->tag == Gate_Type::ITE_Gate || - g->tag == Gate_Type::XOr_Gate || - !gate_contains (g, -g->lhs)); - // TODO: this would be nice to have! - // CADICAL_assert (g->tag != Gate_Type::ITE_Gate || (g->rhs.size() == 3 - // && g->rhs[1] != -g->lhs && g->rhs[2] != -g->lhs)); - // CADICAL_assert (table.count(g) == 1); - for (auto lit : g->rhs) { - CADICAL_assert (!internal->val (lit)); - CADICAL_assert (representative (lit) == lit); - } - } - } - for (Gate *g : table) { - if (g->garbage) - continue; - if (g->tag == Gate_Type::And_Gate) { - // CADICAL_assert (find_and_lits(g->arity, g->rhs)); - } - } - } -#endif - STOP (congruencemerge); - return propagated; -} - -std::string string_of_gate (Gate_Type t) { - switch (t) { - case Gate_Type::And_Gate: - return "And"; - case Gate_Type::XOr_Gate: - return "XOr"; - case Gate_Type::ITE_Gate: - return "ITE"; - default: - return "buggy"; - } -} - -void Closure::reset_closure () { - scheduled.clear (); - for (Gate *g : table) { - CADICAL_assert (g->indexed); - LOG (g, "deleting"); - if (!g->garbage) - delete g; - } - table.clear (); - - for (auto &occ : gtab) { - occ.clear (); - } - gtab.clear (); - - for (auto gate : garbage) - delete gate; - garbage.clear (); - - if (internal->lrat) { - CADICAL_assert (internal->proof); - for (auto c : extra_clauses) { - CADICAL_assert (!c->garbage); - internal->proof->delete_clause (c); - delete c; - } - extra_clauses.clear (); - } else { - CADICAL_assert (extra_clauses.empty ()); - } -} - -void Closure::reset_extraction () { - full_watching = true; - if (!internal->unsat && !internal->propagate ()) { - internal->learn_empty_clause (); - } - -#if 0 - // remove delete watched clauses from the watch list - for (auto v : internal->vars) { - for (auto sgn = -1; sgn <= 1; sgn += 2) { - const int lit = v * sgn; - auto &watchers = internal->watches (lit); - const size_t size = watchers.size (); - size_t j = 0; - for (size_t i = 0; i != size; ++i) { - const auto w = watchers[i]; - watchers[j] = watchers[i]; - if (!w.clause->garbage) - ++j; - } - watchers.resize(j); - } - } - // watch the remaining non-watched clauses - for (auto c : new_unwatched_binary_clauses) - internal->watch_clause (c); - new_unwatched_binary_clauses.clear(); - for (auto c : internal->clauses) { - if (c->garbage) - continue; - if (c->size != 2) - internal->watch_clause (c); - } -#else // simpler implementation - new_unwatched_binary_clauses.clear (); - internal->clear_watches (); - internal->connect_watches (); -#endif -} - -void Closure::forward_subsume_matching_clauses () { - START (congruencematching); - reset_closure (); - std::vector matchable; - matchable.resize (internal->max_var + 1); - size_t count_matchable = 0; - - for (auto idx : internal->vars) { - if (!internal->flags (idx).active ()) - continue; - const int lit = idx; - const int repr = find_representative (lit); - if (lit == repr) - continue; - const int repr_idx = abs (repr); - if (!matchable[idx]) { - LOG ("matchable %d", idx); - matchable[idx] = true; - count_matchable++; - } - - if (!matchable[repr_idx]) { - LOG ("matchable %d", repr_idx); - matchable[repr_idx] = true; - count_matchable++; - } - } - - LOG ("found %.0f%%", - (double) count_matchable / - (double) (internal->max_var ? internal->max_var : 1)); - std::vector candidates; - auto &analyzed = internal->analyzed; - - for (auto *c : internal->clauses) { - if (c->garbage) - continue; - if (c->redundant) - continue; - if (c->size == 2) - continue; - CADICAL_assert (analyzed.empty ()); - bool contains_matchable = false; - for (auto lit : *c) { - const signed char v = internal->val (lit); - if (v < 0) - continue; - if (v > 0) { - LOG (c, "mark satisfied"); - internal->mark_garbage (c); - break; - } - if (!contains_matchable) { - const int idx = abs (lit); - if (matchable[idx]) - contains_matchable = true; - } - - const int repr = find_representative (lit); - CADICAL_assert (!internal->val (repr)); - if (marked (repr)) - continue; - const int not_repr = -repr; - if (marked (not_repr)) { - LOG (c, "matches both %d and %d", (lit), (not_repr)); - internal->mark_garbage (c); - break; - } - marked (repr) = 1; - analyzed.push_back (repr); - } - - for (auto lit : analyzed) - marked (lit) = 0; - analyzed.clear (); - if (c->garbage) - continue; - if (!contains_matchable) { - LOG ("no matching variable"); - continue; - } - LOG (c, "candidate"); - candidates.push_back (c); - } - - rsort (begin (candidates), end (candidates), smaller_clause_size_rank ()); - size_t tried = 0, subsumed = 0; - internal->init_occs (); - for (auto c : candidates) { - CADICAL_assert (c->size != 2); - // TODO if terminated - ++tried; - if (find_subsuming_clause (c)) { - ++subsumed; - } - } - LOG ("[congruence] subsumed %.0f%%", - (double) subsumed / (double) (tried ? tried : 1)); - STOP (congruencematching); -} - -/*------------------------------------------------------------------------*/ -// Candidate clause 'subsumed' is subsumed by 'subsuming'. We need to copy -// the function because 'congruence' is too early to include the version -// from subsume - -void Closure::subsume_clause (Clause *subsuming, Clause *subsumed) { - // CADICAL_assert (!subsuming->redundant); - // CADICAL_assert (!subsumed->redundant); - auto &stats = internal->stats; - stats.subsumed++; - CADICAL_assert (subsuming->size <= subsumed->size); - LOG (subsumed, "subsumed"); - if (subsumed->redundant) - stats.subred++; - else - stats.subirr++; - if (subsumed->redundant || !subsuming->redundant) { - internal->mark_garbage (subsumed); - return; - } - LOG ("turning redundant subsuming clause into irredundant clause"); - subsuming->redundant = false; - if (internal->proof) - internal->proof->strengthen (subsuming->id); - internal->mark_garbage (subsumed); - stats.current.irredundant++; - stats.added.irredundant++; - stats.irrlits += subsuming->size; - CADICAL_assert (stats.current.redundant > 0); - stats.current.redundant--; - CADICAL_assert (stats.added.redundant > 0); - stats.added.redundant--; - // ... and keep 'stats.added.total'. -} - -bool Closure::find_subsuming_clause (Clause *subsumed) { - CADICAL_assert (!subsumed->garbage); - Clause *subsuming = nullptr; - for (auto lit : *subsumed) { - CADICAL_assert (internal->val (lit) <= 0); - const int repr_lit = find_representative (lit); - const signed char repr_val = internal->val (repr_lit); - CADICAL_assert (repr_val <= 0); - if (repr_val < 0) - continue; - if (marked (repr_lit)) - continue; - CADICAL_assert (!marked (-repr_lit)); - marked (repr_lit) = 1; - } - int least_occuring_lit = 0; - size_t count_least_occurring = INT_MAX; - LOG (subsumed, "trying to forward subsume"); - - for (auto lit : *subsumed) { - const int repr_lit = find_representative (lit); - const size_t count = internal->occs (lit).size (); - CADICAL_assert (count <= UINT_MAX); - if (count < count_least_occurring) { - count_least_occurring = count; - least_occuring_lit = repr_lit; - } - for (auto d : internal->occs (lit)) { - CADICAL_assert (!d->garbage); - CADICAL_assert (subsumed != d); - if (!subsumed->redundant && d->redundant) - continue; - for (auto other : *d) { - const signed char v = internal->val (other); - if (v < 0) - continue; - CADICAL_assert (!v); - const int repr_other = find_representative (other); - if (!marked (repr_other)) - goto CONTINUE_WITH_NEXT_CLAUSE; - LOG ("subsuming due to %d -> %d", other, repr_other); - } - subsuming = d; - goto FOUND_SUBSUMING; - - CONTINUE_WITH_NEXT_CLAUSE:; - } - } - CADICAL_assert (least_occuring_lit); - -FOUND_SUBSUMING: - for (auto lit : *subsumed) { - const int repr_lit = find_representative (lit); - const signed char v = internal->val (lit); - if (!v) - marked (repr_lit) = 0; - } - if (subsuming) { - LOG (subsumed, "subsumed"); - LOG (subsuming, "subsuming"); - subsume_clause (subsuming, subsumed); - ++internal->stats.congruence.subsumed; - return true; - } else { - internal->occs (least_occuring_lit).push_back (subsumed); - return false; - } -} - -/*------------------------------------------------------------------------*/ -static bool skip_ite_gate (Gate *g) { - CADICAL_assert (g->tag == Gate_Type::ITE_Gate); - if (g->garbage) - return true; - return false; -} - -void Closure::produce_ite_merge_then_else_reasons ( - Gate *g, int src, int dst, std::vector &reasons_implication, - std::vector &reasons_back) { - CADICAL_assert (!g->garbage); - if (!internal->lrat) - return; - check_correct_ite_flags (g); - // no merge is happening actually - CADICAL_assert (g->rhs[1] == find_eager_representative(g->rhs[1]) || g->rhs[2] == find_eager_representative(g->rhs[2])); - if (find_eager_representative (g->lhs) == g->rhs[1] || find_eager_representative (g->lhs) == g->rhs[2]) - return; - if ((g->rhs[1] == src && g->lhs == dst && g->rhs[2] == g->lhs) || - (g->rhs[2] == src && g->lhs == dst && g->rhs[1] == g->lhs) || - (g->rhs[1] == -src && g->lhs == -dst && g->rhs[2] == g->lhs) || - (g->rhs[2] == -src && g->lhs == -dst && g->rhs[1] == g->lhs)) - return; - check_ite_lrat_reasons (g, false); - CADICAL_assert (g->rhs.size () == 3); - CADICAL_assert (src == g->rhs[1] || src == g->rhs[2]); - CADICAL_assert (dst == g->rhs[1] || dst == g->rhs[2]); - const int8_t flag = g->degenerated_ite; - CADICAL_assert (!ite_flags_no_then_clauses (flag)); // e = lhs: already merged - CADICAL_assert (!ite_flags_no_else_clauses (flag)); // t = lhs: already merged - produce_rewritten_clause_lrat (g->pos_lhs_ids, g->lhs, false); - if (ite_flags_neg_cond_lhs (flag)) { - LOG ("degenerated case with lhs = -cond"); - LOG (g->pos_lhs_ids[0].clause, "1:"); - LOG (g->pos_lhs_ids[1].clause, "2:"); - reasons_back.push_back (g->pos_lhs_ids[0].clause->id); - reasons_implication.push_back (g->pos_lhs_ids[1].clause->id); - return; - } - if (ite_flags_cond_lhs (flag)) { - LOG ("degenerated case with lhs = cond"); - CADICAL_assert (g->pos_lhs_ids[0].clause); - CADICAL_assert (g->pos_lhs_ids[3].clause); - reasons_back.push_back (g->pos_lhs_ids[3].clause->id); - reasons_implication.push_back (g->pos_lhs_ids[0].clause->id); - return; - } - reasons_implication.push_back (g->pos_lhs_ids[0].clause->id); - reasons_implication.push_back (g->pos_lhs_ids[2].clause->id); - reasons_back.push_back (g->pos_lhs_ids[1].clause->id); - reasons_back.push_back (g->pos_lhs_ids[3].clause->id); -} - -void Closure::rewrite_ite_gate_update_lrat_reasons (Gate *g, int src, - int dst) { - if (!internal->lrat) - return; - LOG (g, "updating lrat from"); - for (auto &litId : g->pos_lhs_ids) { - CADICAL_assert (litId.clause); - if (litId.current_lit == src) - litId.current_lit = dst; - if (litId.current_lit == -src) - litId.current_lit = -dst; - } - check_ite_lrat_reasons (g, false); -} - -bool Closure::rewrite_ite_gate_to_and ( - Gate *g, int src, int dst, size_t idx1, size_t idx2, - int cond_lit_to_learn_if_degenerated) { - CADICAL_assert (internal->lrat_chain.empty ()); - CADICAL_assert (!g->garbage); - LOG (g, "rewriting to proper AND"); - if (internal->val (g->lhs) > 0) { - { - const int lit = g->rhs[0]; - const char v = internal->val (lit); - if (v > 0) { - } else if (!v) { - if (internal->lrat) { - push_id_and_rewriting_lrat_unit (g->pos_lhs_ids[idx1].clause, - Rewrite (), lrat_chain); - } - learn_congruence_unit (cond_lit_to_learn_if_degenerated); - } else { - if (internal->lrat) - push_id_and_rewriting_lrat_unit (g->pos_lhs_ids[idx1].clause, - Rewrite (), lrat_chain); - push_lrat_unit (-lit); - internal->learn_empty_clause (); - return true; - } - } - if (!internal->unsat) { - const int lit = g->rhs[1]; - const char v = internal->val (lit); - CADICAL_assert (dst == g->rhs[0] || dst == g->rhs[1] || -dst == g->rhs[0] || - -dst == g->rhs[1]); - const int other = (dst == g->rhs[0] || dst == g->rhs[1]) - ? dst ^ g->rhs[0] ^ g->rhs[1] - : (-dst) ^ g->rhs[0] ^ g->rhs[1]; - if (v > 0) { - // already set by propagation - return true; - } else if (!v) { - if (internal->lrat) { - push_id_and_rewriting_lrat_unit (g->pos_lhs_ids[idx2].clause, - Rewrite (), lrat_chain); - } - learn_congruence_unit (other); - } else { - if (internal->lrat) { - push_lrat_unit (cond_lit_to_learn_if_degenerated); - push_id_and_rewriting_lrat_unit (g->pos_lhs_ids[idx2].clause, - Rewrite (), lrat_chain); - } - internal->learn_empty_clause (); - return true; - } - } - return true; - } - if (!internal->lrat) - return false; - LOG ("updating flags"); - g->degenerated_and_neg = (g->rhs[1] == -g->lhs || g->rhs[0] == -g->lhs); - g->degenerated_and_pos = (g->rhs[0] == g->lhs || g->rhs[1] == g->lhs); - CADICAL_assert (g->rhs.size () == 3); - CADICAL_assert (g->pos_lhs_ids.size () == 4); - CADICAL_assert (idx1 < g->pos_lhs_ids.size ()); - CADICAL_assert (idx2 < g->pos_lhs_ids.size ()); - int lit = g->pos_lhs_ids[idx2].current_lit, other = g->lhs; - // TODO: remove argument - (void) src; - produce_rewritten_clause_lrat_and_clean (g->pos_lhs_ids, g->lhs, idx1, - idx2, false); - - if ((idx1 == (size_t) -1 || idx2 == (size_t) -1)) { - // degenerated and gate - return false; - } - - CADICAL_assert (idx1 != (size_t) -1); - CADICAL_assert (idx2 != (size_t) -1); - CADICAL_assert (idx1 < g->pos_lhs_ids.size ()); - CADICAL_assert (idx2 < g->pos_lhs_ids.size ()); - Clause *c = g->pos_lhs_ids[idx1].clause; - CADICAL_assert (c->size == 2); - Clause *d = g->pos_lhs_ids[idx2].clause; - CADICAL_assert (c != d); - CADICAL_assert (c); - CADICAL_assert (d); - g->pos_lhs_ids.erase (std::remove_if (begin (g->pos_lhs_ids), - end (g->pos_lhs_ids), - [d] (const LitClausePair &p) { - return p.clause == d || !p.clause; - }), - end (g->pos_lhs_ids)); - CADICAL_assert (g->pos_lhs_ids.size () == 2); - CADICAL_assert (lit); - CADICAL_assert (other); - CADICAL_assert (lit != dst); - CADICAL_assert (other != dst); - CADICAL_assert (lit != other); - lrat_chain.push_back (c->id); - lrat_chain.push_back (d->id); - Clause *e = learn_binary_tmp_or_full_clause (lit, -other); - CADICAL_assert (e); - - auto long_clause = - std::find_if (begin (g->pos_lhs_ids), end (g->pos_lhs_ids), - [] (LitClausePair l) { return l.clause->size == 3; }); - CADICAL_assert (long_clause != end (g->pos_lhs_ids)); - LOG (long_clause->clause, "new long clause"); - g->neg_lhs_ids.push_back (*long_clause); - g->pos_lhs_ids.erase (long_clause); - - CADICAL_assert (g->pos_lhs_ids.size () == 1); - - (void) maybe_promote_tmp_binary_clause (g->pos_lhs_ids[0].clause); - g->pos_lhs_ids.push_back ({lit, e}); -#ifndef CADICAL_NDEBUG - for (auto litId : g->pos_lhs_ids) { - bool found = false; - CADICAL_assert (litId.clause); - for (auto other : *litId.clause) { - found = (find_eager_representative (other) == litId.current_lit); - if (found) - break; - } - CADICAL_assert (found); - } - for (auto id : g->pos_lhs_ids) { - LOG (id.clause, "clause after rewriting:"); - CADICAL_assert (id.clause->size == 2); - } - -#endif - return false; -} - -void Closure::produce_ite_merge_lhs_then_else_reasons ( - Gate *g, std::vector &reasons_implication, - std::vector &reasons_back, std::vector &reasons_unit, - bool rewritting_then, bool &learn_units) { - - const size_t idx1 = rewritting_then ? 0 : 2; - const size_t idx2 = idx1 + 1; - const size_t other_idx1 = rewritting_then ? 2 : 0; - const size_t other_idx2 = other_idx1 + 1; - const int cond_lit = g->rhs[0]; - const int lit_to_merge = g->rhs[rewritting_then ? 2 : 1]; - const int other_lit = g->rhs[rewritting_then ? 1 : 2]; - const int repr_cond_lit = find_eager_representative (g->rhs[0]); - const int repr_lit_to_merge = find_eager_representative (lit_to_merge); - const int repr_other_lit = find_eager_representative (other_lit); - const int repr_lhs = find_eager_representative(g->lhs); - if (!internal->proof) - return; - - - LOG ("cond: %d, merging %d and rewriting to %d", cond_lit, lit_to_merge, - other_lit); - if (internal->lrat) { - CADICAL_assert (internal->lrat); - CADICAL_assert (g->pos_lhs_ids.size () == 4); - - if (repr_lhs == -repr_other_lit) { - LOG ("special case: %s=%s, checking if other: %s %s", LOGLIT (g->lhs), - LOGLIT (-lit_to_merge), LOGLIT (cond_lit), LOGLIT (other_lit)); - CADICAL_assert (repr_lit_to_merge != -repr_lhs); // should have been rewritten before - - if (rewritting_then && repr_cond_lit == repr_lhs) { - LOG ("t=-lhs/c=lhs"); - learn_units = true; - // is a unit - push_id_and_rewriting_lrat_unit (g->pos_lhs_ids[0].clause, - Rewrite (), lrat_chain); - unsimplified.push_back (-cond_lit); - LRAT_ID id_unit = simplify_and_add_to_proof_chain (unsimplified); - reasons_unit = {id_unit}; - // don't bother finding out which one is used - reasons_implication.push_back (id_unit); - g->pos_lhs_ids[3].clause = produce_rewritten_clause_lrat ( - g->pos_lhs_ids[3].clause, g->lhs, false); - CADICAL_assert (g->pos_lhs_ids[3].clause); - reasons_implication.push_back (g->pos_lhs_ids[3].clause->id); - unsimplified.clear (); - return; - } - if (!rewritting_then && repr_cond_lit == repr_lhs) { - LOG ("e=-lhs/c=lhs"); - learn_units = true; - // is a unit - push_id_and_rewriting_lrat_unit (g->pos_lhs_ids[3].clause, - Rewrite (), lrat_chain); - unsimplified.push_back (cond_lit); - LRAT_ID id_unit = simplify_and_add_to_proof_chain (unsimplified); - reasons_unit = {id_unit}; - // don't bother finding out which one is used - reasons_implication.push_back (id_unit); - g->pos_lhs_ids[0].clause = produce_rewritten_clause_lrat ( - g->pos_lhs_ids[0].clause, g->lhs, false); - CADICAL_assert (g->pos_lhs_ids[0].clause); - reasons_implication.push_back (g->pos_lhs_ids[0].clause->id); - unsimplified.clear (); - return; - } - if (!rewritting_then && repr_cond_lit == -repr_lhs) { - LOG ("e=-lhs/c=-lhs"); - learn_units = true; - // TODO: this function does not work to produce units for this case - // c LOG 0 rewriting 4 by 3 in gate[42] (arity: 3) -3 := ITE 3 7 - // ... - // c LOG 0 clause[50] 4 -3 - // c LOG 0 clause[44] 5 3 - // c LOG 0 clause[2] -3 -4 -5 - // the first two are rewriting, but they are not ordered properly - // and we need the '5' clause to come after - push_id_and_rewriting_lrat_unit (g->pos_lhs_ids[2].clause, - Rewrite (), lrat_chain); - unsimplified.push_back (cond_lit); - LRAT_ID id_unit = simplify_and_add_to_proof_chain (unsimplified); - reasons_unit = {id_unit}; - g->pos_lhs_ids[1].clause = produce_rewritten_clause_lrat ( - g->pos_lhs_ids[1].clause, g->lhs, false); - CADICAL_assert (g->pos_lhs_ids[1].clause); - - // don't bother finding out which one is used - reasons_implication.push_back (id_unit); - reasons_implication.push_back (g->pos_lhs_ids[1].clause->id); - unsimplified.clear (); - return; - } - if (rewritting_then && repr_cond_lit == -repr_lhs) { - LOG ("t=-lhs/c=-lhs"); - learn_units = true; - push_id_and_rewriting_lrat_unit (g->pos_lhs_ids[1].clause, - Rewrite (), lrat_chain); - unsimplified.push_back (-cond_lit); - LRAT_ID id_unit = simplify_and_add_to_proof_chain (unsimplified); - reasons_unit = {id_unit}; - g->pos_lhs_ids[2].clause = produce_rewritten_clause_lrat ( - g->pos_lhs_ids[2].clause, g->lhs, false); - CADICAL_assert (g->pos_lhs_ids[2].clause); - - reasons_implication.push_back (id_unit); - reasons_implication.push_back (g->pos_lhs_ids[2].clause->id); - unsimplified.clear (); - return; - } - if (rewritting_then && repr_lit_to_merge == repr_lhs) { - LOG ("t=-lhs/e=lhs from rewriting then"); - learn_units = true; - g->pos_lhs_ids[idx1].clause = produce_rewritten_clause_lrat ( - g->pos_lhs_ids[idx1].clause, g->lhs, false); - g->pos_lhs_ids[idx2].clause = produce_rewritten_clause_lrat ( - g->pos_lhs_ids[idx2].clause, g->lhs, false); - CADICAL_assert (g->pos_lhs_ids[idx1].clause); - CADICAL_assert (g->pos_lhs_ids[idx2].clause); - lrat_chain.push_back (g->pos_lhs_ids[idx1].clause->id); - lrat_chain.push_back (g->pos_lhs_ids[idx2].clause->id); - unsimplified.push_back (-cond_lit); - LRAT_ID id_unit = simplify_and_add_to_proof_chain (unsimplified); - reasons_unit = {id_unit}; - unsimplified.clear (); - - return; - } - if (!rewritting_then && repr_lit_to_merge == repr_lhs) { - LOG ("t=-lhs/e=lhs from rewriting else"); - learn_units = true; - g->pos_lhs_ids[idx1].clause = produce_rewritten_clause_lrat ( - g->pos_lhs_ids[idx1].clause, g->lhs, false); - g->pos_lhs_ids[idx2].clause = produce_rewritten_clause_lrat ( - g->pos_lhs_ids[idx2].clause, g->lhs, false); - CADICAL_assert (g->pos_lhs_ids[idx1].clause); - CADICAL_assert (g->pos_lhs_ids[idx2].clause); - lrat_chain.push_back (g->pos_lhs_ids[idx1].clause->id); - lrat_chain.push_back (g->pos_lhs_ids[idx2].clause->id); - unsimplified.push_back (cond_lit); - LRAT_ID id_unit = simplify_and_add_to_proof_chain (unsimplified); - reasons_unit = {id_unit}; - unsimplified.clear (); - return; - } - - if (other_lit == repr_lhs) { - LOG ("TODO FIX ME t=-lhs/e=lhs"); - learn_units = true; - // in the other direction we are merging a literal with itself - g->pos_lhs_ids[idx1].clause = produce_rewritten_clause_lrat ( - g->pos_lhs_ids[idx1].clause, g->lhs, false); - g->pos_lhs_ids[idx2].clause = produce_rewritten_clause_lrat ( - g->pos_lhs_ids[idx2].clause, g->lhs, false); - CADICAL_assert (g->pos_lhs_ids[idx1].clause); - CADICAL_assert (g->pos_lhs_ids[idx2].clause); - reasons_unit.push_back (g->pos_lhs_ids[idx1].clause->id); - reasons_unit.push_back (g->pos_lhs_ids[idx2].clause->id); - return; - } - // if (other_lit == -g->lhs) { - // CADICAL_assert (false); - // } - // if (other_lit == g->lhs) { - // CADICAL_assert (false); - // } - } - - LOG ("normal path"); - produce_rewritten_clause_lrat (g->pos_lhs_ids, g->lhs, false); - CADICAL_assert (g->pos_lhs_ids.size () == 4); - - reasons_unit.push_back (g->pos_lhs_ids[idx1].clause->id); - reasons_unit.push_back (g->pos_lhs_ids[idx2].clause->id); - - // already merged: only unit is important - if (!rewritting_then && repr_lhs == repr_lit_to_merge) { - return; - } - - reasons_implication.push_back (g->pos_lhs_ids[other_idx1].clause->id); - reasons_implication.push_back (g->pos_lhs_ids[idx1].clause->id); - reasons_implication.push_back (g->pos_lhs_ids[idx2].clause->id); - - reasons_back.push_back (g->pos_lhs_ids[other_idx2].clause->id); - reasons_back.push_back (g->pos_lhs_ids[idx1].clause->id); - reasons_back.push_back (g->pos_lhs_ids[idx2].clause->id); - } else { - LOG ("learn extra clauses XXXXXXXXXXXXXXXXXXXXXXXXX"); - const int lhs = g->lhs; - const int cond = g->rhs[0]; - if (rewritting_then) { - unsimplified.push_back (-cond); - unsimplified.push_back (lhs); - simplify_and_add_to_proof_chain (unsimplified); - unsimplified.push_back (-cond); - unsimplified.push_back (-lhs); - simplify_and_add_to_proof_chain (unsimplified); - } else { - unsimplified.push_back (cond); - unsimplified.push_back (-lhs); - simplify_and_add_to_proof_chain (unsimplified); - unsimplified.push_back (cond); - unsimplified.push_back (lhs); - simplify_and_add_to_proof_chain (unsimplified); - } - unsimplified.clear (); - } -} - -void Closure::rewrite_ite_gate (Gate *g, int dst, int src) { - CADICAL_assert (unsimplified.empty ()); - if (skip_ite_gate (g)) - return; - if (!gate_contains (g, src)) - return; - LOG (g, "rewriting %d by %d in", src, dst); - CADICAL_assert (!g->shrunken); - CADICAL_assert (g->rhs.size () == 3); - CADICAL_assert (!internal->lrat || g->pos_lhs_ids.size () == 4); - auto &rhs = g->rhs; - const int lhs = g->lhs; - const int cond = g->rhs[0]; - const int then_lit = g->rhs[1]; - const int else_lit = g->rhs[2]; - const int not_lhs = -(lhs); - const int not_dst = -(dst); - const int not_cond = -(cond); - const int not_then_lit = -(then_lit); - const int not_else_lit = -(else_lit); - Gate_Type new_tag = Gate_Type::And_Gate; - - bool garbage = false; - bool shrink = true; - const auto git = g->indexed ? table.find (g) : end (table); - CADICAL_assert (!g->indexed || git != end (table)); - CADICAL_assert (*git == g); - if (internal->val (cond) && internal->val (then_lit) && - internal->val (else_lit)) { // propagation has set all value anyway - LOG (g, "all values are set"); - CADICAL_assert (internal->val (g->lhs)); - garbage = true; - } else if (internal->val (g->lhs) && internal->val (cond)) { - LOG (g, "all values are set 2"); - CADICAL_assert (internal->val (g->lhs)); - garbage = true; - } - // this code is taken one-to-one from kissat - else if (src == cond) { - if (dst == then_lit) { - // then_lit ? then_lit : else_lit - // then_lit & then_lit | !then_lit & else_lit - // then_lit | !then_lit & else_lit - // then_lit | else_lit - // !(!then_lit & !else_lit) - g->lhs = not_lhs; - rhs[0] = not_then_lit; - rhs[1] = not_else_lit; - if (then_lit == lhs || else_lit == lhs) - garbage = true; - else - garbage = rewrite_ite_gate_to_and (g, src, dst, 1, 3, -dst); - } else if (not_dst == then_lit) { - // !then_lit ? then_lit : else_lit - // !then_lit & then_lit | then_lit & else_lit - // then_lit & else_lit - rhs[0] = else_lit; - CADICAL_assert (rhs[1] == then_lit); - garbage = rewrite_ite_gate_to_and (g, src, dst, 0, 2, -dst); - } else if (dst == else_lit) { - // else_list ? then_lit : else_lit - // else_list & then_lit | !else_list & else_lit - // else_list & then_lit - rhs[0] = else_lit; - CADICAL_assert (rhs[1] == then_lit); - garbage = rewrite_ite_gate_to_and (g, src, dst, 2, 0, dst); - } else if (not_dst == else_lit) { - // !else_list ? then_lit : else_lit - // !else_list & then_lit | else_lit & else_lit - // !else_list & then_lit | else_lit - // then_lit | else_lit - // !(!then_lit & !else_lit) - g->lhs = not_lhs; - rhs[0] = not_then_lit; - rhs[1] = not_else_lit; - if (then_lit == lhs || else_lit == lhs) - garbage = true; - else - garbage = rewrite_ite_gate_to_and (g, src, dst, 3, 1, dst); - } else { - shrink = false; - rhs[0] = dst; - rewrite_ite_gate_update_lrat_reasons (g, src, dst); - } - } else if (src == then_lit) { - if (not_dst == g->lhs) { // TODO not in kissat - rhs[1] = dst; - check_ite_implied (g->lhs, cond, then_lit, else_lit); - std::vector reasons_implication, reasons_back, reasons_unit; - LOG ("%d = %d ?", g->lhs, -g->rhs[0]); - bool learn_units_instead_of_equivalence = false; - produce_ite_merge_lhs_then_else_reasons ( - g, reasons_implication, reasons_back, reasons_unit, true, - learn_units_instead_of_equivalence); - if (learn_units_instead_of_equivalence) { // it is too hard to produce - // LRAT chains - // in this case - - if (internal->lrat) - lrat_chain = reasons_unit; - learn_congruence_unit (-cond, true); - if (-else_lit == lhs) { - if (internal->lrat) - lrat_chain = reasons_implication; - learn_congruence_unit (cond == -lhs ? -else_lit : else_lit, false, true); - } else fully_propagate (); - } else { - if (merge_literals_lrat (g->lhs, else_lit, reasons_implication, - reasons_back)) { - ++internal->stats.congruence.unaries; - ++internal->stats.congruence.unary_ites; - } - if (!internal->unsat) { - if (internal->lrat) - lrat_chain = reasons_unit; - learn_congruence_unit (-cond); - } - } - delete_proof_chain (); - garbage = true; - } else if (dst == cond) { - // cond ? cond : else_lit - // cond & cond | !cond & else_lit - // cond | !cond & else_lit - // cond | else_lit - // !(!cond & !else_lit) - g->lhs = not_lhs; - rhs[0] = not_cond; - rhs[1] = not_else_lit; - if (else_lit == lhs || cond == lhs) - garbage = true; - else - garbage = rewrite_ite_gate_to_and (g, src, dst, 1, 3, -cond); - } else if (not_dst == cond) { - // cond ? !cond : else_lit - // cond & !cond | !cond & else_lit - // !cond & else_lit - rhs[0] = not_cond; - rhs[1] = else_lit; - garbage = rewrite_ite_gate_to_and (g, src, dst, 0, 2, -cond); - } else if (dst == else_lit) { - // cond ? else_lit : else_lit - // else_lit - std::vector reasons_implication, reasons_back; - produce_ite_merge_then_else_reasons (g, src, dst, reasons_implication, - reasons_back); - if (merge_literals_lrat (lhs, else_lit, reasons_implication, - reasons_back)) { - ++internal->stats.congruence.unaries; - ++internal->stats.congruence.unary_ites; - } - delete_proof_chain (); - garbage = true; - } else if (not_dst == else_lit) { - // cond ? !else_lit : else_lit - // cond & !else_lit | !cond & else_lit - // cond ^ else_lit - if (g->lhs == cond) { - produce_rewritten_clause_lrat_and_clean (g->pos_lhs_ids, g->lhs, - false); - if (internal->lrat) { - CADICAL_assert (g->pos_lhs_ids.size () == 2); - lrat_chain.push_back (g->pos_lhs_ids[0].clause->id); - lrat_chain.push_back (g->pos_lhs_ids[1].clause->id); - } - learn_congruence_unit (-else_lit); - garbage = true; - } else { - LOG ("changing to xor"); - new_tag = Gate_Type::XOr_Gate; - CADICAL_assert (rhs[0] == cond); - rhs[1] = else_lit; - CADICAL_assert (!internal->lrat || !g->pos_lhs_ids.empty ()); - { -#ifdef LOGGING - for (auto litId : g->pos_lhs_ids) { - LOG (litId.clause, "%d ->", litId.current_lit); - } -#endif - produce_rewritten_clause_lrat_and_clean (g->pos_lhs_ids, g->lhs, - true); -#ifdef LOGGING - for (auto litId : g->pos_lhs_ids) { - LOG (litId.clause, "%d ->", litId.current_lit); - } -#endif - } - } - } else { - shrink = false; - rhs[1] = dst; - rewrite_ite_gate_update_lrat_reasons (g, src, dst); - } - } else { - CADICAL_assert (src == else_lit); - if (not_dst == g->lhs) { // TODO not in kissat - rhs[2] = dst; - std::vector reasons_implication, reasons_back, reasons_unit; - bool learn_units_instead_of_equivalence = false; - produce_ite_merge_lhs_then_else_reasons ( - g, reasons_implication, reasons_back, reasons_unit, false, - learn_units_instead_of_equivalence); - if (learn_units_instead_of_equivalence) { // Too hard to produce LRAT - if (internal->lrat) - lrat_chain = reasons_unit; - learn_congruence_unit (cond, true); - if (then_lit != lhs) { - LOG ("special case, learning %d",cond == -lhs ? -then_lit : then_lit); - if (internal->lrat) - lrat_chain = reasons_implication; - learn_congruence_unit (cond == -lhs ? -then_lit : then_lit, false, true); - } else fully_propagate (); - } else { - if (merge_literals_lrat (lhs, then_lit, reasons_implication, - reasons_back)) { - ++internal->stats.congruence.unaries; - ++internal->stats.congruence.unary_ites; - } - if (!internal->unsat) { - if (internal->lrat) - lrat_chain = reasons_unit; - learn_congruence_unit (cond); - } - } - delete_proof_chain (); - garbage = true; - } else if (dst == cond) { - // cond ? then_lit : cond - // cond & then_lit | !cond & cond - // cond & then_lit - CADICAL_assert (rhs[0] == cond); - CADICAL_assert (rhs[1] == then_lit); - garbage = rewrite_ite_gate_to_and (g, src, dst, 2, 0, cond); - } else if (not_dst == cond) { - // cond ? then_lit : !cond - // cond & then_lit | !cond & !cond - // cond & then_lit | !cond - // then_lit | !cond - // !(!then_lit & cond) - g->lhs = not_lhs; - CADICAL_assert (rhs[0] == cond); - rhs[1] = not_then_lit; - if (then_lit == lhs || cond == lhs) - garbage = true; - else - garbage = rewrite_ite_gate_to_and (g, src, dst, 3, 1, cond); - } else if (dst == then_lit) { - // cond ? then_lit : then_lit - // then_lit - std::vector reasons_implication, reasons_back; - produce_ite_merge_then_else_reasons (g, src, dst, reasons_implication, - reasons_back); - if (merge_literals_lrat (lhs, then_lit, reasons_implication, - reasons_back)) { - ++internal->stats.congruence.unaries; - ++internal->stats.congruence.unary_ites; - } - garbage = true; - } else if (not_dst == then_lit) { - // cond ? then_lit : !then_lit - // cond & then_lit | !cond & !then_lit - // !(cond ^ then_lit) - if (lhs == cond) { - produce_rewritten_clause_lrat_and_clean (g->pos_lhs_ids, not_lhs, - false); - if (internal->lrat) { - CADICAL_assert (g->pos_lhs_ids.size () == 2); - lrat_chain.push_back (g->pos_lhs_ids[0].clause->id); - lrat_chain.push_back (g->pos_lhs_ids[1].clause->id); - } - learn_congruence_unit (then_lit); - garbage = true; - } else if (not_lhs == cond) { - produce_rewritten_clause_lrat_and_clean (g->pos_lhs_ids, not_lhs, - false); - if (internal->lrat) { - CADICAL_assert (g->pos_lhs_ids.size () == 2); - lrat_chain.push_back (g->pos_lhs_ids[0].clause->id); - lrat_chain.push_back (g->pos_lhs_ids[1].clause->id); - } - learn_congruence_unit (-then_lit); - garbage = true; - } else if (not_lhs == then_lit) { - produce_rewritten_clause_lrat_and_clean (g->pos_lhs_ids, not_lhs, - false); - if (internal->lrat) { - CADICAL_assert (g->pos_lhs_ids.size () == 2); - lrat_chain.push_back (g->pos_lhs_ids[0].clause->id); - lrat_chain.push_back (g->pos_lhs_ids[1].clause->id); - } - learn_congruence_unit (cond); - garbage = true; - } else { - new_tag = Gate_Type::XOr_Gate; - g->lhs = not_lhs; - CADICAL_assert (rhs[0] == cond); - CADICAL_assert (rhs[1] == then_lit); - CADICAL_assert (rhs[0] != g->lhs); - CADICAL_assert (rhs[1] != g->lhs); - produce_rewritten_clause_lrat_and_clean (g->pos_lhs_ids, not_lhs, - false); - } - } else { - shrink = false; - rhs[2] = dst; - rewrite_ite_gate_update_lrat_reasons (g, src, dst); - } - } - if (!garbage && !internal->unsat) { - CADICAL_assert (new_tag != Gate_Type::ITE_Gate || g->lhs != -rhs[1]); - CADICAL_assert (new_tag != Gate_Type::ITE_Gate || g->lhs != -rhs[2]); - if (shrink) { - if (new_tag == Gate_Type::XOr_Gate) { - bool negate_lhs = false; - if (rhs[0] < 0) { - rhs[0] = -rhs[0]; - negate_lhs = !negate_lhs; - } - if (rhs[1] < 0) { - rhs[1] = -rhs[1]; - negate_lhs = !negate_lhs; - } - if (negate_lhs) - g->lhs = -g->lhs; - } - if (internal->vlit (rhs[0]) > - internal->vlit ( - rhs[1])) { // unlike kissat, we need to do it after negating - std::swap (rhs[0], rhs[1]); - CADICAL_assert (new_tag != Gate_Type::ITE_Gate); - } - CADICAL_assert (internal->vlit (rhs[0]) < internal->vlit (rhs[1])); - CADICAL_assert (!g->shrunken); - g->shrunken = true; - rhs[2] = 0; - g->tag = new_tag; - rhs.resize (2); - CADICAL_assert (rhs[0] != -rhs[1]); - if (new_tag == Gate_Type::XOr_Gate) { - if (rhs[0] == -g->lhs || rhs[1] == -g->lhs) { - LOG (g, "special XOR:"); - const int unit = rhs[0] ^ -g->lhs ^ rhs[1]; - produce_rewritten_clause_lrat_and_clean (g->pos_lhs_ids, not_lhs, - false); - if (internal->lrat) { - CADICAL_assert (g->pos_lhs_ids.size () == 2); - lrat_chain.push_back (g->pos_lhs_ids[0].clause->id); - lrat_chain.push_back (g->pos_lhs_ids[1].clause->id); - } - learn_congruence_unit (unit); - garbage = true; - } else if (rhs[0] == g->lhs || rhs[1] == g->lhs) { - LOG (g, "special XOR:"); - const int unit = rhs[0] ^ g->lhs ^ rhs[1]; - produce_rewritten_clause_lrat_and_clean (g->pos_lhs_ids, not_lhs, - false); - if (internal->lrat) { - CADICAL_assert (g->pos_lhs_ids.size () == 2); - lrat_chain.push_back (g->pos_lhs_ids[0].clause->id); - lrat_chain.push_back (g->pos_lhs_ids[1].clause->id); - } - learn_congruence_unit (-unit); - garbage = true; - } else { - int i = 0; - bool negated = false; - for (int j = 0; j < 2; ++i, ++j) { - CADICAL_assert (i <= j); - const int lit = rhs[i] = rhs[j]; - const char v = internal->val (lit); - if (v > 0) { - --i; - negated = !negated; - } else if (v < 0) { - --i; - } - } - CADICAL_assert (i <= 2); - rhs.resize (i); - if (negated) { - g->lhs = -g->lhs; - } - if (i != 2) { - LOG (g, "removed units"); - } - if (!i) - garbage = true; - else if (i == 1) { -#ifdef LOGGING - for (auto litId : g->pos_lhs_ids) { - LOG (litId.clause, "%d ->", litId.current_lit); - } -#endif - produce_rewritten_clause_lrat_and_clean (g->pos_lhs_ids, g->lhs); - CADICAL_assert (!internal->lrat || g->pos_lhs_ids.size () == 2); - Clause *c1 = nullptr, *c2 = nullptr; - if (internal->lrat) { - CADICAL_assert (g->pos_lhs_ids[0].clause); - bool rhs_as_src_first = - g->pos_lhs_ids[0].clause->literals[0] == g->lhs || - g->pos_lhs_ids[0].clause->literals[1] == g->lhs; - c1 = (rhs_as_src_first ? g->pos_lhs_ids[0].clause - : g->pos_lhs_ids[1].clause); - c2 = (rhs_as_src_first ? g->pos_lhs_ids[1].clause - : g->pos_lhs_ids[0].clause); - c1 = maybe_promote_tmp_binary_clause (c1); - c2 = maybe_promote_tmp_binary_clause (c2); - } else { - maybe_add_binary_clause (-g->lhs, g->rhs[0]); - maybe_add_binary_clause (g->lhs, -g->rhs[0]); - } - merge_literals_equivalence (g->lhs, g->rhs[0], c1, c2); - garbage = true; - } - } - if (!garbage) { - CADICAL_assert (rhs[0] != g->lhs); - CADICAL_assert (rhs[1] != g->lhs); - CADICAL_assert (rhs[0] != -g->lhs); - CADICAL_assert (rhs[1] != -g->lhs); - } - } - - if (!garbage) { - g->hash = hash_lits (nonces, g->rhs); - LOG (g, "rewritten"); - - if (internal->lrat) { - if (new_tag == Gate_Type::XOr_Gate) { -#ifndef CADICAL_NDEBUG - std::for_each (begin (g->pos_lhs_ids), end (g->pos_lhs_ids), - [g] (LitClausePair l) { - CADICAL_assert ((size_t) l.clause->size == - 1 + g->arity ()); - }); -#endif - } else if (new_tag == Gate_Type::And_Gate) { - // we have to get rid of one clause, two become binaries, and - // becomes ternary - -#if defined(LOGGING) || !defined(CADICAL_NDEBUG) - for (auto id : g->pos_lhs_ids) { - LOG (id.clause, "clause after rewriting:"); - CADICAL_assert (id.clause->size == 2); - } -#endif - CADICAL_assert (g->pos_lhs_ids.size () == 2 || - gate_contains (g, g->lhs)); - CADICAL_assert (g->neg_lhs_ids.size () == 1 || - gate_contains (g, g->lhs)); - CADICAL_assert (g->arity () == 2); -#ifndef CADICAL_NDEBUG - std::for_each ( - begin (g->pos_lhs_ids), end (g->pos_lhs_ids), - [] (LitClausePair l) { CADICAL_assert (l.clause->size == 2); }); -#endif - } else { - CADICAL_assert (false); -#ifdef WIN32 - __assume(false); -#else - __builtin_unreachable (); -#endif - } - } - Gate *h; - if (new_tag == Gate_Type::And_Gate) { - check_and_gate_implied (g); - h = find_and_lits (rhs); - } else { - CADICAL_assert (new_tag == Gate_Type::XOr_Gate); - check_xor_gate_implied (g); - h = find_xor_gate (g); - } - if (h) { - garbage = true; - if (new_tag == Gate_Type::XOr_Gate) { - std::vector reasons_implication, reasons_back; - add_xor_matching_proof_chain (g, g->lhs, h->pos_lhs_ids, h->lhs, - reasons_implication, - reasons_back); - if (merge_literals_lrat (g->lhs, h->lhs, reasons_implication, - reasons_back)) - ++internal->stats.congruence.xors; - } else { - add_ite_turned_and_binary_clauses (g); - std::vector reasons_implication, reasons_back; - if (internal->lrat) - merge_and_gate_lrat_produce_lrat (g, h, reasons_implication, - reasons_back, false); - if (merge_literals_lrat (g->lhs, h->lhs, reasons_implication, - reasons_back)) - ++internal->stats.congruence.ands; - } - delete_proof_chain (); - } else { - garbage = false; - if (g->indexed) - remove_gate (git); - index_gate (g); - CADICAL_assert (g->arity () == 2); - for (auto lit : g->rhs) - if (lit != dst) - if (lit != cond && lit != then_lit && lit != else_lit) - connect_goccs (g, lit); - if (g->tag == Gate_Type::And_Gate && !internal->lrat) - for (auto lit : g->rhs) - maybe_add_binary_clause (-g->lhs, lit); - } - } - } else { - LOG (g, "rewritten"); - if (internal->lrat) - update_ite_flags (g), check_correct_ite_flags(g); - CADICAL_assert (rhs[0] != rhs[1]); - CADICAL_assert (rhs[0] != rhs[2]); - CADICAL_assert (rhs[1] != rhs[2]); - CADICAL_assert (rhs[0] != -(rhs[1])); - CADICAL_assert (rhs[0] != -(rhs[2])); - CADICAL_assert (rhs[1] != -(rhs[2])); - check_ite_gate_implied (g); - check_ite_lrat_reasons (g, false); - bool negate_lhs; - Gate *h = find_ite_gate (g, negate_lhs); - CADICAL_assert (lhs == g->lhs); - CADICAL_assert (not_lhs == -(g->lhs)); - if (negate_lhs) - g->lhs = -lhs; - check_ite_lrat_reasons (g); - if (internal->lrat) - check_correct_ite_flags (g); - if (h) { - garbage = true; - check_ite_gate_implied (g); - check_ite_lrat_reasons (g, false); - check_ite_gate_implied (h); - check_ite_lrat_reasons (h, false); - int normalized_lhs = negate_lhs ? not_lhs : lhs; - std::vector extra_reasons_lit, extra_reasons_ulit; - add_ite_matching_proof_chain (g, h, normalized_lhs, h->lhs, - extra_reasons_lit, - extra_reasons_ulit); - if (merge_literals_lrat (normalized_lhs, h->lhs, extra_reasons_lit, - extra_reasons_ulit)) - ++internal->stats.congruence.ites; - delete_proof_chain (); - CADICAL_assert (internal->unsat || chain.empty ()); - } else { - garbage = false; - if (g->indexed) - remove_gate (git); - LOG (g, "normalized"); - g->hash = hash_lits (nonces, g->rhs); - index_gate (g); - CADICAL_assert (g->arity () == 3); - for (auto lit : g->rhs) - if (lit != dst) - if (lit != cond && lit != then_lit && lit != else_lit) - connect_goccs (g, lit); - } - } - } - if (garbage && !internal->unsat) - mark_garbage (g); - - CADICAL_assert (chain.empty ()); -} - -void Closure::simplify_ite_gate_produce_unit_lrat (Gate *g, int lit, - size_t idx1, - size_t idx2) { - if (!internal->lrat) - return; - // TODO - if (internal->val (lit) > 0) - return; - CADICAL_assert (internal->lrat); - CADICAL_assert (g); - CADICAL_assert (idx1 < g->pos_lhs_ids.size ()); - CADICAL_assert (idx2 < g->pos_lhs_ids.size ()); - CADICAL_assert (g->pos_lhs_ids.size () == 4); - - CADICAL_assert (idx1 != idx2); - Clause *c = g->pos_lhs_ids[idx1].clause; - Clause *d = g->pos_lhs_ids[idx2].clause; - - if (g->lhs == -g->rhs[0]) { - LOG ("special case of LHS=-cond where only one clause in LRAT is needed is needed"); - size_t idx = (internal->val (g->rhs[1]) < 0 ? idx2 : idx1); - c = produce_rewritten_clause_lrat (g->pos_lhs_ids[idx].clause, g->lhs, false, false); - CADICAL_assert (c); - // not possible to do this in a single lrat chain - push_id_and_rewriting_lrat_unit (c, Rewrite (), lrat_chain, true, - Rewrite (), g->lhs); - CADICAL_assert (d); - return; - } - if (g->lhs == g->rhs[0]) { - LOG ("special case of LHS=cond where only one clause in LRAT is needed is needed"); - size_t idx = (internal->val (g->rhs[1]) > 0 ? idx2 : idx1); - c = produce_rewritten_clause_lrat (g->pos_lhs_ids[idx].clause, g->lhs, false, false); - CADICAL_assert (c); - // not possible to do this in a single lrat chain - push_id_and_rewriting_lrat_unit (c, Rewrite (), lrat_chain, true, - Rewrite (), g->lhs); - CADICAL_assert (d); - return; - } - - c = produce_rewritten_clause_lrat (c, g->lhs, true); - if (c) { - lrat_chain.push_back (c->id); - d = produce_rewritten_clause_lrat (d, g->lhs, true); - if (d) - lrat_chain.push_back (d->id); - } else if (!c) { - push_id_and_rewriting_lrat_unit (d, Rewrite (), lrat_chain, true, - Rewrite (), g->lhs); - CADICAL_assert (d); - lrat_chain.push_back (d->id); - } -} - -// TODO merge -void Closure::merge_and_gate_lrat_produce_lrat ( - Gate *g, Gate *h, std::vector &reasons_lrat_src, - std::vector &reasons_lrat_usrc, bool remove_units) { - CADICAL_assert (internal->lrat); - CADICAL_assert (g->tag == Gate_Type::And_Gate); - CADICAL_assert (h->tag == Gate_Type::And_Gate); - CADICAL_assert (g->neg_lhs_ids.size () <= 1); - update_and_gate_build_lrat_chain (g, h, reasons_lrat_src, - reasons_lrat_usrc, remove_units); -} - -// odd copy of rewrite_ite_gate_lrat_and -bool Closure::simplify_ite_gate_to_and (Gate *g, size_t idx1, size_t idx2, - int removed_lit) { - CADICAL_assert (internal->lrat_chain.empty ()); - CADICAL_assert (g->rhs.size () == 3); -#ifdef LOGGING - for (auto litId : g->pos_lhs_ids) { - LOG (litId.clause, "%d ->", litId.current_lit); - } -#endif - if (g->lhs == -g->rhs[0] || g->lhs == -g->rhs[1]) { - if (internal->lrat) { - Clause *c = g->pos_lhs_ids[idx1].clause; - push_id_and_rewriting_lrat_unit (c, Rewrite (), lrat_chain); - CADICAL_assert (!lrat_chain.empty ()); - } - learn_congruence_unit (-g->lhs); - return true; - } - if (!internal->lrat) - return false; - g->degenerated_and_neg = (g->degenerated_and_neg || g->rhs[1] == -g->lhs || g->rhs[0] == -g->lhs); - g->degenerated_and_pos = (g->degenerated_and_pos || g->rhs[0] == g->lhs || g->rhs[1] == g->lhs); - - CADICAL_assert (g->pos_lhs_ids.size () == 4); - CADICAL_assert (idx1 < g->pos_lhs_ids.size ()); - CADICAL_assert (idx2 < g->pos_lhs_ids.size ()); - int lit = g->pos_lhs_ids[idx2].current_lit, other = g->lhs; - size_t new_idx1 = idx1; - size_t new_idx2 = idx2; - produce_rewritten_clause_lrat_and_clean (g->pos_lhs_ids, g->lhs, new_idx1, - new_idx2); - - if (g->pos_lhs_ids.size () == 1) { - LOG (g, "degenerated AND gate"); - const int replacement_lit = (g->rhs[1] == g->lhs ? g->rhs[0] : g->rhs[1]); - for (auto &litId : g->pos_lhs_ids) { - CADICAL_assert (litId.clause); - LOG (litId.clause, "%d ->", litId.current_lit); - if (litId.current_lit == removed_lit) - litId.current_lit = -replacement_lit; - if (litId.current_lit == -removed_lit) - litId.current_lit = replacement_lit; - LOG (litId.clause, "%d ->", litId.current_lit); - // TODO we need a replacement index - CADICAL_assert (std::find (begin (*litId.clause), end (*litId.clause), litId.current_lit) != - end (*litId.clause)); - CADICAL_assert (std::find (begin (g->rhs), end (g->rhs), litId.current_lit) != - end (g->rhs)); - } - return false; - } - CADICAL_assert (new_idx1 < g->pos_lhs_ids.size ()); - CADICAL_assert (new_idx2 < g->pos_lhs_ids.size ()); - Clause *c = g->pos_lhs_ids[new_idx1].clause; - CADICAL_assert (c->size == 2); - CADICAL_assert (new_idx1 != new_idx2); - Clause *d = g->pos_lhs_ids[new_idx2].clause; - CADICAL_assert (c != d); - CADICAL_assert (c); - CADICAL_assert (d); - g->pos_lhs_ids.erase (std::remove_if (begin (g->pos_lhs_ids), - end (g->pos_lhs_ids), - [d] (const LitClausePair &p) { - return p.clause == d; - }), - end (g->pos_lhs_ids)); - CADICAL_assert (g->pos_lhs_ids.size () == 2); - CADICAL_assert (lit); - CADICAL_assert (other); - CADICAL_assert (lit != other); - lrat_chain.push_back (c->id); - lrat_chain.push_back (d->id); - Clause *e = add_tmp_binary_clause (lit, -other); - - auto long_clause = - std::find_if (begin (g->pos_lhs_ids), end (g->pos_lhs_ids), - [] (LitClausePair l) { return l.clause->size == 3; }); - CADICAL_assert (long_clause != end (g->pos_lhs_ids)); - LOG (long_clause->clause, "new long clause"); - g->neg_lhs_ids.push_back (*long_clause); - g->pos_lhs_ids.erase (long_clause); - CADICAL_assert (g->pos_lhs_ids.size () == 1); - g->pos_lhs_ids.push_back ({lit, e}); - - const int first_lit = g->rhs[0]; - const int second_lit = g->rhs[1]; - for (auto &litId : g->pos_lhs_ids) { - CADICAL_assert (litId.clause); - LOG (litId.clause, "%s ->", LOGLIT (litId.current_lit)); - if (internal->val (litId.current_lit)) { - CADICAL_assert (litId.clause->size == 2); - int replacement_lit = 0; - for (int i = 0; i < 2; ++i) { - if (litId.clause->literals[i] == first_lit) { - replacement_lit = first_lit; - break; - } else if (litId.clause->literals[i] == second_lit) { - replacement_lit = second_lit; - break; - } - } - CADICAL_assert (replacement_lit); - - litId.current_lit = replacement_lit; - } else if (litId.current_lit == removed_lit) - litId.current_lit = -g->rhs[0]; - else if (litId.current_lit == -removed_lit) - litId.current_lit = g->rhs[0]; - LOG (litId.clause, "%d ->", litId.current_lit); - // TODO we need a replacement index - CADICAL_assert (std::find (begin (g->rhs), end (g->rhs), litId.current_lit) != - end (g->rhs)); - CADICAL_assert (std::find (begin (*litId.clause), end (*litId.clause), - litId.current_lit) != end (*litId.clause)); - } - return false; -} - -void Closure::merge_ite_gate_same_then_else_lrat ( - std::vector &clauses, - std::vector &reasons_implication, - std::vector &reasons_back) { - CADICAL_assert (clauses.size () == 4); - produce_rewritten_clause_lrat_and_clean (clauses); - CADICAL_assert (clauses.size () == 4); - auto then_imp = clauses[0]; - auto neg_then_imp = clauses[1]; - auto else_imp = clauses[2]; - auto neg_else_imp = clauses[3]; - reasons_implication.push_back (then_imp.clause->id); - reasons_implication.push_back (else_imp.clause->id); - reasons_back.push_back (neg_then_imp.clause->id); - reasons_back.push_back (neg_else_imp.clause->id); -} - -void Closure::simplify_ite_gate_then_else_set ( - Gate *g, std::vector &reasons_implication, - std::vector &reasons_back, size_t idx1, size_t idx2) { - CADICAL_assert (idx1 < g->pos_lhs_ids.size ()); - CADICAL_assert (idx2 < g->pos_lhs_ids.size ()); - Clause *c = g->pos_lhs_ids[idx1].clause; - Clause *d = g->pos_lhs_ids[idx2].clause; - push_id_and_rewriting_lrat_unit (c, Rewrite (), reasons_back, true, - Rewrite (), g->lhs); - push_id_and_rewriting_lrat_unit (d, Rewrite (), reasons_implication, true, - Rewrite (), g->lhs); - LOG (reasons_back, "LRAT"); - LOG (reasons_implication, "LRAT"); - // c = produce_rewritten_clause_lrat (c, g->lhs, false); - // CADICAL_assert (c); - // d = produce_rewritten_clause_lrat (d, g->lhs, false); - // CADICAL_assert (d); - // const int cond = g->rhs[0]; - // CADICAL_assert (internal->val (cond)); - // reasons_implication.push_back(internal->unit_id (internal->val (cond) > - // 0 ? cond : -cond)); reasons_implication.push_back(c->id); - // reasons_back.push_back(internal->unit_id (internal->val (cond) > 0 ? - // cond : -cond)); reasons_back.push_back(d->id); -} - -void Closure::simplify_ite_gate_condition_set ( - Gate *g, std::vector &reasons_lrat, - std::vector &reasons_back_lrat, size_t idx1, size_t idx2) { - CADICAL_assert (internal->lrat); - Clause *c = g->pos_lhs_ids[idx1].clause; - Clause *d = g->pos_lhs_ids[idx2].clause; -#if defined(LOGGING) || !defined(CADICAL_NDEBUG) - const int cond = g->rhs[0]; - CADICAL_assert (internal->val (cond)); - LOG ("cond = %d", cond); -#endif -#ifdef LOGGING - for (auto litid : g->pos_lhs_ids) - LOG (litid.clause, "clause in gate:"); -#endif - push_id_and_rewriting_lrat_unit (c, Rewrite (), reasons_lrat, true, - Rewrite (), -g->lhs); - push_id_and_rewriting_lrat_unit (d, Rewrite (), reasons_back_lrat, true, - Rewrite (), g->lhs); -} - -void Closure::simplify_ite_gate (Gate *g) { - if (skip_ite_gate (g)) - return; - LOG (g, "simplifying"); - CADICAL_assert (g->arity () == 3); - bool garbage = true; - int lhs = g->lhs; - auto &rhs = g->rhs; - const int cond = rhs[0]; - const int then_lit = rhs[1]; - const int else_lit = rhs[2]; - const signed char v_cond = internal->val (cond); - const signed char v_else = internal->val (else_lit); - const signed char v_then = internal->val (then_lit); - std::vector reasons_lrat, reasons_back_lrat; - if (v_cond && v_else && v_then) { // propagation has set all value anyway - LOG (g, "all values are set"); - CADICAL_assert (internal->val (g->lhs)); - garbage = true; - } else if (v_cond > 0) { - if (internal->lrat) - simplify_ite_gate_condition_set (g, reasons_lrat, reasons_back_lrat, - 0, 1); - if (merge_literals_lrat (lhs, then_lit, reasons_lrat, - reasons_back_lrat)) { - ++internal->stats.congruence.unary_ites; - ++internal->stats.congruence.unaries; - } - } else if (v_cond < 0) { - if (internal->lrat) - simplify_ite_gate_condition_set (g, reasons_lrat, reasons_back_lrat, - 2, 3); - if (merge_literals_lrat (lhs, else_lit, reasons_lrat, - reasons_back_lrat)) { - ++internal->stats.congruence.unary_ites; - ++internal->stats.congruence.unaries; - } - } else { - LOG ("then %d: %d; else %d: %d", then_lit, v_then, else_lit, v_else); - std::vector extra_reasons, extra_reasons_back; - CADICAL_assert (v_then || v_else); - if (v_then > 0 && v_else > 0) { - simplify_ite_gate_produce_unit_lrat (g, lhs, 1, 3); - learn_congruence_unit (lhs); - } else if (v_then < 0 && v_else < 0) { - simplify_ite_gate_produce_unit_lrat (g, -lhs, 0, 2); - learn_congruence_unit (-lhs); - } else if (v_then > 0 && v_else < 0) { - if (internal->lrat) - simplify_ite_gate_then_else_set (g, extra_reasons, - extra_reasons_back, 1, 2); - if (merge_literals_lrat (lhs, cond, extra_reasons, - extra_reasons_back)) { - ++internal->stats.congruence.unary_ites; - ++internal->stats.congruence.unaries; - } - } else if (v_then < 0 && v_else > 0) { - if (internal->lrat) - simplify_ite_gate_then_else_set (g, extra_reasons, - extra_reasons_back, 0, 3); - if (merge_literals_lrat (lhs, -cond, extra_reasons_back, - extra_reasons)) { - ++internal->stats.congruence.unary_ites; - ++internal->stats.congruence.unaries; - } - } else { - CADICAL_assert (!!v_then + !!v_else == 1); - auto git = g->indexed ? table.find (g) : end (table); - CADICAL_assert (!g->indexed || git != end (table)); - if (v_then > 0) { - g->lhs = -lhs; - rhs[0] = -cond; - rhs[1] = -else_lit; - simplify_ite_gate_to_and (g, 1, 3, then_lit); - } else if (v_then < 0) { - rhs[0] = -cond; - rhs[1] = else_lit; - simplify_ite_gate_to_and (g, 0, 2, -then_lit); - } else if (v_else > 0) { - g->lhs = -lhs; - rhs[0] = -then_lit; - rhs[1] = cond; - simplify_ite_gate_to_and (g, 3, 1, else_lit); - } else { - CADICAL_assert (v_else < 0); - rhs[0] = then_lit; - rhs[1] = cond; - simplify_ite_gate_to_and (g, 2, 0, -else_lit); - } - if (internal->unsat) - return; - if (internal->vlit (rhs[0]) > internal->vlit (rhs[1])) - std::swap (rhs[0], rhs[1]); - g->shrunken = true; - g->tag = Gate_Type::And_Gate; - rhs.resize (2); - CADICAL_assert (is_sorted (begin (rhs), end (rhs), - sort_literals_by_var_smaller (internal))); - g->hash = hash_lits (nonces, rhs); - check_and_gate_implied (g); - Gate *h = find_and_lits (rhs); - if (h) { - CADICAL_assert (garbage); - std::vector reasons_lrat, reasons_lrat_back; - if (internal->lrat) - merge_and_gate_lrat_produce_lrat (g, h, reasons_lrat, - reasons_lrat_back, false); - if (merge_literals_lrat (g->lhs, h->lhs, reasons_lrat, - reasons_lrat_back)) { - ++internal->stats.congruence.ites; - } - } else { - remove_gate (git); - index_gate (g); - garbage = false; - g->hash = hash_lits (nonces, g->rhs); - for (auto lit : rhs) - if (lit != cond && lit != then_lit && lit != else_lit) { - connect_goccs (g, lit); - } - - if (rhs[0] == -g->lhs || rhs[1] == -g->lhs) - simplify_and_gate ( - g); // TODO Kissat does not do that, but it has also no - // checks to verify that it cannot happen... - } - } - } - if (garbage && !internal->unsat) - mark_garbage (g); - ++internal->stats.congruence.simplified; - ++internal->stats.congruence.simplified_ites; -} - -void Closure::add_ite_matching_proof_chain ( - Gate *g, Gate *h, int lhs1, int lhs2, std::vector &reasons1, - std::vector &reasons2) { - check_ite_lrat_reasons (g); - check_ite_lrat_reasons (h, false); - CADICAL_assert (g->lhs == lhs1); - CADICAL_assert (h->lhs == lhs2); - if (lhs1 == lhs2) - return; - if (!internal->proof) - return; - LOG (g, "starting ITE matching proof chain"); - LOG (h, "starting ITE matching proof chain with"); - CADICAL_assert (unsimplified.empty ()); - CADICAL_assert (chain.empty ()); - if (internal->lrat) - check_correct_ite_flags (g); - const auto &rhs = g->rhs; - const int8_t flags_g = g->degenerated_ite; - const int8_t flags_h = h->degenerated_ite; - const int cond = rhs[0]; - LRAT_ID g_then_id = 0, g_neg_then_id = 0, g_neg_else_id = 0; - LRAT_ID h_then_id = 0, h_neg_then_id = 0, h_else_id = 0; - LRAT_ID g_else_id = 0, h_neg_else_id = 0; - const bool degenerated_g_then = ite_flags_no_then_clauses (flags_g); - const bool degenerated_g_else = ite_flags_no_else_clauses (flags_g); - const bool degenerated_h_then = ite_flags_no_then_clauses (flags_h); - const bool degenerated_h_else = ite_flags_no_else_clauses (flags_h); - - const bool degenerated_g_cond = ite_flags_cond_lhs (flags_g); - const bool degenerated_h_cond = ite_flags_cond_lhs (flags_h); - CADICAL_assert (!(degenerated_g_cond && degenerated_h_cond)); - - const bool degenerated_g_not_cond = ite_flags_neg_cond_lhs (flags_g); - const bool degenerated_h_not_cond = ite_flags_neg_cond_lhs (flags_h); - CADICAL_assert (!(degenerated_g_not_cond && degenerated_h_not_cond)); - - if (internal->lrat) { - // the code can produce tautologies in the case that: - // a = (c ? a : e) - // b = (c ? a : e) - // (no clauses with (then) index a/-a) - // but also for - // a = (a ? t : e) - // b = (a ? t : e) - // (no clauses with (then) index -a and (else) index e) - // and same for - // a = (c ? t : a) - // b = (c ? t : a) - // (no clauses with (then) index a and (else) index -e) - LOG (g, "get ids from"); - CADICAL_assert (g->pos_lhs_ids.size () == 4); - auto &g_then_clause = g->pos_lhs_ids[0].clause; - g_then_clause = - g_then_clause ? produce_rewritten_clause_lrat (g_then_clause, g->lhs, false) : nullptr; - if (g_then_clause) - g_then_id = g_then_clause->id; - - auto &g_neg_then_clause = g->pos_lhs_ids[1].clause; - g_neg_then_clause = - g_neg_then_clause ? produce_rewritten_clause_lrat (g_neg_then_clause, g->lhs, false) : nullptr; - if (g_neg_then_clause) - g_neg_then_id = g_neg_then_clause->id; - - auto &g_else_clause = g->pos_lhs_ids[2].clause; - g_else_clause = - g_else_clause ? produce_rewritten_clause_lrat (g_else_clause, g->lhs, false) : g_else_clause; - if (g_else_clause) - g_else_id = g_else_clause->id; - - auto &g_neg_else_clause = g->pos_lhs_ids[3].clause; - g_neg_else_clause = - g_neg_else_clause ? produce_rewritten_clause_lrat (g_neg_else_clause, g->lhs, false) : nullptr; - if (g_neg_else_clause) - g_neg_else_id = g_neg_else_clause->id; - - LOG (h, "now clauses from"); - CADICAL_assert (h->pos_lhs_ids.size () == 4); - auto &h_then_clause = h->pos_lhs_ids[0].clause; - h_then_clause = - h_then_clause ? produce_rewritten_clause_lrat (h_then_clause, h->lhs, false) : nullptr; - if (h_then_clause) - h_then_id = h_then_clause->id; - - auto &h_neg_then_clause = h->pos_lhs_ids[1].clause; - h_neg_then_clause = - h_neg_then_clause ? produce_rewritten_clause_lrat (h_neg_then_clause, h->lhs, false) : nullptr; - if (h_neg_then_clause) - h_neg_then_id = h_neg_then_clause->id; - - auto &h_else_clause = h->pos_lhs_ids[2].clause; - h_else_clause = - h_else_clause ? produce_rewritten_clause_lrat (h_else_clause, h->lhs, false) : nullptr; - if (h_else_clause) - h_else_id = h_else_clause->id; - - auto &h_neg_else_clause = h->pos_lhs_ids[3].clause; - h_neg_else_clause = - h_neg_else_clause ? produce_rewritten_clause_lrat (h_neg_else_clause, h->lhs, false) : nullptr; - if (h_neg_else_clause) - h_neg_else_id = h_neg_else_clause->id; - - } - - if (degenerated_g_cond) { - LOG ("special case: cond = lhs, g degenerated"); - unsimplified.push_back (-lhs1); - unsimplified.push_back (lhs2); - LRAT_ID id1 = 0; - if (internal->lrat) { - lrat_chain.push_back (g_then_id); - lrat_chain.push_back (h_neg_then_id); - } - id1 = simplify_and_add_to_proof_chain (unsimplified); - - unsimplified.clear (); - unsimplified.push_back (lhs1); - unsimplified.push_back (-lhs2); - LRAT_ID id2 = 0; - if (internal->lrat) { - lrat_chain.push_back (g_neg_else_id); - lrat_chain.push_back (h_else_id); - } - id2 = simplify_and_add_to_proof_chain (unsimplified); - - CADICAL_assert (!internal->lrat || id1); - CADICAL_assert (!internal->lrat || id2); - reasons1.push_back (id1); - reasons2.push_back (id2); - unsimplified.clear (); - return; - } - - if (degenerated_h_cond) { - LOG ("special case: cond = lhs, h degenerated"); - unsimplified.push_back (lhs1); // potentially lhs1 == lhs2 - unsimplified.push_back (-lhs2); - LRAT_ID id1 = 0; - if (internal->lrat) { - lrat_chain.push_back (h_then_id); - lrat_chain.push_back (g_neg_then_id); - } - id1 = simplify_and_add_to_proof_chain (unsimplified); - - unsimplified.clear (); - unsimplified.push_back (-lhs1); - unsimplified.push_back (lhs2); - LRAT_ID id2 = 0; - if (internal->lrat) { - lrat_chain.push_back (h_neg_else_id); - lrat_chain.push_back (g_else_id); - } - id2 = simplify_and_add_to_proof_chain (unsimplified); - - CADICAL_assert (!internal->lrat || id1); - CADICAL_assert (!internal->lrat || id2); - reasons2.push_back (id1); - reasons1.push_back (id2); - unsimplified.clear (); - return; - } - - if (degenerated_g_not_cond) { - LOG ("special case: cond = -lhs, g degenerated"); - unsimplified.push_back (lhs1); - unsimplified.push_back (-lhs2); - LRAT_ID id1 = 0; - if (internal->lrat) { - CADICAL_assert (g_neg_then_id && h_then_id && g_else_id && h_neg_else_id); - lrat_chain.push_back (g_neg_then_id); - lrat_chain.push_back (h_then_id); - } - id1 = simplify_and_add_to_proof_chain (unsimplified); - - unsimplified.clear (); - unsimplified.push_back (-lhs1); - unsimplified.push_back (lhs2); - LRAT_ID id2 = -1; - - if (internal->lrat) { - lrat_chain.push_back (g_else_id); - lrat_chain.push_back (h_neg_else_id); - } - id2 = simplify_and_add_to_proof_chain (unsimplified); - CADICAL_assert (!internal->lrat || id1); - CADICAL_assert (!internal->lrat || id2); - reasons2.push_back (id1); - reasons1.push_back (id2); - unsimplified.clear (); - return; - } - - if (degenerated_h_not_cond) { - LOG ("special case: cond = -lhs, h degenerated"); - unsimplified.push_back (lhs1); - unsimplified.push_back (-lhs2); - LRAT_ID id1 = 0; - if (internal->lrat) { - CADICAL_assert (g_neg_then_id && h_then_id && g_else_id && h_neg_else_id); - lrat_chain.push_back (h_neg_then_id); - lrat_chain.push_back (g_then_id); - } - id1 = simplify_and_add_to_proof_chain (unsimplified); - - unsimplified.clear (); - unsimplified.push_back (-lhs1); - unsimplified.push_back (lhs2); - LRAT_ID id2 = -1; - - if (internal->lrat) { - lrat_chain.push_back (h_else_id); - lrat_chain.push_back (g_neg_else_id); - } - id2 = simplify_and_add_to_proof_chain (unsimplified); - CADICAL_assert (!internal->lrat || id1); - CADICAL_assert (!internal->lrat || id2); - reasons2.push_back (id1); - reasons1.push_back (id2); - unsimplified.clear (); - return; - } - - LOG ("normal path"); - CADICAL_assert (!internal->lrat || degenerated_g_then || - (g_then_id && g_neg_then_id)); - CADICAL_assert (!internal->lrat || degenerated_g_else || - (g_else_id && g_neg_else_id)); - CADICAL_assert (!internal->lrat || degenerated_h_then || - (h_then_id && h_neg_then_id)); - CADICAL_assert (!internal->lrat || degenerated_h_else || - (h_else_id && h_neg_else_id)); - CADICAL_assert (!internal->lrat || g_then_id || h_neg_then_id); - CADICAL_assert (!internal->lrat || g_neg_then_id || h_then_id); - unsimplified.push_back (-lhs1); - unsimplified.push_back (lhs2); - unsimplified.push_back (-cond); - LRAT_ID id1 = 0; - if (degenerated_g_then || degenerated_h_then) { - id1 = degenerated_g_then ? h_neg_then_id : g_then_id; - } else { - if (internal->lrat) { - lrat_chain.push_back (g_then_id); - lrat_chain.push_back (h_neg_then_id); - } - id1 = simplify_and_add_to_proof_chain (unsimplified); - } - unsimplified.pop_back (); - unsimplified.push_back (cond); - - LRAT_ID id2 = 0; - if (degenerated_g_else || degenerated_h_else) { - id2 = degenerated_g_else ? h_neg_else_id : g_else_id; - } else { - if (internal->lrat) { - lrat_chain.push_back (h_neg_else_id); - lrat_chain.push_back (g_else_id); - } - id2 = simplify_and_add_to_proof_chain (unsimplified); - } - unsimplified.pop_back (); - - unsimplified.clear (); - unsimplified.push_back (lhs1); - unsimplified.push_back (-lhs2); - unsimplified.push_back (-cond); - CADICAL_assert (lrat_chain.empty ()); - - LRAT_ID id3 = 0; - if (degenerated_g_then || degenerated_h_then) { - id3 = degenerated_g_then ? h_then_id : g_neg_then_id; - } else { - if (internal->lrat) { - // lrat_chain.push_back (g_then_id); - // lrat_chain.push_back (h_neg_then_id); - lrat_chain.push_back (g_neg_then_id); - lrat_chain.push_back (h_then_id); - } - id3 = simplify_and_add_to_proof_chain (unsimplified); - } - unsimplified.pop_back (); - unsimplified.push_back (cond); - CADICAL_assert (lrat_chain.empty ()); - - LRAT_ID id4 = 0; - if (degenerated_g_else || degenerated_h_else) { - id4 = degenerated_g_else ? h_else_id : g_neg_else_id; - } else { - if (internal->lrat) { - lrat_chain.push_back (g_neg_else_id); - lrat_chain.push_back (h_else_id); - } - id4 = simplify_and_add_to_proof_chain (unsimplified); - } - unsimplified.pop_back (); - - if (internal->lrat) { - CADICAL_assert (!internal->lrat || (id1 && id2 && id3 && id4)); - reasons1.push_back (id1), reasons1.push_back (id2); - reasons2.push_back (id3), reasons2.push_back (id4); - } - - unsimplified.clear (); - - LOG ("finished ITE matching proof chain"); -} - -Gate *Closure::new_ite_gate (int lhs, int cond, int then_lit, int else_lit, - std::vector &&clauses) { - CADICAL_assert (chain.empty ()); - if (else_lit == -then_lit) { - if (then_lit < 0) - LOG ("skipping ternary XOR %d := %d ^ %d", lhs, cond, -then_lit); - else - LOG ("skipping ternary XOR %d := %d ^ %d", -lhs, cond, then_lit); - return nullptr; - } - if (else_lit == then_lit) { - LOG ("found trivial ITE gate %d := %d ? %d : %d", (lhs), (cond), - (then_lit), (else_lit)); - std::vector reasons_implication, reasons_back; - if (internal->lrat) { - merge_ite_gate_same_then_else_lrat (clauses, reasons_implication, - reasons_back); - } - if (merge_literals_lrat (lhs, then_lit, reasons_implication, - reasons_back)) - ++internal->stats.congruence.trivial_ite; - return 0; - } - - rhs.clear (); - rhs.push_back (cond); - rhs.push_back (then_lit); - rhs.push_back (else_lit); - LOG ("ITE gate %d = %d ? %d : %d", lhs, cond, then_lit, else_lit); - - bool negate_lhs = false; - Gate *g = new Gate; - g->lhs = lhs; - g->tag = Gate_Type::ITE_Gate; - g->rhs = {rhs}; - g->pos_lhs_ids = clauses; -#ifdef LOGGING - g->id = -1; -#endif - Gate *h = find_ite_gate (g, negate_lhs); - if (negate_lhs) - lhs = -lhs; - g->lhs = lhs; - check_ite_gate_implied (g); - check_ite_lrat_reasons ( - g, false); // due to merges done before during AND gate detection! - - if (h) { - check_ite_gate_implied (h); - std::vector extra_reasons_lit, extra_reasons_ulit; - add_ite_matching_proof_chain (h, g, h->lhs, lhs, extra_reasons_lit, - extra_reasons_ulit); - if (merge_literals_lrat (h, g, h->lhs, lhs, extra_reasons_lit, - extra_reasons_ulit)) { - ++internal->stats.congruence.ites; - LOG ("found merged literals"); - } - delete_proof_chain (); - delete g; - return h; - } else { - // do not sort clauses here obviously! - // sort (begin (g->rhs), end (g->rhs)); - g->garbage = false; - g->indexed = true; - g->shrunken = false; - g->hash = hash_lits (nonces, g->rhs); - table.insert (g); - ++internal->stats.congruence.gates; -#ifdef LOGGING - g->id = fresh_id++; -#endif - LOG (g, "creating new"); - if (internal->lrat) - update_ite_flags (g); - check_ite_gate_implied (g); - for (auto lit : g->rhs) { - connect_goccs (g, lit); - } - } - check_ite_lrat_reasons (g); - return g; -} - -void check_ite_lits_normalized (const std::vector &lits) { - CADICAL_assert (lits[0] > 0); - CADICAL_assert (lits[1] > 0); - CADICAL_assert (lits[0] != lits[1]); - CADICAL_assert (lits[0] != lits[2]); - CADICAL_assert (lits[1] != lits[2]); - CADICAL_assert (lits[0] != -lits[1]); - CADICAL_assert (lits[0] != -lits[2]); - CADICAL_assert (lits[1] != -lits[2]); -#ifdef CADICAL_NDEBUG - (void) lits; -#endif -} - -void Closure::check_ite_implied (int lhs, int cond, int then_lit, - int else_lit) { - if (internal->lrat) - return; - check_ternary (cond, -else_lit, lhs); - check_ternary (cond, else_lit, -lhs); - check_ternary (-cond, -then_lit, lhs); - check_ternary (-cond, then_lit, -lhs); -} - -void Closure::check_contained_module_rewriting (Clause *c, int lit, - bool normalized, - int except) { -#ifndef CADICAL_NDEBUG - if (lit == except) // happens for degenerated cases - except = 0; - const int normalize_lit = - (lit == except ? except : find_eager_representative (lit)); - CADICAL_assert (!normalized || lit == -except || normalize_lit == lit); - bool found = false; - LOG (c, "looking for (normalized) %d in ", lit); - for (auto other : *c) { - const int normalize_other = - (other == except ? except : find_eager_representative (other)); - LOG ("%d -> %d ", other, normalize_other); - CADICAL_assert (!normalized || other == -except || normalize_other == other); - if (normalize_other == normalize_lit) { - found = true; - break; - } - } - CADICAL_assert (found); -#else - (void) c, (void) lit, (void) normalized, (void) except; -#endif -} - -void Closure::check_ite_lrat_reasons (Gate *g, bool normalized) { -#ifndef CADICAL_NDEBUG - CADICAL_assert (g->tag == Gate_Type::ITE_Gate); - if (!internal->lrat) - return; - CADICAL_assert (g->rhs.size () == 3); - CADICAL_assert (is_tautological_ite_gate (g) || g->pos_lhs_ids.size () == 4); - CADICAL_assert (g->neg_lhs_ids.empty ()); - CADICAL_assert (g->pos_lhs_ids.size () == 4); -#else - (void) g, (void) normalized; -#endif -} - -void Closure::check_ite_gate_implied (Gate *g) { - CADICAL_assert (g->tag == Gate_Type::ITE_Gate); - if (internal->lrat) - return; - check_ite_implied (g->lhs, g->rhs[0], g->rhs[1], g->rhs[2]); -} - -void Closure::init_ite_gate_extraction ( - std::vector &candidates) { - std::vector ternary; - glargecounts.resize (2 * internal->vsize, 0); - for (auto c : internal->clauses) { - if (c->garbage) - continue; - if (c->redundant) - continue; - if (c->size < 3) - continue; - unsigned size = 0; - - CADICAL_assert (!c->garbage); - for (auto lit : *c) { - const signed char v = internal->val (lit); - if (v < 0) - continue; - if (v > 0) { - LOG (c, "deleting as satisfied due to %d", lit); - internal->mark_garbage (c); - goto CONTINUE_COUNTING_NEXT_CLAUSE; - } - if (size == 3) - goto CONTINUE_COUNTING_NEXT_CLAUSE; - size++; - } - if (size < 3) - continue; - CADICAL_assert (size == 3); - ternary.push_back (c); - LOG (c, "counting original ITE gate base"); - for (auto lit : *c) { - if (!internal->val (lit)) - ++largecount (lit); - } - CONTINUE_COUNTING_NEXT_CLAUSE:; - } - - for (auto c : ternary) { - CADICAL_assert (!c->garbage); - CADICAL_assert (!c->redundant); - unsigned positive = 0, negative = 0, twice = 0; - for (auto lit : *c) { - if (internal->val (lit)) - continue; - const int count_not_lit = largecount (-lit); - if (!count_not_lit) - goto CONTINUE_WITH_NEXT_TERNARY_CLAUSE; - const unsigned count_lit = largecount (lit); - CADICAL_assert (count_lit); - if (count_lit > 1 && count_not_lit > 1) - ++twice; - if (lit < 0) - ++negative; - else - ++positive; - } - if (twice < 2) - goto CONTINUE_WITH_NEXT_TERNARY_CLAUSE; - CADICAL_assert (c->size != 2); - for (auto lit : *c) - internal->occs (lit).push_back (c); - if (positive && negative) - candidates.push_back (c); - CONTINUE_WITH_NEXT_TERNARY_CLAUSE:; - } - - ternary.clear (); -} - -void Closure::reset_ite_gate_extraction () { - condbin[0].clear (); - condbin[1].clear (); - condeq[0].clear (); - condeq[1].clear (); - glargecounts.clear (); - internal->clear_occs (); -} - -void Closure::copy_conditional_equivalences (int lit, - lit_implications &condbin) { - CADICAL_assert (condbin.empty ()); - for (auto c : internal->occs (lit)) { - CADICAL_assert (c->size != 2); - int first = 0, second = 0; - for (auto other : *c) { - if (internal->val (other)) - continue; - if (other == lit) - continue; - if (!first) - first = other; - else { - CADICAL_assert (!second); - second = other; - } - } - CADICAL_assert (first), CADICAL_assert (second); - lit_implication p (first, second, c); - - if (internal->vlit (first) < internal->vlit (second)) { - CADICAL_assert (p.first == first); - CADICAL_assert (p.second == second); - } else { - CADICAL_assert (internal->vlit (second) < internal->vlit (first)); - p.swap (); - CADICAL_assert (p.first == second); - CADICAL_assert (p.second == first); - } - LOG (c, "literal %d condition binary clause %d %d", lit, first, second); - condbin.push_back (p); - } -} - -bool less_litpair (lit_equivalence p, lit_equivalence q) { - const int a = p.first; - const int b = q.first; - if (a < b) - return true; - if (b > a) - return false; - const int c = p.second; - const int d = q.second; - return (c < d); -} -struct litpair_rank { - CaDiCaL::Internal *internal; - litpair_rank (Internal *i) : internal (i) {} - typedef uint64_t Type; - Type operator() (const lit_implication &a) const { - uint64_t lita = internal->vlit (a.first); - uint64_t litb = internal->vlit (a.second); - return (lita << 32) + litb; - } -}; - -struct litpair_smaller { - CaDiCaL::Internal *internal; - litpair_smaller (Internal *i) : internal (i) {} - bool operator() (const lit_implication &a, - const lit_implication &b) const { - const auto s = litpair_rank (internal) (a); - const auto t = litpair_rank (internal) (b); - return s < t; - } -}; - -lit_implications::const_iterator -Closure::find_lit_implication_second_literal ( - int lit, lit_implications::const_iterator begin, - lit_implications::const_iterator end) { - LOG ("searching for %d in", lit); - for (auto it = begin; it != end; ++it) - LOG ("%d [%d]", it->first, it->second); - lit_implications::const_iterator found = std::lower_bound ( - begin, end, lit_implication{lit, lit}, - [] (const lit_implication &a, const lit_implication &b) { - return a.second < b.second; - }); -#ifndef CADICAL_NDEBUG - auto found2 = std::binary_search ( - begin, end, lit_implication{lit, lit}, - [] (const lit_implication &a, const lit_implication &b) { - return a.second < b.second; - }); -#endif - - if (found < end && found->second == lit) { - CADICAL_assert (found2 == (found < end)); - return found; - } - return end; -} - -void Closure::search_condeq (int lit, int pos_lit, - lit_implications::const_iterator pos_begin, - lit_implications::const_iterator pos_end, - int neg_lit, - lit_implications::const_iterator neg_begin, - lit_implications::const_iterator neg_end, - lit_equivalences &condeq) { - CADICAL_assert (neg_lit == -pos_lit); - CADICAL_assert (pos_begin < pos_end); - CADICAL_assert (neg_begin < neg_end); - CADICAL_assert (pos_begin->first == pos_lit); - CADICAL_assert (neg_begin->first == neg_lit); - CADICAL_assert (pos_end <= neg_begin || neg_end <= pos_begin); - for (lit_implications::const_iterator p = pos_begin; p != pos_end; p++) { - const int other = p->second; - const int not_other = -other; - const lit_implications::const_iterator other_clause = - find_lit_implication_second_literal (not_other, neg_begin, neg_end); - CADICAL_assert (std::find (begin (*p->clause), end (*p->clause), lit) != - end (*p->clause)); - if (other_clause != neg_end) { - CADICAL_assert (std::find (begin (*other_clause->clause), - end (*other_clause->clause), - neg_lit) != end (*other_clause->clause)); - CADICAL_assert (std::find (begin (*p->clause), end (*p->clause), other) != - end (*p->clause)); - lit_equivalence equivalence (neg_lit, other_clause->clause, other, - p->clause); - if (pos_lit > 0) { - equivalence.negate_both (); - } - if (internal->lrat) - equivalence.check_invariant (); - LOG ("found conditional %d equivalence %d = %d", lit, - equivalence.first, equivalence.second); - CADICAL_assert (equivalence.first > 0); - CADICAL_assert (internal->vlit (equivalence.first) < - internal->vlit (equivalence.second)); - check_ternary (lit, neg_lit, -other); - check_ternary (lit, -neg_lit, other); - condeq.push_back (equivalence); - if (equivalence.second < 0) { - lit_equivalence inverse_equivalence = - equivalence.swap ().negate_both (); - condeq.push_back (inverse_equivalence); - if (internal->lrat) - inverse_equivalence.check_invariant (); - } else { - lit_equivalence inverse_equivalence = equivalence.swap (); - condeq.push_back (inverse_equivalence); - if (internal->lrat) - inverse_equivalence.check_invariant (); - } - } - } -#ifndef LOGGING - (void) lit; -#endif -} - -void Closure::extract_condeq_pairs (int lit, lit_implications &condbin, - lit_equivalences &condeq) { - const lit_implications::const_iterator begin = condbin.cbegin (); - const lit_implications::const_iterator end = condbin.cend (); - lit_implications::const_iterator pos_begin = begin; - int next_lit = 0; - -#ifdef LOGGING - for (const auto &pair : condbin) - LOG ("unsorted conditional %d equivalence %d = %d", lit, pair.first, - pair.second); -#endif - LOG ("searching for first positive literal for lit %d", lit); - for (;;) { - if (pos_begin == end) - return; - next_lit = pos_begin->first; - LOG ("checking %d", next_lit); - if (next_lit > 0) - break; - pos_begin++; - } - - for (;;) { - CADICAL_assert (pos_begin != end); - CADICAL_assert (next_lit == pos_begin->first); - CADICAL_assert (next_lit > 0); - const int pos_lit = next_lit; - lit_implications::const_iterator pos_end = pos_begin + 1; - LOG ("searching for first other literal after finding lit %d", - next_lit); - for (;;) { - if (pos_end == end) - return; - next_lit = pos_end->first; - if (next_lit != pos_lit) - break; - pos_end++; - } - CADICAL_assert (pos_end != end); - CADICAL_assert (next_lit == pos_end->first); - const int neg_lit = -pos_lit; - if (next_lit != neg_lit) { - if (next_lit < 0) { - pos_begin = pos_end + 1; - LOG ("next_lit %d < 0", next_lit); - for (;;) { - if (pos_begin == end) - return; - next_lit = pos_begin->first; - if (next_lit > 0) - break; - pos_begin++; - } - } else - pos_begin = pos_end; - continue; - } - const lit_implications::const_iterator neg_begin = pos_end; - lit_implications::const_iterator neg_end = neg_begin + 1; - while (neg_end != end) { - next_lit = neg_end->first; - if (next_lit != neg_lit) - break; - neg_end++; - } -#ifdef LOGGING - for (lit_implications::const_iterator p = pos_begin; p != pos_end; p++) - LOG ("conditional %d binary clause %d %d with positive %d", (lit), - (p->first), (p->second), (pos_lit)); - for (lit_implications::const_iterator p = neg_begin; p != neg_end; p++) - LOG ("conditional %d binary clause %d %d with negative %d", (lit), - (p->first), (p->second), (neg_lit)); -#endif - const size_t pos_size = pos_end - pos_begin; - const size_t neg_size = neg_end - neg_begin; - if (pos_size <= neg_size) { - LOG ("searching negation of %zu conditional binary clauses " - "with positive %d in %zu conditional binary clauses with %d", - pos_size, (pos_lit), neg_size, (neg_lit)); - search_condeq (lit, pos_lit, pos_begin, pos_end, neg_lit, neg_begin, - neg_end, condeq); - } else { - LOG ("searching negation of %zu conditional binary clauses " - "with negative %d in %zu conditional binary clauses with %d", - neg_size, (neg_lit), pos_size, (pos_lit)); - search_condeq (lit, neg_lit, neg_begin, neg_end, pos_lit, pos_begin, - pos_end, condeq); - } - if (neg_end == end) - return; - CADICAL_assert (next_lit == neg_end->first); - if (next_lit < 0) { - pos_begin = neg_end + 1; - for (;;) { - if (pos_begin == end) - return; - next_lit = pos_begin->first; - if (next_lit > 0) - break; - pos_begin++; - } - } else - pos_begin = neg_end; - } -} - -void Closure::find_conditional_equivalences (int lit, - lit_implications &condbin, - lit_equivalences &condeq) { - CADICAL_assert (condbin.empty ()); - CADICAL_assert (condeq.empty ()); - CADICAL_assert (internal->occs (lit).size () > 1); - copy_conditional_equivalences (lit, condbin); - MSORT (internal->opts.radixsortlim, begin (condbin), end (condbin), - litpair_rank (this->internal), litpair_smaller (this->internal)); - - extract_condeq_pairs (lit, condbin, condeq); - MSORT (internal->opts.radixsortlim, begin (condbin), end (condbin), - litpair_rank (this->internal), litpair_smaller (this->internal)); - -#ifdef LOGGING - for (auto pair : condeq) - LOG ("sorted conditional %d equivalence %d = %d", lit, pair.first, - pair.second); - LOG ("found %zu conditional %d equivalences", condeq.size (), lit); - -#endif -} - -void Closure::merge_condeq (int cond, lit_equivalences &condeq, - lit_equivalences ¬_condeq) { - LOG ("merging cond for literal %d", cond); - auto q = begin (not_condeq); - const auto end_not_condeq = end (not_condeq); - for (auto p : condeq) { - const int lhs = p.first; - const int then_lit = p.second; - if (internal->lrat) - p.check_invariant (); - CADICAL_assert (lhs > 0); - while (q != end_not_condeq && q->first < lhs) - ++q; - while (q != end_not_condeq && q->first == lhs) { - LOG ("looking when %d at p= %d %d", cond, p.first, p.second); - LOG ("looking when %d at %d %d", -cond, q->first, q->second); - lit_equivalence not_cond_pair = *q++; - const int else_lit = not_cond_pair.second; - std::vector clauses; - if (internal->lrat) { - // The then/else literal is the second of the pair, hence the swap - // of the reasons - CADICAL_assert (p.first_clause && p.second_clause); - CADICAL_assert (not_cond_pair.first_clause && not_cond_pair.second_clause); - LOG (p.second_clause, "pairing %d", then_lit); - LOG (p.first_clause, "pairing %d", -then_lit); - LOG (not_cond_pair.second_clause, "pairing %d", else_lit); - LOG (not_cond_pair.first_clause, "pairing %d", -else_lit); - clauses.push_back (LitClausePair (then_lit, p.second_clause)); - clauses.push_back (LitClausePair (-then_lit, p.first_clause)); - clauses.push_back ( - LitClausePair (else_lit, not_cond_pair.second_clause)); - clauses.push_back ( - LitClausePair (-else_lit, not_cond_pair.first_clause)); - if (internal->lrat) - not_cond_pair.check_invariant (); - } - new_ite_gate (lhs, cond, then_lit, else_lit, std::move (clauses)); - if (internal->unsat) - return; - } - } -} - -void Closure::extract_ite_gates_of_literal (int lit) { - LOG ("search for ITE for literal %d ", lit); - find_conditional_equivalences (lit, condbin[0], condeq[0]); - if (!condeq[0].empty ()) { - find_conditional_equivalences (-lit, condbin[1], condeq[1]); - if (!condeq[1].empty ()) { - if (lit < 0) - merge_condeq (-lit, condeq[0], condeq[1]); - else - merge_condeq (lit, condeq[1], condeq[0]); - } - } - - condbin[0].clear (); - condbin[1].clear (); - condeq[0].clear (); - condeq[1].clear (); -} - -void Closure::extract_ite_gates_of_variable (int idx) { - const int lit = idx; - const int not_lit = -idx; - - auto lit_watches = internal->occs (lit); - auto not_lit_watches = internal->occs (not_lit); - const size_t size_lit_watches = lit_watches.size (); - const size_t size_not_lit_watches = not_lit_watches.size (); - if (size_lit_watches <= size_not_lit_watches) { - if (size_lit_watches > 1) - extract_ite_gates_of_literal (lit); - } else { - if (size_not_lit_watches > 1) - extract_ite_gates_of_literal (not_lit); - } -} - -void Closure::extract_ite_gates () { - CADICAL_assert (!full_watching); - if (!internal->opts.congruenceite) - return; - START (extractites); - std::vector candidates; - - init_ite_gate_extraction (candidates); - - for (auto idx : internal->vars) { - if (internal->flags (idx).active ()) { - extract_ite_gates_of_variable (idx); - if (internal->unsat) - break; - } - } - // Kissat has an alternative version MERGE_CONDITIONAL_EQUIVALENCES - reset_ite_gate_extraction (); - STOP (extractites); -} - -/*------------------------------------------------------------------------*/ -void Closure::extract_gates () { - START (extract); - extract_and_gates (); - CADICAL_assert (internal->unsat || lrat_chain.empty ()); - CADICAL_assert (internal->unsat || chain.empty ()); - if (internal->unsat || internal->terminated_asynchronously ()) { - STOP (extract); - return; - } - extract_xor_gates (); - CADICAL_assert (internal->unsat || lrat_chain.empty ()); - CADICAL_assert (internal->unsat || chain.empty ()); - - if (internal->unsat || internal->terminated_asynchronously ()) { - STOP (extract); - return; - } - extract_ite_gates (); - STOP (extract); -} - -/*------------------------------------------------------------------------*/ -// top level function to extract gate -bool Internal::extract_gates () { - if (unsat) - return false; - if (!opts.congruence) - return false; - if (level) - backtrack (); - if (!propagate ()) { - learn_empty_clause (); - return false; - } - if (congruence_delay.bumpreasons.limit) { - LOG ("delaying congruence %" PRId64 " more times", - congruence_delay.bumpreasons.limit); - congruence_delay.bumpreasons.limit--; - return false; - } - - // to remove false literals from clauses - // It makes the technique stronger as long clauses - // can become binary / ternary - // garbage_collection (); - - const int64_t old = stats.congruence.congruent; - const int old_merged = stats.congruence.congruent; - - // congruencebinary is already doing it (and more actually) - if (!internal->opts.congruencebinaries) { - const bool dedup = opts.deduplicate; - opts.deduplicate = true; - mark_duplicated_binary_clauses_as_garbage (); - opts.deduplicate = dedup; - } - ++stats.congruence.rounds; - clear_watches (); - // connect_binary_watches (); - - START_SIMPLIFIER (congruence, CONGRUENCE); - Closure closure (this); - - closure.init_closure (); - CADICAL_assert (unsat || closure.chain.empty ()); - CADICAL_assert (unsat || lrat_chain.empty ()); - closure.extract_binaries (); - CADICAL_assert (unsat || closure.chain.empty ()); - CADICAL_assert (unsat || lrat_chain.empty ()); - closure.extract_gates (); - CADICAL_assert (unsat || closure.chain.empty ()); - CADICAL_assert (unsat || lrat_chain.empty ()); - internal->clear_watches (); - internal->connect_watches (); - closure.reset_extraction (); - - if (!unsat) { - closure.find_units (); - CADICAL_assert (unsat || closure.chain.empty ()); - CADICAL_assert (unsat || lrat_chain.empty ()); - if (!internal->unsat) { - closure.find_equivalences (); - CADICAL_assert (unsat || closure.chain.empty ()); - CADICAL_assert (unsat || lrat_chain.empty ()); - - if (!unsat) { - const int propagated = closure.propagate_units_and_equivalences (); - CADICAL_assert (unsat || closure.chain.empty ()); - if (!unsat && propagated) - closure.forward_subsume_matching_clauses (); - } - } - } - - closure.reset_closure (); - internal->clear_watches (); - internal->connect_watches (); - if (!internal->unsat) { - propagated2 = propagated = 0; - propagate (); - } - CADICAL_assert (closure.new_unwatched_binary_clauses.empty ()); - internal->reset_occs (); - internal->reset_noccs (); - CADICAL_assert (!internal->occurring ()); - CADICAL_assert (lrat_chain.empty ()); - - const int64_t new_merged = stats.congruence.congruent; - -#ifndef CADICAL_QUIET - phase ("congruence-phase", stats.congruence.rounds, "merged %ld literals", - new_merged - old_merged); -#endif - if (!unsat && !internal->propagate ()) - unsat = true; - - STOP_SIMPLIFIER (congruence, CONGRUENCE); - report ('c', !opts.reportall && !(stats.congruence.congruent - old)); -#ifndef CADICAL_NDEBUG - size_t watched = 0; - for (auto v : vars) { - for (auto sgn = -1; sgn <= 1; sgn += 2) { - const int lit = v * sgn; - for (auto w : watches (lit)) { - if (w.binary ()) - CADICAL_assert (!w.clause->garbage); - if (w.clause->garbage) - continue; - ++watched; - LOG (w.clause, "watched"); - } - } - } - LOG ("and now the clauses:"); - size_t nb_clauses = 0; - for (auto c : clauses) { - if (c->garbage) - continue; - LOG (c, "watched"); - ++nb_clauses; - } - CADICAL_assert (watched == nb_clauses * 2); -#endif - CADICAL_assert (!internal->occurring ()); - - if (new_merged == old_merged) { - congruence_delay.bumpreasons.interval++; - } else { - congruence_delay.bumpreasons.interval /= 2; - } - - LOG ("delay congruence internal %" PRId64, - congruence_delay.bumpreasons.interval); - congruence_delay.bumpreasons.limit = - congruence_delay.bumpreasons.interval; - - return new_merged != old_merged; -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_constrain.cpp b/src/sat/cadical/cadical_constrain.cpp deleted file mode 100644 index 47f14e3d9..000000000 --- a/src/sat/cadical/cadical_constrain.cpp +++ /dev/null @@ -1,70 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -void Internal::constrain (int lit) { - if (lit) - constraint.push_back (lit); - else { - if (level) - backtrack (); - LOG (constraint, "shrinking constraint"); - bool satisfied_constraint = false; - const vector::const_iterator end = constraint.end (); - vector::iterator i = constraint.begin (); - for (vector::const_iterator j = i; j != end; j++) { - int tmp = marked (*j); - if (tmp > 0) { - LOG ("removing duplicated literal %d from constraint", *j); - } else if (tmp < 0) { - LOG ("tautological since both %d and %d occur in constraint", -*j, - *j); - satisfied_constraint = true; - break; - } else { - tmp = val (*j); - if (tmp < 0) { - LOG ("removing falsified literal %d from constraint clause", *j); - } else if (tmp > 0) { - LOG ("satisfied constraint with literal %d", *j); - satisfied_constraint = true; - break; - } else { - *i++ = *j; - mark (*j); - } - } - } - constraint.resize (i - constraint.begin ()); - for (const auto &lit : constraint) - unmark (lit); - if (satisfied_constraint) - constraint.clear (); - else if (constraint.empty ()) { - unsat_constraint = true; - if (!conflict_id) - marked_failed = false; // allow to trigger failing () - } else - for (const auto lit : constraint) - freeze (lit); - } -} - -bool Internal::failed_constraint () { return unsat_constraint; } - -void Internal::reset_constraint () { - for (auto lit : constraint) - melt (lit); - LOG ("cleared %zd constraint literals", constraint.size ()); - constraint.clear (); - unsat_constraint = false; - marked_failed = true; -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_contract.cpp b/src/sat/cadical/cadical_contract.cpp deleted file mode 100644 index 7485ff4aa..000000000 --- a/src/sat/cadical/cadical_contract.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include "global.h" - -#ifndef CADICAL_NCONTRACTS - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -void fatal_message_start (); - -// See comments in 'contract.hpp'. Ugly hack we keep for now. - -void require_solver_pointer_to_be_non_zero (const void *ptr, - const char *function_name, - const char *file_name) { - if (ptr) - return; - fatal_message_start (); - fprintf (stderr, - "invalid API usage of '%s' in '%s': " - "solver 'this' pointer zero (not initialized)\n", - function_name, file_name); - fflush (stderr); - abort (); -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END - -#endif diff --git a/src/sat/cadical/cadical_cover.cpp b/src/sat/cadical/cadical_cover.cpp deleted file mode 100644 index 0d3253e98..000000000 --- a/src/sat/cadical/cadical_cover.cpp +++ /dev/null @@ -1,710 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -/*------------------------------------------------------------------------*/ - -// Covered clause elimination (CCE) is described in our short LPAR-10 paper -// and later in more detail in our JAIR'15 article. Actually implement -// the asymmetric version which adds asymmetric literals too but still call -// it 'CCE' in the following (and not 'ACCE'). This implementation provides -// a simplified and cleaner version of the one implemented before in -// Lingeling. We still follow quite closely the original description in the -// literature, which is based on asymmetric literal addition (ALA) and -// covered literal addition (CLA). Both can be seen as kind of propagation, -// where the literals in the original and then extended clause are assigned -// to false, and the literals on the trail (actually we use our own 'added' -// stack for that) make up the extended clause. The ALA steps can be -// implemented by simple propagation (copied from 'propagate.cpp') using -// watches, while the CLA steps need full occurrence lists to determine the -// resolution candidate clauses. The CCE is successful if a conflict is -// found during ALA steps or if during a CLA step all resolution candidates -// of a literal on the trail are satisfied (the extended clause is blocked). - -struct Coveror { - std::vector added; // acts as trail - std::vector extend; // extension stack for witness - std::vector covered; // clause literals or added through CLA - std::vector intersection; // of literals in resolution candidates - - size_t alas, clas; // actual number of ALAs and CLAs - - struct { - size_t added, covered; - } next; // propagate next ... - - Coveror () : alas (0), clas (0) {} -}; - -/*------------------------------------------------------------------------*/ - -// Push on the extension stack a clause made up of the given literal, the -// original clause (initially copied to 'covered') and all the added covered -// literals so far. The given literal will act as blocking literal for that -// clause, if CCE is successful. Only in this case, this private extension -// stack is copied to the actual extension stack of the solver. Note, that -// even though all 'added' clauses correspond to the extended clause, we -// only need to save the original and added covered literals. - -inline void Internal::cover_push_extension (int lit, Coveror &coveror) { - coveror.extend.push_back (0); - coveror.extend.push_back (lit); // blocking literal comes first - bool found = false; - for (const auto &other : coveror.covered) - if (lit == other) - CADICAL_assert (!found), found = true; - else - coveror.extend.push_back (other); - CADICAL_assert (found); - (void) found; -} - -// Successful covered literal addition (CLA) step. - -inline void Internal::covered_literal_addition (int lit, Coveror &coveror) { - require_mode (COVER); - CADICAL_assert (level == 1); - cover_push_extension (lit, coveror); - for (const auto &other : coveror.intersection) { - LOG ("covered literal addition %d", other); - CADICAL_assert (!vals[other]), CADICAL_assert (!vals[-other]); - set_val (other, -1); - coveror.covered.push_back (other); - coveror.added.push_back (other); - coveror.clas++; - } - coveror.next.covered = 0; -} - -// Successful asymmetric literal addition (ALA) step. - -inline void Internal::asymmetric_literal_addition (int lit, - Coveror &coveror) { - require_mode (COVER); - CADICAL_assert (level == 1); - LOG ("initial asymmetric literal addition %d", lit); - CADICAL_assert (!vals[lit]), CADICAL_assert (!vals[-lit]); - set_val (lit, -1); - coveror.added.push_back (lit); - coveror.alas++; - coveror.next.covered = 0; -} - -/*------------------------------------------------------------------------*/ - -// In essence copied and adapted from 'propagate' in 'propagate.cpp'. Since -// this function is also a hot-spot here in 'cover' we specialize it in the -// same spirit as 'probe_propagate' and 'vivify_propagate'. Please refer to -// the detailed comments for 'propagate' in 'propagate.cpp' for details. - -bool Internal::cover_propagate_asymmetric (int lit, Clause *ignore, - Coveror &coveror) { - require_mode (COVER); - stats.propagations.cover++; - CADICAL_assert (val (lit) < 0); - bool subsumed = false; - LOG ("asymmetric literal propagation of %d", lit); - Watches &ws = watches (lit); - const const_watch_iterator eow = ws.end (); - watch_iterator j = ws.begin (); - const_watch_iterator i = j; - while (!subsumed && i != eow) { - const Watch w = *j++ = *i++; - if (w.clause == ignore) - continue; // costly but necessary here ... - const signed char b = val (w.blit); - if (b > 0) - continue; - if (w.clause->garbage) - j--; - else if (w.binary ()) { - if (b < 0) { - LOG (w.clause, "found subsuming"); - subsumed = true; - } else - asymmetric_literal_addition (-w.blit, coveror); - } else { - literal_iterator lits = w.clause->begin (); - const int other = lits[0] ^ lits[1] ^ lit; - lits[0] = other, lits[1] = lit; - const signed char u = val (other); - if (u > 0) - j[-1].blit = other; - else { - const int size = w.clause->size; - const const_literal_iterator end = lits + size; - const literal_iterator middle = lits + w.clause->pos; - literal_iterator k = middle; - signed char v = -1; - int r = 0; - while (k != end && (v = val (r = *k)) < 0) - k++; - if (v < 0) { - k = lits + 2; - CADICAL_assert (w.clause->pos <= size); - while (k != middle && (v = val (r = *k)) < 0) - k++; - } - w.clause->pos = k - lits; - CADICAL_assert (lits + 2 <= k), CADICAL_assert (k <= w.clause->end ()); - if (v > 0) - j[-1].blit = r; - else if (!v) { - LOG (w.clause, "unwatch %d in", lit); - lits[1] = r; - *k = lit; - watch_literal (r, lit, w.clause); - j--; - } else if (!u) { - CADICAL_assert (v < 0); - asymmetric_literal_addition (-other, coveror); - } else { - CADICAL_assert (u < 0), CADICAL_assert (v < 0); - LOG (w.clause, "found subsuming"); - subsumed = true; - break; - } - } - } - } - if (j != i) { - while (i != eow) - *j++ = *i++; - ws.resize (j - ws.begin ()); - } - return subsumed; -} - -// Covered literal addition (which needs full occurrence lists). The -// function returns 'true' if the extended clause is blocked on 'lit.' - -bool Internal::cover_propagate_covered (int lit, Coveror &coveror) { - require_mode (COVER); - - CADICAL_assert (val (lit) < 0); - if (frozen (lit)) { - LOG ("no covered propagation on frozen literal %d", lit); - return false; - } - - stats.propagations.cover++; - - LOG ("covered propagation of %d", lit); - CADICAL_assert (coveror.intersection.empty ()); - - Occs &os = occs (-lit); - const auto end = os.end (); - bool first = true; - - // Compute the intersection of the literals in all the clauses with - // '-lit'. If all these clauses are double satisfied then we know that - // the extended clauses (in 'added') is blocked. All literals in the - // intersection can be added as covered literal. As soon the intersection - // becomes empty (during traversal of clauses with '-lit') we abort. - - for (auto i = os.begin (); i != end; i++) { - - Clause *c = *i; - if (c->garbage) - continue; - - // First check whether clause is 'blocked', i.e., is double satisfied. - - bool blocked = false; - for (const auto &other : *c) { - if (other == -lit) - continue; - const signed char tmp = val (other); - if (tmp < 0) - continue; - if (tmp > 0) { - blocked = true; - break; - } - } - if (blocked) { // ... if 'c' is double satisfied. - LOG (c, "blocked"); - continue; // with next clause with '-lit'. - } - - if (first) { - - // Copy and mark literals of first clause. - - for (const auto &other : *c) { - if (other == -lit) - continue; - const signed char tmp = val (other); - if (tmp < 0) - continue; - CADICAL_assert (!tmp); - coveror.intersection.push_back (other); - mark (other); - } - - first = false; - - } else { - - // Unmark all literals in current clause. - - for (const auto &other : *c) { - if (other == -lit) - continue; - signed char tmp = val (other); - if (tmp < 0) - continue; - CADICAL_assert (!tmp); - tmp = marked (other); - if (tmp > 0) - unmark (other); - } - - // Then remove from intersection all marked literals. - - const auto end = coveror.intersection.end (); - auto j = coveror.intersection.begin (); - for (auto k = j; k != end; k++) { - const int other = *j++ = *k; - const int tmp = marked (other); - CADICAL_assert (tmp >= 0); - if (tmp) - j--, unmark (other); // remove marked and unmark it - else - mark (other); // keep unmarked and mark it - } - const size_t new_size = j - coveror.intersection.begin (); - coveror.intersection.resize (new_size); - - if (!coveror.intersection.empty ()) - continue; - - // No covered literal addition candidates in the intersection left! - // Move this clause triggering early abort to the beginning. - // This is a common move to front strategy to minimize effort. - - auto begin = os.begin (); - while (i != begin) { - auto prev = i - 1; - *i = *prev; - i = prev; - } - *begin = c; - - break; // early abort ... - } - } - - bool res = false; - if (first) { - LOG ("all resolution candidates with %d blocked", -lit); - CADICAL_assert (coveror.intersection.empty ()); - cover_push_extension (lit, coveror); - res = true; - } else if (coveror.intersection.empty ()) { - LOG ("empty intersection of resolution candidate literals"); - } else { - LOG (coveror.intersection, - "non-empty intersection of resolution candidate literals"); - covered_literal_addition (lit, coveror); - unmark (coveror.intersection); - coveror.intersection.clear (); - coveror.next.covered = 0; // Restart covering. - } - - unmark (coveror.intersection); - coveror.intersection.clear (); - - return res; -} - -/*------------------------------------------------------------------------*/ - -bool Internal::cover_clause (Clause *c, Coveror &coveror) { - - require_mode (COVER); - CADICAL_assert (!c->garbage); - - LOG (c, "trying covered clauses elimination on"); - bool satisfied = false; - for (const auto &lit : *c) - if (val (lit) > 0) - satisfied = true; - - if (satisfied) { - LOG (c, "clause already satisfied"); - mark_garbage (c); - return false; - } - - CADICAL_assert (coveror.added.empty ()); - CADICAL_assert (coveror.extend.empty ()); - CADICAL_assert (coveror.covered.empty ()); - - CADICAL_assert (!level); - level = 1; - LOG ("assuming literals of candidate clause"); - for (const auto &lit : *c) { - if (val (lit)) - continue; - asymmetric_literal_addition (lit, coveror); - coveror.covered.push_back (lit); - } - - bool tautological = false; - - coveror.next.added = coveror.next.covered = 0; - - while (!tautological) { - if (coveror.next.added < coveror.added.size ()) { - const int lit = coveror.added[coveror.next.added++]; - tautological = cover_propagate_asymmetric (lit, c, coveror); - } else if (coveror.next.covered < coveror.covered.size ()) { - const int lit = coveror.covered[coveror.next.covered++]; - tautological = cover_propagate_covered (lit, coveror); - } else - break; - } - - if (tautological) { - if (coveror.extend.empty ()) { - stats.cover.asymmetric++; - stats.cover.total++; - LOG (c, "asymmetric tautological"); - } else { - stats.cover.blocked++; - stats.cover.total++; - // Only copy extension stack if successful. - int prev = INT_MIN; - bool already_pushed = false; - int64_t last_id = 0; - LOG (c, "covered tautological"); - CADICAL_assert (clause.empty ()); - LOG (coveror.extend, "extension = "); - for (const auto &other : coveror.extend) { - if (!prev) { - // are we finishing a clause? - if (already_pushed) { - // add missing literals that are not needed for covering - // but avoid RAT proofs - for (auto i = 0, j = 0; i < c->size; ++i, ++j) { - const int lit = c->literals[i]; - if (j >= (int) coveror.covered.size () || - c->literals[i] != coveror.covered[j]) { - --j; - LOG ("adding lit %d not needed for ATA", lit); - clause.push_back (lit); - external->push_clause_literal_on_extension_stack (lit); - } - } - } - if (proof && already_pushed) { - if (lrat) - lrat_chain.push_back (c->id); - LOG ("LEARNING clause with id %" PRId64, last_id); - proof->add_derived_clause (last_id, false, clause, lrat_chain); - proof->weaken_plus (last_id, clause); - lrat_chain.clear (); - } - last_id = ++clause_id; - external->push_zero_on_extension_stack (); - external->push_witness_literal_on_extension_stack (other); - external->push_zero_on_extension_stack (); - external->push_id_on_extension_stack (last_id); - external->push_zero_on_extension_stack (); - clause.clear (); - already_pushed = true; - } - if (other) { - external->push_clause_literal_on_extension_stack (other); - clause.push_back (other); - LOG (clause, "current clause is"); - } - prev = other; - } - - if (proof) { - // add missing literals that are not needed for covering - // but avoid RAT proofs - for (auto i = 0, j = 0; i < c->size; ++i, ++j) { - const int lit = c->literals[i]; - if (j >= (int) coveror.covered.size () || - c->literals[i] != coveror.covered[j]) { - --j; - LOG ("adding lit %d not needed for ATA", lit); - clause.push_back (lit); - external->push_clause_literal_on_extension_stack (lit); - } - } - if (lrat) - lrat_chain.push_back (c->id); - proof->add_derived_clause (last_id, false, clause, lrat_chain); - proof->weaken_plus (last_id, clause); - lrat_chain.clear (); - } - clause.clear (); - - mark_garbage (c); - } - } - - // Backtrack and 'unassign' all literals. - - CADICAL_assert (level == 1); - for (const auto &lit : coveror.added) - set_val (lit, 0); - level = 0; - - coveror.covered.clear (); - coveror.extend.clear (); - coveror.added.clear (); - - return tautological; -} - -/*------------------------------------------------------------------------*/ - -// Not yet tried and larger clauses are tried first. - -struct clause_covered_or_smaller { - bool operator() (const Clause *a, const Clause *b) { - if (a->covered && !b->covered) - return true; - if (!a->covered && b->covered) - return false; - return a->size < b->size; - } -}; - -int64_t Internal::cover_round () { - - if (unsat) - return 0; - - init_watches (); - connect_watches (true); // irredundant watches only is enough - - int64_t delta = stats.propagations.search; - delta *= 1e-3 * opts.covereffort; - if (delta < opts.covermineff) - delta = opts.covermineff; - if (delta > opts.covermaxeff) - delta = opts.covermaxeff; - delta = max (delta, ((int64_t) 2) * active ()); - - PHASE ("cover", stats.cover.count, - "covered clause elimination limit of %" PRId64 " propagations", - delta); - - int64_t limit = stats.propagations.cover + delta; - - init_occs (); - - vector schedule; - Coveror coveror; - - // First connect all clauses and find all not yet tried clauses. - // -#ifndef CADICAL_QUIET - int64_t untried = 0; -#endif - // - for (auto c : clauses) { - CADICAL_assert (!c->frozen); - if (c->garbage) - continue; - if (c->redundant) - continue; - bool satisfied = false, allfrozen = true; - for (const auto &lit : *c) - if (val (lit) > 0) { - satisfied = true; - break; - } else if (allfrozen && !frozen (lit)) - allfrozen = false; - if (satisfied) { - mark_garbage (c); - continue; - } - if (allfrozen) { - c->frozen = true; - continue; - } - for (const auto &lit : *c) - occs (lit).push_back (c); - if (c->size < opts.coverminclslim) - continue; - if (c->size > opts.covermaxclslim) - continue; - if (c->covered) - continue; - schedule.push_back (c); -#ifndef CADICAL_QUIET - untried++; -#endif - } - - if (schedule.empty ()) { - - PHASE ("cover", stats.cover.count, "no previously untried clause left"); - - for (auto c : clauses) { - if (c->garbage) - continue; - if (c->redundant) - continue; - if (c->frozen) { - c->frozen = false; - continue; - } - if (c->size < opts.coverminclslim) - continue; - if (c->size > opts.covermaxclslim) - continue; - CADICAL_assert (c->covered); - c->covered = false; - schedule.push_back (c); - } - } else { // Mix of tried and not tried clauses .... - - for (auto c : clauses) { - if (c->garbage) - continue; - if (c->redundant) - continue; - if (c->frozen) { - c->frozen = false; - continue; - } - if (c->size < opts.coverminclslim) - continue; - if (c->size > opts.covermaxclslim) - continue; - if (!c->covered) - continue; - schedule.push_back (c); - } - } - - stable_sort (schedule.begin (), schedule.end (), - clause_covered_or_smaller ()); - -#ifndef CADICAL_QUIET - const size_t scheduled = schedule.size (); - PHASE ("cover", stats.cover.count, - "scheduled %zd clauses %.0f%% with %" PRId64 " untried %.0f%%", - scheduled, percent (scheduled, stats.current.irredundant), untried, - percent (untried, scheduled)); -#endif - - // Heuristically it should be beneficial to intersect with smaller clauses - // first, since then the chances are higher that the intersection of - // resolution candidates becomes emptier earlier. - - for (auto lit : lits) { - if (!active (lit)) - continue; - Occs &os = occs (lit); - stable_sort (os.begin (), os.end (), clause_smaller_size ()); - } - - // This is the main loop of trying to do CCE of candidate clauses. - // - int64_t covered = 0; - // - while (!terminated_asynchronously () && !schedule.empty () && - stats.propagations.cover < limit) { - Clause *c = schedule.back (); - schedule.pop_back (); - c->covered = true; - if (cover_clause (c, coveror)) - covered++; - } - -#ifndef CADICAL_QUIET - const size_t remain = schedule.size (); - const size_t tried = scheduled - remain; - PHASE ("cover", stats.cover.count, - "eliminated %" PRId64 " covered clauses out of %zd tried %.0f%%", - covered, tried, percent (covered, tried)); - if (remain) - PHASE ("cover", stats.cover.count, - "remaining %zu clauses %.0f%% untried", remain, - percent (remain, scheduled)); - else - PHASE ("cover", stats.cover.count, "all scheduled clauses tried"); -#endif - reset_occs (); - reset_watches (); - - return covered; -} - -/*------------------------------------------------------------------------*/ - -bool Internal::cover () { - - if (!opts.cover) - return false; - if (unsat) - return false; - if (terminated_asynchronously ()) - return false; - if (!stats.current.irredundant) - return false; - - // TODO: Our current algorithm for producing the necessary clauses on the - // reconstruction stack for extending the witness requires a covered - // literal addition step which (empirically) conflicts with flushing - // during restoring clauses (see 'regr00{48,51}.trace') even though - // flushing during restore is disabled by default (as is covered clause - // elimination). The consequence of combining these two options - // ('opts.cover' and 'opts.restoreflush') can thus produce incorrect - // witness reconstruction and thus invalid witnesses. This is quite - // infrequent (one out of half billion mobical test cases) but as the two - // regression traces show, does happen. Thus we disable the combination. - // - if (opts.restoreflush) - return false; - - START_SIMPLIFIER (cover, COVER); - - stats.cover.count++; - - // During variable elimination unit clauses can be generated which need to - // be propagated properly over redundant clauses too. Since variable - // elimination avoids to have occurrence lists and watches at the same - // time this propagation is delayed until the end of variable elimination. - // Since we want to interleave CCE with it, we have to propagate here. - // Otherwise this triggers inconsistencies. - // - if (propagated < trail.size ()) { - init_watches (); - connect_watches (); // need to propagated over all clauses! - LOG ("elimination produced %zd units", - (size_t) (trail.size () - propagated)); - if (!propagate ()) { - LOG ("propagating units before covered clause elimination " - "results in empty clause"); - learn_empty_clause (); - CADICAL_assert (unsat); - } - reset_watches (); - } - CADICAL_assert (unsat || propagated == trail.size ()); - - int64_t covered = cover_round (); - - STOP_SIMPLIFIER (cover, COVER); - report ('c', !opts.reportall && !covered); - - return covered; -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_decide.cpp b/src/sat/cadical/cadical_decide.cpp deleted file mode 100644 index 0874cffd7..000000000 --- a/src/sat/cadical/cadical_decide.cpp +++ /dev/null @@ -1,258 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -// This function determines the next decision variable on the queue, without -// actually removing it from the decision queue, e.g., calling it multiple -// times without any assignment will return the same result. This is of -// course used below in 'decide' but also in 'reuse_trail' to determine the -// largest decision level to backtrack to during 'restart' without changing -// the assigned variables (if 'opts.restartreusetrail' is non-zero). - -int Internal::next_decision_variable_on_queue () { - int64_t searched = 0; - int res = queue.unassigned; - while (val (res)) - res = link (res).prev, searched++; - if (searched) { - stats.searched += searched; - update_queue_unassigned (res); - } - LOG ("next queue decision variable %d bumped %" PRId64 "", res, - bumped (res)); - return res; -} - -// This function determines the best decision with respect to score. -// -int Internal::next_decision_variable_with_best_score () { - int res = 0; - for (;;) { - res = scores.front (); - if (!val (res)) - break; - (void) scores.pop_front (); - } - LOG ("next decision variable %d with score %g", res, score (res)); - return res; -} - -int Internal::next_decision_variable () { - if (use_scores ()) - return next_decision_variable_with_best_score (); - else - return next_decision_variable_on_queue (); -} - -/*------------------------------------------------------------------------*/ - -// Implements phase saving as well using a target phase during -// stabilization unless decision phase is forced to the initial value -// of a phase is forced through the 'phase' option. - -int Internal::decide_phase (int idx, bool target) { - const int initial_phase = opts.phase ? 1 : -1; - int phase = 0; - if (force_saved_phase) - phase = phases.saved[idx]; - if (!phase) - phase = phases.forced[idx]; // swapped with opts.forcephase case! - if (!phase && opts.forcephase) - phase = initial_phase; - if (!phase && target) - phase = phases.target[idx]; - if (!phase) - phase = phases.saved[idx]; - - // The following should not be necessary and in some version we had even - // a hard 'COVER' CADICAL_assertion here to check for this. Unfortunately it - // triggered for some users and we could not get to the root cause of - // 'phase' still not being set here. The logic for phase and target - // saving is pretty complex, particularly in combination with local - // search, and to avoid running in such an issue in the future again, we - // now use this 'defensive' code here, even though such defensive code is - // considered bad programming practice. - // - if (!phase) - phase = initial_phase; - - return phase * idx; -} - -// The likely phase of an variable used in 'collect' for optimizing -// co-location of clauses likely accessed together during search. - -int Internal::likely_phase (int idx) { return decide_phase (idx, false); } - -/*------------------------------------------------------------------------*/ - -// adds new level to control and trail -// -void Internal::new_trail_level (int lit) { - level++; - control.push_back (Level (lit, trail.size ())); -} - -/*------------------------------------------------------------------------*/ - -bool Internal::satisfied () { - if ((size_t) level < assumptions.size () + (!!constraint.size ())) - return false; - if (num_assigned < (size_t) max_var) - return false; - CADICAL_assert (num_assigned == (size_t) max_var); - if (propagated < trail.size ()) - return false; - size_t assigned = num_assigned; - return (assigned == (size_t) max_var); -} - -bool Internal::better_decision (int lit, int other) { - int lit_idx = abs (lit); - int other_idx = abs (other); - if (stable) - return stab[lit_idx] > stab[other_idx]; - else - return btab[lit_idx] > btab[other_idx]; -} - -// Search for the next decision and assign it to the saved phase. Requires -// that not all variables are assigned. - -int Internal::decide () { - CADICAL_assert (!satisfied ()); - START (decide); - int res = 0; - if ((size_t) level < assumptions.size ()) { - const int lit = assumptions[level]; - CADICAL_assert (assumed (lit)); - const signed char tmp = val (lit); - if (tmp < 0) { - LOG ("assumption %d falsified", lit); - res = 20; - } else if (tmp > 0) { - LOG ("assumption %d already satisfied", lit); - new_trail_level (0); - LOG ("added pseudo decision level"); - notify_decision (); - } else { - LOG ("deciding assumption %d", lit); - search_assume_decision (lit); - } - } else if ((size_t) level == assumptions.size () && constraint.size ()) { - - int satisfied_lit = 0; // The literal satisfying the constrain. - int unassigned_lit = 0; // Highest score unassigned literal. - int previous_lit = 0; // Move satisfied literals to the front. - - const size_t size_constraint = constraint.size (); - -#ifndef CADICAL_NDEBUG - unsigned sum = 0; - for (auto lit : constraint) - sum += lit; -#endif - for (size_t i = 0; i != size_constraint; i++) { - - // Get literal and move 'constraint[i] = constraint[i-1]'. - - int lit = constraint[i]; - constraint[i] = previous_lit; - previous_lit = lit; - - const signed char tmp = val (lit); - if (tmp < 0) { - LOG ("constraint literal %d falsified", lit); - continue; - } - - if (tmp > 0) { - LOG ("constraint literal %d satisfied", lit); - satisfied_lit = lit; - break; - } - - CADICAL_assert (!tmp); - LOG ("constraint literal %d unassigned", lit); - - if (!unassigned_lit || better_decision (lit, unassigned_lit)) - unassigned_lit = lit; - } - - if (satisfied_lit) { - - constraint[0] = satisfied_lit; // Move satisfied to the front. - - LOG ("literal %d satisfies constraint and " - "is implied by assumptions", - satisfied_lit); - - new_trail_level (0); - LOG ("added pseudo decision level for constraint"); - notify_decision (); - - } else { - - // Just move all the literals back. If we found an unsatisfied - // literal then it will be satisfied (most likely) at the next - // decision and moved then to the first position. - - if (size_constraint) { - - for (size_t i = 0; i + 1 != size_constraint; i++) - constraint[i] = constraint[i + 1]; - - constraint[size_constraint - 1] = previous_lit; - } - - if (unassigned_lit) { - - LOG ("deciding %d to satisfy constraint", unassigned_lit); - search_assume_decision (unassigned_lit); - - } else { - - LOG ("failing constraint"); - unsat_constraint = true; - res = 20; - } - } - -#ifndef CADICAL_NDEBUG - for (auto lit : constraint) - sum -= lit; - CADICAL_assert (!sum); // Checksum of literal should not change! -#endif - - } else { - - int decision = ask_decision (); - if ((size_t) level < assumptions.size () || - ((size_t) level == assumptions.size () && constraint.size ())) { - // Forced backtrack below pseudo decision levels. - // So one of the two branches above will handle it. - STOP (decide); - res = decide (); // STARTS and STOPS profiling - START (decide); - } else { - stats.decisions++; - if (!decision) { - int idx = next_decision_variable (); - const bool target = (opts.target > 1 || (stable && opts.target)); - decision = decide_phase (idx, target); - } - search_assume_decision (decision); - } - } - if (res) - marked_failed = false; - STOP (decide); - return res; -} -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_decompose.cpp b/src/sat/cadical/cadical_decompose.cpp deleted file mode 100644 index 9081321b4..000000000 --- a/src/sat/cadical/cadical_decompose.cpp +++ /dev/null @@ -1,739 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -void Internal::decompose_analyze_binary_chain (DFS *dfs, int from) { - if (!lrat) - return; - LOG ("binary chain starting at %d", from); - DFS &from_dfs = dfs[vlit (from)]; - Clause *reason = from_dfs.parent; - if (!reason) - return; - CADICAL_assert (reason->size == 2); - mini_chain.push_back (reason->id); - int other = reason->literals[0]; - other = other == from ? -reason->literals[1] : -other; - Flags &f = flags (other); - if (f.seen) - return; - f.seen = true; - analyzed.push_back (other); - decompose_analyze_binary_chain (dfs, other); -} - -vector Internal::decompose_analyze_binary_clauses (DFS *dfs, - int from) { - vector result; - LOG ("binary chain starting at %d", from); - DFS &from_dfs = dfs[vlit (from)]; - Clause *reason = from_dfs.parent; - while (reason) { - result.push_back (reason); - CADICAL_assert (reason->size == 2); - int other = reason->literals[0]; - other = other == from ? -reason->literals[1] : -other; - Flags &f = flags (other); - if (f.seen) - break; - f.seen = true; - analyzed.push_back (other); - from = other; - DFS &from_dfs = dfs[vlit (from)]; - reason = from_dfs.parent; - } - return result; -} - -void Internal::decompose_conflicting_scc_lrat (DFS *dfs, vector &scc) { - if (!lrat) - return; - CADICAL_assert (lrat_chain.empty ()); - CADICAL_assert (mini_chain.empty ()); - for (auto &lit : scc) { - Flags &f = flags (lit); - if (f.seen) - return; - f.seen = true; - analyzed.push_back (lit); - decompose_analyze_binary_chain (dfs, lit); - for (auto p = mini_chain.rbegin (); p != mini_chain.rend (); p++) { - lrat_chain.push_back (*p); - } - mini_chain.clear (); - } - clear_analyzed_literals (); -} - -void Internal::build_lrat_for_clause ( - const vector> &dfs_chains, bool invert) { - CADICAL_assert (lrat); - LOG ("building chain for not subsumed clause"); - CADICAL_assert (lrat_chain.empty ()); - CADICAL_assert (sign_marked.empty ()); - // build chain for each replaced literal - for (const auto lit : clause) { - auto other = lit; - if (val (other) > 0) { - if (marked_decomposed (other)) - continue; - mark_decomposed (other); - int64_t id = unit_id (other); - lrat_chain.push_back (id); - continue; - } - CADICAL_assert (mini_chain.empty ()); - for (auto p : dfs_chains[vlit (other)]) { - if (marked_decomposed (other)) - continue; - mark_decomposed (other); - int implied = p->literals[0]; - implied = implied == other ? -p->literals[1] : -implied; - LOG ("ADDED %d -> %d (%" PRId64 ")", implied, other, p->id); - other = implied; - mini_chain.push_back (p->id); - if (val (implied) <= 0) - continue; - if (marked_decomposed (implied)) - break; - mark_decomposed (implied); - int64_t id = unit_id (implied); - mini_chain.push_back (id); - break; - } - if (invert) - for (auto p = mini_chain.rbegin (); p != mini_chain.rend (); p++) - lrat_chain.push_back (*p); - else - for (auto p = mini_chain.begin (); p != mini_chain.end (); p++) - lrat_chain.push_back (*p); - mini_chain.clear (); - } - clear_sign_marked_literals (); - LOG (lrat_chain, "lrat_chain:"); -} - -void Internal::clear_sign_marked_literals () { - LOG ("clearing %zd marked literals", sign_marked.size ()); - for (const auto &lit : sign_marked) { - // CADICAL_assert (marked_signed (lit)); violated on purpose in factor - unmark_decomposed (lit); - } - sign_marked.clear (); -} - -// This performs one round of Tarjan's algorithm, e.g., equivalent literal -// detection and substitution, on the whole formula. We might want to -// repeat it since its application might produce new binary clauses or -// units. Such units might even result in an empty clause. - -bool Internal::decompose_round () { - - if (!opts.decompose) - return false; - if (unsat) - return false; - if (terminated_asynchronously ()) - return false; - - CADICAL_assert (!level); - - START_SIMPLIFIER (decompose, DECOMP); - - stats.decompositions++; - - const size_t size_dfs = 2 * (1 + (size_t) max_var); - DFS *dfs = new DFS[size_dfs]; - DeferDeleteArray dfs_delete (dfs); - int *reprs = new int[size_dfs]; - DeferDeleteArray reprs_delete (reprs); - clear_n (reprs, size_dfs); - vector> dfs_chains; - dfs_chains.resize (size_dfs); - if (lrat) { - for (size_t i = 0; i > size_dfs; i++) { - vector empty; - dfs_chains[i] = empty; - } - } - - int substituted = 0; -#ifndef CADICAL_QUIET - int non_trivial_sccs = 0; - int before = active (); -#endif - unsigned dfs_idx = 0; - - vector work; // depth first search working stack - vector scc; // collects members of one SCC - - // The binary implication graph might have disconnected components and - // thus we have in general to start several depth first searches. - - for (auto root_idx : vars) { - if (unsat) - break; - if (!active (root_idx)) - continue; - for (int root_sign = -1; !unsat && root_sign <= 1; root_sign += 2) { - int root = root_sign * root_idx; - if (dfs[vlit (root)].min == TRAVERSED) - continue; // skip traversed - LOG ("new dfs search starting at root %d", root); - CADICAL_assert (work.empty ()); - CADICAL_assert (scc.empty ()); - work.push_back (root); - while (!unsat && !work.empty ()) { - int parent = work.back (); - DFS &parent_dfs = dfs[vlit (parent)]; - if (parent_dfs.min == TRAVERSED) { // skip traversed - CADICAL_assert (reprs[vlit (parent)]); - work.pop_back (); - } else { - CADICAL_assert (!reprs[vlit (parent)]); - - // Go over all implied literals, thus need to iterate over all - // binary watched clauses with the negation of 'parent'. - - Watches &ws = watches (-parent); - - // Two cases: Either the node has never been visited before, i.e., - // it's depth first search index is zero, then perform the - // 'pre-fix' work before visiting it's children. Otherwise all - // it's children and nodes reachable from those children have been - // visited and their minimum reachable depth first search index - // has been computed. This second case is the 'post-fix' work. - - if (parent_dfs.idx) { // post-fix - - work.pop_back (); // 'parent' done - - // Get the minimum reachable depth first search index reachable - // from the children of 'parent'. - - unsigned new_min = parent_dfs.min; - - for (const auto &w : ws) { - if (!w.binary ()) - continue; - const int child = w.blit; - if (!active (child)) - continue; - DFS &child_dfs = dfs[vlit (child)]; - if (new_min > child_dfs.min) - new_min = child_dfs.min; - } - - LOG ("post-fix work dfs search %d index %u reaches minimum %u", - parent, parent_dfs.idx, new_min); - - if (parent_dfs.idx == new_min) { // entry to SCC - - // All nodes on the 'scc' stack after and including 'parent' - // are in the same SCC. Their representative is computed as - // the smallest literal (index-wise) in the SCC. If the SCC - // contains both a literal and its negation, then the formula - // becomes unsatisfiable. - - if (lrat) { - CADICAL_assert (analyzed.empty ()); - int other, first = 0; - bool conflicting = false; - size_t j = scc.size (); - do { - CADICAL_assert (j > 0); - other = scc[--j]; - if (!first || vlit (other) < vlit (first)) - first = other; - Flags &f = flags (other); - if (other == -parent) { - conflicting = true; // conflicting scc - } - if (f.seen) { - continue; // also conflicting scc - } - f.seen = true; - analyzed.push_back (other); - } while (other != parent); - - CADICAL_assert (!conflicting || first > 0); - vector to_justify; - if (conflicting) { - LOG ("conflicting scc simulating up at %d", parent); - to_justify.push_back (-parent); - } else - to_justify.push_back (first); - while (!to_justify.empty ()) { - const int next = to_justify.back (); - to_justify.pop_back (); - Watches &next_ws = watches (-next); - for (const auto &w : next_ws) { - if (!w.binary ()) - continue; - const int child = w.blit; - if (!active (child)) - continue; - if (!flags (child).seen) - continue; - DFS &child_dfs = dfs[vlit (child)]; - if (child_dfs.parent) - continue; - child_dfs.parent = w.clause; - to_justify.push_back (child); - } - } - - clear_analyzed_literals (); - } - - int other, repr = parent; -#ifndef CADICAL_QUIET - int size = 0; -#endif - CADICAL_assert (!scc.empty ()); - size_t j = scc.size (); - do { - CADICAL_assert (j > 0); - other = scc[--j]; - if (other == -parent) { - LOG ("both %d and %d in one SCC", parent, -parent); - if (lrat) { - Flags &f = flags (-parent); - f.seen = true; - analyzed.push_back (-parent); - decompose_analyze_binary_chain (dfs, parent); - for (auto p : mini_chain) - lrat_chain.push_back (p); - mini_chain.clear (); - } - assign_unit (parent); -#ifndef CADICAL_NDEBUG - bool ok = -#endif - propagate (); - CADICAL_assert (!ok); - learn_empty_clause (); - lrat_chain.clear (); - } else { - if (abs (other) < abs (repr)) - repr = other; -#ifndef CADICAL_QUIET - size++; -#endif - } - } while (!unsat && other != parent); - - if (unsat) - break; -#ifndef CADICAL_QUIET - LOG ("SCC of representative %d of size %d", repr, size); -#endif - do { - CADICAL_assert (!scc.empty ()); - other = scc.back (); - scc.pop_back (); - dfs[vlit (other)].min = TRAVERSED; - if (frozen (other)) { - reprs[vlit (other)] = other; - continue; - } - reprs[vlit (other)] = repr; - if (other == repr) - continue; - substituted++; - LOG ("literal %d in SCC of %d", other, repr); - if (!lrat) - continue; - CADICAL_assert (mini_chain.empty ()); - Flags &f = flags (repr); - f.seen = true; - analyzed.push_back (repr); - // no need to reverse dfs_chain because this is handled by - // build_lrat_for_clause. - dfs_chains[vlit (other)] = - decompose_analyze_binary_clauses (dfs, other); - clear_analyzed_literals (); - } while (other != parent); - -#ifndef CADICAL_QUIET - if (size > 1) - non_trivial_sccs++; -#endif - - } else { - - // Current node 'parent' is in a non-trivial SCC but is not - // the entry point of the SCC in this depth first search, so - // keep it on the SCC stack until the entry point is reached. - - parent_dfs.min = new_min; - } - - } else { // pre-fix - - dfs_idx++; - CADICAL_assert (dfs_idx < TRAVERSED); - parent_dfs.idx = parent_dfs.min = dfs_idx; - scc.push_back (parent); - - LOG ("pre-fix work dfs search %d index %u", parent, dfs_idx); - - // Now traverse all the children in the binary implication - // graph but keep 'parent' on the stack for 'post-fix' work. - - for (const auto &w : ws) { - if (!w.binary ()) - continue; - const int child = w.blit; - if (!active (child)) - continue; - DFS &child_dfs = dfs[vlit (child)]; - if (child_dfs.idx) - continue; - work.push_back (child); - } - } - } - } - } - } - - erase_vector (work); - erase_vector (scc); - // delete [] dfs; need to postpone until after changing clauses... - - // Only keep the representatives 'repr' mapping. - - PHASE ("decompose", stats.decompositions, - "%d non-trivial sccs, %d substituted %.2f%%", non_trivial_sccs, - substituted, percent (substituted, before)); - - bool new_unit = false, new_binary_clause = false; - - // Finally, mark substituted literals as such and push the equivalences of - // the substituted literals to their representative on the extension - // stack to fix an assignment during 'extend'. - // It is also necessary to do so for proper IDRUP/LIDRUP/Resolution proofs - - vector decompose_ids; - const size_t size = 2 * (1 + (size_t) max_var); - decompose_ids.resize (size); - - for (auto idx : vars) { - if (!substituted) - break; - if (unsat) - break; - if (!active (idx)) - continue; - int other = reprs[vlit (idx)]; - if (other == idx) - continue; - CADICAL_assert (!flags (other).eliminated ()); - CADICAL_assert (!flags (other).substituted ()); - - LOG ("marking equivalence of %d and %d", idx, other); - CADICAL_assert (clause.empty ()); - CADICAL_assert (lrat_chain.empty ()); - clause.push_back (other); - clause.push_back (-idx); - if (lrat) { - build_lrat_for_clause (dfs_chains); - CADICAL_assert (!lrat_chain.empty ()); - } - - const int64_t id1 = ++clause_id; - if (proof) { - proof->add_derived_clause (id1, false, clause, lrat_chain); - proof->weaken_minus (id1, clause); - } - external->push_binary_clause_on_extension_stack (id1, -idx, other); - - decompose_ids[vlit (-idx)] = id1; - - lrat_chain.clear (); - clause.clear (); - - CADICAL_assert (clause.empty ()); - CADICAL_assert (lrat_chain.empty ()); - clause.push_back (idx); - clause.push_back (-other); - if (lrat) { - build_lrat_for_clause (dfs_chains); - CADICAL_assert (!lrat_chain.empty ()); - } - const int64_t id2 = ++clause_id; - if (proof) { - proof->add_derived_clause (id2, false, clause, lrat_chain); - proof->weaken_minus (id2, clause); - } - external->push_binary_clause_on_extension_stack (id2, idx, -other); - decompose_ids[vlit (idx)] = id2; - - clause.clear (); - lrat_chain.clear (); - } - - vector postponed_garbage; - - // Now go over all clauses and find clause which contain literals that - // should be substituted by their representative. - - size_t clauses_size = clauses.size (); -#ifndef CADICAL_QUIET - size_t garbage = 0, replaced = 0; -#endif - for (size_t i = 0; substituted && !unsat && i < clauses_size; i++) { - Clause *c = clauses[i]; - if (c->garbage) - continue; - int j, size = c->size; - for (j = 0; j < size; j++) { - const int lit = c->literals[j]; - if (reprs[vlit (lit)] != lit) - break; - } - - if (j == size) - continue; - -#ifndef CADICAL_QUIET - replaced++; -#endif - LOG (c, "first substituted literal %d in", substituted); - - // Now copy the result to 'clause'. Substitute literals if they have a - // different representative. Skip duplicates and false literals. If a - // literal occurs in both phases or is assigned to true the clause is - // satisfied and can be marked as garbage. - - CADICAL_assert (clause.empty ()); - CADICAL_assert (lrat_chain.empty ()); - CADICAL_assert (analyzed.empty ()); - bool satisfied = false; - - for (int k = 0; !satisfied && k < size; k++) { - const int lit = c->literals[k]; - signed char tmp = val (lit); - if (tmp > 0) - satisfied = true; - else if (tmp < 0) { - if (!lrat) - continue; - Flags &f = flags (lit); - if (f.seen) - continue; - f.seen = true; - analyzed.push_back (lit); - int64_t id = unit_id (-lit); - lrat_chain.push_back (id); - continue; - } else { - const int other = reprs[vlit (lit)]; - tmp = val (other); - if (tmp < 0) { - if (!lrat) - continue; - Flags &f = flags (other); - if (!f.seen) { - f.seen = true; - analyzed.push_back (other); - int64_t id = unit_id (-other); - lrat_chain.push_back (id); - } - if (other == lit) - continue; - int64_t id = decompose_ids[vlit (-lit)]; - CADICAL_assert (id); - lrat_chain.push_back (id); - continue; - } else if (tmp > 0) - satisfied = true; - else { - tmp = marked (other); - if (tmp < 0) - satisfied = true; - else if (!tmp) { - mark (other); - clause.push_back (other); - } - if (other == lit) - continue; - if (!lrat) - continue; - int64_t id = decompose_ids[vlit (-lit)]; - CADICAL_assert (id); - lrat_chain.push_back (id); - } - } - } - if (lrat) - lrat_chain.push_back (c->id); - clear_analyzed_literals (); - LOG (lrat_chain, "lrat_chain:"); - if (satisfied) { - LOG (c, "satisfied after substitution (postponed)"); - postponed_garbage.push_back (c); -#ifndef CADICAL_QUIET - garbage++; -#endif - } else if (!clause.size ()) { - LOG ("learned empty clause during decompose"); - learn_empty_clause (); - } else if (clause.size () == 1) { - LOG (c, "unit %d after substitution", clause[0]); - assign_unit (clause[0]); - mark_garbage (c); - new_unit = true; -#ifndef CADICAL_QUIET - garbage++; -#endif - } else if (c->literals[0] != clause[0] || c->literals[1] != clause[1]) { - LOG ("need new clause since at least one watched literal changed"); - if (clause.size () == 2) - new_binary_clause = true; - size_t d_clause_idx = clauses.size (); - Clause *d = new_clause_as (c); - CADICAL_assert (clauses[d_clause_idx] == d); - clauses[d_clause_idx] = c; - clauses[i] = d; - mark_garbage (c); -#ifndef CADICAL_QUIET - garbage++; -#endif - } else { - LOG ("simply shrinking clause since watches did not change"); - CADICAL_assert (c->size > 2); - if (!c->redundant) - mark_removed (c); - if (proof) { - proof->add_derived_clause (++clause_id, c->redundant, clause, - lrat_chain); - proof->delete_clause (c); - c->id = clause_id; - } - size_t l; - int *literals = c->literals; - for (l = 2; l < clause.size (); l++) - literals[l] = clause[l]; - int flushed = c->size - (int) l; - if (flushed) { - if (l == 2) - new_binary_clause = true; - LOG ("flushed %d literals", flushed); - (void) shrink_clause (c, l); - } else if (likely_to_be_kept_clause (c)) - mark_added (c); - // we have shrunken c->size to l so even though there is an CADICAL_assertion - // for c->size > 2 at the beginning of this else block, the new size - // can be 2 now. - if (c->size == 2) { // cheaper to update only new binary clauses - CADICAL_assert (new_binary_clause); - update_watch_size (watches (c->literals[0]), c->literals[1], c); - update_watch_size (watches (c->literals[1]), c->literals[0], c); - } - LOG (c, "substituted"); - } - while (!clause.empty ()) { - int lit = clause.back (); - clause.pop_back (); - CADICAL_assert (marked (lit) > 0); - unmark (lit); - } - lrat_chain.clear (); - } - - if (proof) { - for (auto idx : vars) { - if (!substituted) - break; - if (!active (idx)) - continue; - const int64_t id1 = decompose_ids[vlit (-idx)]; - if (!id1) - continue; - int other = reprs[vlit (idx)]; - CADICAL_assert (other != idx); - CADICAL_assert (!flags (other).eliminated ()); - CADICAL_assert (!flags (other).substituted ()); - - clause.push_back (other); - clause.push_back (-idx); - proof->delete_clause (id1, false, clause); - clause.clear (); - - clause.push_back (idx); - clause.push_back (-other); - const int64_t id2 = decompose_ids[vlit (idx)]; - proof->delete_clause (id2, false, clause); - clause.clear (); - } - } - - if (!unsat && !postponed_garbage.empty ()) { - LOG ("now marking %zd postponed garbage clauses", - postponed_garbage.size ()); - for (const auto &c : postponed_garbage) - mark_garbage (c); - } - erase_vector (postponed_garbage); - - PHASE ("decompose", stats.decompositions, - "%zd clauses replaced %.2f%% producing %zd garbage clauses %.2f%%", - replaced, percent (replaced, clauses_size), garbage, - percent (garbage, replaced)); - - erase_vector (scc); - - // Propagate found units. - - if (!unsat && propagated < trail.size () && !propagate ()) { - LOG ("empty clause after propagating units from substitution"); - learn_empty_clause (); - } - - for (auto idx : vars) { - if (!substituted) - break; - if (unsat) - break; - if (!active (idx)) - continue; - int other = reprs[vlit (idx)]; - if (other == idx) - continue; - CADICAL_assert (!flags (other).eliminated ()); - CADICAL_assert (!flags (other).substituted ()); - if (!flags (other).fixed ()) - mark_substituted (idx); - } - - reprs_delete.free (); - dfs_delete.free (); - erase_vector (dfs_chains); - - if (substituted) - flush_all_occs_and_watches (); // particularly the 'blit's - - bool success = - unsat || (substituted > 0 && (new_unit || new_binary_clause)); - report ('d', !opts.reportall && !success); - - STOP_SIMPLIFIER (decompose, DECOMP); - - return success; -} - -void Internal::decompose () { - for (int round = 1; round <= opts.decomposerounds; round++) - if (!decompose_round ()) - break; -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_deduplicate.cpp b/src/sat/cadical/cadical_deduplicate.cpp deleted file mode 100644 index 49d26a571..000000000 --- a/src/sat/cadical/cadical_deduplicate.cpp +++ /dev/null @@ -1,176 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -// Equivalent literal substitution in 'decompose' and shrinking in 'subsume' -// or 'vivify' might produce duplicated binary clauses. They can not be -// found in 'subsume' nor 'vivify' since we explicitly do not consider -// binary clauses as candidates to be shrunken or subsumed. They are -// detected here by a simple scan of watch lists and then marked as garbage. -// This is actually also quite fast. - -// Further it might also be possible that two binary clauses can be resolved -// to produce a unit (we call it 'hyper unary resolution'). For example -// resolving the binary clauses '1 -2' and '1 2' produces the unit '1'. -// This could be found by probing in 'probe' unless '-1' also occurs in a -// binary clause (add the clause '-1 2' to those two clauses) in which case -// '1' as well as '2' both occur positively as well as negatively and none -// of them nor their negation is considered as probe - -void Internal::mark_duplicated_binary_clauses_as_garbage () { - - if (!opts.deduplicate) - return; - if (unsat) - return; - if (terminated_asynchronously ()) - return; - - START_SIMPLIFIER (deduplicate, DEDUP); - stats.deduplications++; - - CADICAL_assert (!level); - CADICAL_assert (watching ()); - - vector stack; // To save marked literals and unmark them later. - - int64_t subsumed = 0; - int64_t units = 0; - - for (auto idx : vars) { - - if (unsat) - break; - if (!active (idx)) - continue; - int unit = 0; - - for (int sign = -1; !unit && sign <= 1; sign += 2) { - - const int lit = sign * idx; // Consider all literals. - - CADICAL_assert (stack.empty ()); - Watches &ws = watches (lit); - - // We are removing references to garbage clause. Thus no 'auto'. - - const const_watch_iterator end = ws.end (); - watch_iterator j = ws.begin (); - const_watch_iterator i; - - for (i = j; !unit && i != end; i++) { - Watch w = *j++ = *i; - if (!w.binary ()) - continue; - int other = w.blit; - const int tmp = marked (other); - Clause *c = w.clause; - - if (tmp > 0) { // Found duplicated binary clause. - - if (c->garbage) { - j--; - continue; - } - LOG (c, "found duplicated"); - - // The previous identical clause 'd' might be redundant and if the - // second clause 'c' is not (so irredundant), then we have to keep - // 'c' instead of 'd', thus we search for it and replace it. - - if (!c->redundant) { - watch_iterator k; - for (k = ws.begin ();; k++) { - CADICAL_assert (k != i); - if (!k->binary ()) - continue; - if (k->blit != other) - continue; - Clause *d = k->clause; - if (d->garbage) - continue; - c = d; - break; - } - *k = w; - } - - LOG (c, "mark garbage duplicated"); - stats.subsumed++; - stats.deduplicated++; - subsumed++; - mark_garbage (c); - j--; - - } else if (tmp < 0) { // Hyper unary resolution. - - LOG ("found %d %d and %d %d which produces unit %d", lit, -other, - lit, other, lit); - unit = lit; - if (lrat) { - // taken from fradical - CADICAL_assert (lrat_chain.empty ()); - lrat_chain.push_back (c->id); - // We've forgotten where the other binary clause is, so go find - // it again - for (watch_iterator k = ws.begin ();; k++) { - CADICAL_assert (k != i); - if (!k->binary ()) - continue; - if (k->blit != -other) - continue; - lrat_chain.push_back (k->clause->id); - break; - } - } - j = ws.begin (); // Flush 'ws'. - units++; - - } else { - if (c->garbage) - continue; - mark (other); - stack.push_back (other); - } - } - - if (j == ws.begin ()) - erase_vector (ws); - else if (j != end) - ws.resize (j - ws.begin ()); // Shrink watchers. - - for (const auto &other : stack) - unmark (other); - - stack.clear (); - } - - // Propagation potentially messes up the watches and thus we can not - // propagate the unit immediately after finding it. Instead we break - // out of both loops and assign and propagate the unit here. - - if (unit) { - - stats.failed++; - stats.hyperunary++; - assign_unit (unit); - // lrat_chain.clear (); done in search_assign - - if (!propagate ()) { - LOG ("empty clause after propagating unit"); - learn_empty_clause (); - } - } - } - STOP_SIMPLIFIER (deduplicate, DEDUP); - - report ('2', !opts.reportall && !(subsumed + units)); -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_definition.cpp b/src/sat/cadical/cadical_definition.cpp deleted file mode 100644 index 7c8fe4fbb..000000000 --- a/src/sat/cadical/cadical_definition.cpp +++ /dev/null @@ -1,289 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -#define INVALID_LIT UINT_MAX - -// functions below are passed to cadical_kitten -// -struct definition_extractor { - Eliminator *eliminator; - Internal *internal; - vector clauses[2]; - int lit; - vector> implicants; - int unit; -}; - -extern "C" { - -// used to extract definitions from cadical_kitten -// -static void traverse_definition_core (void *state, unsigned id) { - definition_extractor *extractor = (definition_extractor *) state; - Clause *clause; - const vector &clauses0 = extractor->clauses[0]; - const vector &clauses1 = extractor->clauses[1]; - Eliminator *eliminator = extractor->eliminator; - const size_t size_clauses0 = clauses0.size (); - const size_t size_clauses1 = clauses1.size (); - CADICAL_assert (size_clauses0 <= UINT_MAX); - unsigned sign; - CADICAL_assert (id < size_clauses0 + size_clauses1); - if (id < size_clauses0) { - clause = clauses0[id]; - sign = 1; - } else { - unsigned tmp = id - size_clauses0; -#ifndef CADICAL_NDEBUG - CADICAL_assert (size_clauses1 <= UINT_MAX); - CADICAL_assert (tmp < size_clauses1); -#endif - clause = clauses1[tmp]; - sign = 2; - } - (void) size_clauses1; - clause->gate = true; - eliminator->gates.push_back (clause); -#ifdef LOGGING - Internal *internal = extractor->internal; - LOG (clause, "extracted gate"); -#endif - eliminator->definition_unit |= sign; -} - -// extracts relevant learned clauses from kissat for drat proofs -// -static void traverse_one_sided_core_lemma (void *state, bool learned, - size_t size, - const unsigned *lits) { - if (!learned) - return; - definition_extractor *extractor = (definition_extractor *) state; - Eliminator *eliminator = extractor->eliminator; - Internal *internal = extractor->internal; - Proof *proof = internal->proof; - const int unit = extractor->unit; - vector &proof_clauses = eliminator->proof_clauses; - if (size) { - proof_clause pc; - pc.id = ++(internal->clause_id); - pc.literals.push_back (unit); - const unsigned *end = lits + size; - for (const unsigned *p = lits; p != end; p++) - pc.literals.push_back (internal->citten2lit (*p)); // conversion - proof_clauses.push_back (pc); - CADICAL_assert (proof); - proof->add_derived_clause (pc.id, true, pc.literals, pc.chain); - } else { - internal->assign_unit (unit); - for (const auto &pc : proof_clauses) { - proof->delete_clause (pc.id, true, pc.literals); - } - proof_clauses.clear (); - } -} - -// extract lrat proofs for relevant clauses -// -static void traverse_one_sided_core_lemma_with_lrat ( - void *state, unsigned cid, unsigned id, bool learned, size_t size, - const unsigned *lits, size_t chain_size, const unsigned *chain) { - definition_extractor *extractor = (definition_extractor *) state; - Eliminator *eliminator = extractor->eliminator; - Internal *internal = extractor->internal; - Proof *proof = internal->proof; - const int unit = extractor->unit; - const vector &clauses0 = extractor->clauses[0]; - const vector &clauses1 = extractor->clauses[1]; - vector &proof_clauses = eliminator->proof_clauses; - if (!learned) { // remember clauses for mapping to cadical_kitten internal - CADICAL_assert (size); - CADICAL_assert (!chain_size); - proof_clause pc; - pc.cid = cid; - pc.learned = false; - const size_t size_clauses0 = clauses0.size (); - CADICAL_assert (size_clauses0 <= UINT_MAX); - if (id < size_clauses0) { - pc.id = clauses0[id]->id; - } else { - unsigned tmp = id - size_clauses0; -#ifndef CADICAL_NDEBUG - const size_t size_clauses1 = clauses1.size (); - CADICAL_assert (size_clauses1 <= UINT_MAX); - CADICAL_assert (tmp < size_clauses1); -#endif - pc.id = clauses1[tmp]->id; - } - proof_clauses.push_back (pc); - } else { // actually add to proof - CADICAL_assert (chain_size); - if (size) { - proof_clause pc; - pc.id = ++(internal->clause_id); - pc.cid = cid; - pc.learned = true; - pc.literals.push_back (unit); - const unsigned *end = lits + size; - for (const unsigned *p = lits; p != end; p++) - pc.literals.push_back (internal->citten2lit (*p)); // conversion - for (const unsigned *p = chain + chain_size; p != chain; p--) { - int64_t id = 0; - for (const auto &cpc : proof_clauses) { - if (cpc.cid == *(p - 1)) { - id = cpc.id; - break; - } - } - CADICAL_assert (id); - pc.chain.push_back (id); - } - proof_clauses.push_back (pc); - CADICAL_assert (proof); - proof->add_derived_clause (pc.id, true, pc.literals, pc.chain); - } else { // learn unit finish proof - CADICAL_assert (internal->lrat_chain.empty ()); - for (const unsigned *p = chain + chain_size; p != chain; p--) { - int64_t id = 0; - for (const auto &cpc : proof_clauses) { - if (cpc.cid == *(p - 1)) { - id = cpc.id; - break; - } - } - CADICAL_assert (id); - internal->lrat_chain.push_back (id); - } - internal->assign_unit (unit); - CADICAL_assert (internal->lrat_chain.empty ()); - for (const auto &pc : proof_clauses) { - if (pc.learned) - proof->delete_clause (pc.id, true, pc.literals); - } - proof_clauses.clear (); - } - } -} - -} // end extern C - -// Code ported from kissat. Kitten (and kissat) use unsigned representation -// for literals whereas CaDiCaL uses signed representation. Conversion is -// necessary for communication using lit2citten and citten2lit. -// This code is called in elim and cadical_kitten is initialized beforehand. -// To avoid confusion all cadical interal definitions with cadical_kitten are called -// citten. -// -void Internal::find_definition (Eliminator &eliminator, int lit) { - if (!opts.elimdef) - return; - if (unsat) - return; - if (val (lit)) - return; - if (!eliminator.gates.empty ()) - return; - CADICAL_assert (!val (lit)); - CADICAL_assert (!level); - CADICAL_assert (citten); - const int not_lit = -lit; - definition_extractor extractor; - extractor.lit = lit; - extractor.clauses[0] = occs (lit); - extractor.clauses[1] = occs (not_lit); - extractor.eliminator = &eliminator; - extractor.internal = internal; - citten_clear_track_log_terminate (); - unsigned exported = 0; - for (unsigned sign = 0; sign < 2; sign++) { - const unsigned except = sign ? lit2citten (not_lit) : lit2citten (lit); - for (auto c : extractor.clauses[sign]) { - // to avoid copying the literals of c in their unsigned - // representation we instead implement the translation in cadical_kitten - if (!c->garbage) { - LOG (c, "adding to cadical_kitten"); - citten_clause_with_id_and_exception (citten, exported, c->size, - c->literals, except); - } - exported++; - } - } - stats.definitions_checked++; - const size_t limit = opts.elimdefticks; - cadical_kitten_set_ticks_limit (citten, limit); - int status = cadical_kitten_solve (citten); - if (!exported) - goto ABORT; - if (status == 20) { - LOG ("sub-solver result UNSAT shows definition exists"); - uint64_t learned; - unsigned reduced = cadical_kitten_compute_clausal_core (citten, &learned); - LOG ("1st sub-solver core of size %u original clauses out of %u", - reduced, exported); - for (int i = 2; i <= opts.elimdefcores; i++) { - cadical_kitten_shrink_to_clausal_core (citten); - cadical_kitten_shuffle_clauses (citten); - cadical_kitten_set_ticks_limit (citten, 10 * limit); - int tmp = cadical_kitten_solve (citten); - CADICAL_assert (!tmp || tmp == 20); - if (!tmp) { - LOG ("aborting core extraction"); - goto ABORT; - } -#ifndef CADICAL_NDEBUG - unsigned previous = reduced; -#endif - reduced = cadical_kitten_compute_clausal_core (citten, &learned); - LOG ("%d sub-solver core of size %u original clauses out of %u", i, - reduced, exported); - CADICAL_assert (reduced <= previous); -#if not defined(LOGGING) && defined(CADICAL_NDEBUG) - (void) reduced; -#endif - } - stats.definitions_extracted++; - eliminator.gatetype = DEF; - eliminator.definition_unit = 0; - cadical_kitten_traverse_core_ids (citten, &extractor, traverse_definition_core); - CADICAL_assert (eliminator.definition_unit); - int unit = 0; - if (eliminator.definition_unit == 2) { - unit = not_lit; - } else if (eliminator.definition_unit == 1) - unit = lit; - - if (unit) { - stats.definition_units++; - VERBOSE (2, "one sided core " - "definition extraction yields " - "failed literal"); - if (proof) { - if (lrat) { - extractor.unit = unit; - cadical_kitten_trace_core (citten, &extractor, - traverse_one_sided_core_lemma_with_lrat); - } else { - extractor.unit = unit; - cadical_kitten_traverse_core_clauses (citten, &extractor, - traverse_one_sided_core_lemma); - } - } else - assign_unit (unit); - elim_propagate (eliminator, unit); - } - } else { - ABORT: - LOG ("sub-solver failed to show that definition exists"); - } - stats.definition_ticks += cadical_kitten_current_ticks (citten); - return; -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_drattracer.cpp b/src/sat/cadical/cadical_drattracer.cpp deleted file mode 100644 index eb73b4c95..000000000 --- a/src/sat/cadical/cadical_drattracer.cpp +++ /dev/null @@ -1,159 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -/*------------------------------------------------------------------------*/ - -DratTracer::DratTracer (Internal *i, File *f, bool b) - : internal (i), file (f), binary (b) -#ifndef CADICAL_QUIET - , - added (0), deleted (0) -#endif -{ - (void) internal; -} - -void DratTracer::connect_internal (Internal *i) { - internal = i; - file->connect_internal (internal); - LOG ("DRAT TRACER connected to internal"); -} - -DratTracer::~DratTracer () { - LOG ("DRAT TRACER delete"); - delete file; -} - -/*------------------------------------------------------------------------*/ - -inline void DratTracer::put_binary_zero () { - CADICAL_assert (binary); - CADICAL_assert (file); - file->put ((unsigned char) 0); -} - -inline void DratTracer::put_binary_lit (int lit) { - CADICAL_assert (binary); - CADICAL_assert (file); - CADICAL_assert (lit != INT_MIN); - unsigned idx = abs (lit); - CADICAL_assert (idx < (1u << 31)); - unsigned x = 2u * idx + (lit < 0); - unsigned char ch; - while (x & ~0x7f) { - ch = (x & 0x7f) | 0x80; - file->put (ch); - x >>= 7; - } - ch = x; - file->put (ch); -} - -/*------------------------------------------------------------------------*/ - -void DratTracer::drat_add_clause (const vector &clause) { - if (binary) - file->put ('a'); - for (const auto &external_lit : clause) - if (binary) - put_binary_lit (external_lit); - else - file->put (external_lit), file->put (' '); - if (binary) - put_binary_zero (); - else - file->put ("0\n"); -} -void DratTracer::drat_delete_clause (const vector &clause) { - if (binary) - file->put ('d'); - else - file->put ("d "); - for (const auto &external_lit : clause) - if (binary) - put_binary_lit (external_lit); - else - file->put (external_lit), file->put (' '); - if (binary) - put_binary_zero (); - else - file->put ("0\n"); -} - -/*------------------------------------------------------------------------*/ - -void DratTracer::add_derived_clause (int64_t, bool, - const vector &clause, - const vector &) { - if (file->closed ()) - return; - LOG ("DRAT TRACER tracing addition of derived clause"); - drat_add_clause (clause); -#ifndef CADICAL_QUIET - added++; -#endif -} - -void DratTracer::delete_clause (int64_t, bool, const vector &clause) { - if (file->closed ()) - return; - LOG ("DRAT TRACER tracing deletion of clause"); - drat_delete_clause (clause); -#ifndef CADICAL_QUIET - deleted++; -#endif -} - -/*------------------------------------------------------------------------*/ - -bool DratTracer::closed () { return file->closed (); } - -#ifndef CADICAL_QUIET - -void DratTracer::print_statistics () { - uint64_t bytes = file->bytes (); - uint64_t total = added + deleted; - MSG ("DRAT %" PRId64 " added clauses %.2f%%", added, - percent (added, total)); - MSG ("DRAT %" PRId64 " deleted clauses %.2f%%", deleted, - percent (deleted, total)); - MSG ("DRAT %" PRId64 " bytes (%.2f MB)", bytes, - bytes / (double) (1 << 20)); -} - -#endif - -void DratTracer::close (bool print) { - CADICAL_assert (!closed ()); - file->close (); -#ifndef CADICAL_QUIET - if (print) { - MSG ("DRAT proof file '%s' closed", file->name ()); - print_statistics (); - } -#else - (void) print; -#endif -} - -void DratTracer::flush (bool print) { - CADICAL_assert (!closed ()); - file->flush (); -#ifndef CADICAL_QUIET - if (print) { - MSG ("DRAT proof file '%s' flushed", file->name ()); - print_statistics (); - } -#else - (void) print; -#endif -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_elim.cpp b/src/sat/cadical/cadical_elim.cpp deleted file mode 100644 index 951dfee74..000000000 --- a/src/sat/cadical/cadical_elim.cpp +++ /dev/null @@ -1,1178 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -/*------------------------------------------------------------------------*/ - -// Implements a variant of bounded variable elimination as originally -// described in our SAT'05 paper introducing 'SATeLite'. This is an -// inprocessing version, i.e., it is interleaved with search and triggers -// subsumption and strengthening, blocked and covered clause elimination -// during elimination rounds. It focuses only those variables which -// occurred in removed irredundant clauses since the last time an -// elimination round was run. By bounding the maximum resolvent size we can -// run each elimination round until completion. See the code of 'elim' for -// how elimination rounds are interleaved with blocked clause elimination -// and subsumption (which in turn also calls vivification and transitive -// reduction of the binary implication graph). - -/*------------------------------------------------------------------------*/ - -inline double Internal::compute_elim_score (unsigned lit) { - CADICAL_assert (1 <= lit), CADICAL_assert (lit <= (unsigned) max_var); - const unsigned uidx = 2 * lit; - const double pos = internal->ntab[uidx]; - const double neg = internal->ntab[uidx + 1]; - if (!pos) - return -neg; - if (!neg) - return -pos; - double sum = 0, prod = 0; - if (opts.elimsum) - sum = opts.elimsum * (pos + neg); - if (opts.elimprod) - prod = opts.elimprod * (pos * neg); - return prod + sum; -} - -/*------------------------------------------------------------------------*/ - -bool elim_more::operator() (unsigned a, unsigned b) { - const auto s = internal->compute_elim_score (a); - const auto t = internal->compute_elim_score (b); - if (s > t) - return true; - if (s < t) - return false; - return a > b; -} - -/*------------------------------------------------------------------------*/ - -// Note that the new fast subsumption algorithm implemented in 'subsume' -// does not distinguish between irredundant and redundant clauses and is -// also run during search to strengthen and remove 'sticky' redundant -// clauses but also irredundant ones. So beside learned units during search -// or as consequence of other preprocessors, these subsumption rounds during -// search can remove (irredundant) clauses (and literals), which in turn -// might make new bounded variable elimination possible. This is tested -// in the 'bool ineliminating ()' guard. - -bool Internal::ineliminating () { - - if (!opts.elim) - return false; - if (!preprocessing && !opts.inprocessing) - return false; - if (preprocessing) - CADICAL_assert (lim.preprocessing); - - // Respect (increasing) conflict limit. - // - if (lim.elim >= stats.conflicts) - return false; - - // Wait until there are new units or new removed variables - // (in removed or shrunken irredundant clauses and thus marked). - // - if (last.elim.fixed < stats.all.fixed) - return true; - if (last.elim.marked < stats.mark.elim) - return true; - - // VERBOSE (3, "elim not scheduled due to fixpoint"); - return false; -} - -/*------------------------------------------------------------------------*/ - -// Update the global elimination schedule after adding or removing a clause. - -void Internal::elim_update_added_clause (Eliminator &eliminator, - Clause *c) { - CADICAL_assert (!c->redundant); - ElimSchedule &schedule = eliminator.schedule; - for (const auto &lit : *c) { - if (!active (lit)) - continue; - occs (lit).push_back (c); - if (frozen (lit)) - continue; - noccs (lit)++; - const int idx = abs (lit); - if (schedule.contains (idx)) - schedule.update (idx); - } -} - -void Internal::elim_update_removed_lit (Eliminator &eliminator, int lit) { - if (!active (lit)) - return; - if (frozen (lit)) - return; - int64_t &score = noccs (lit); - CADICAL_assert (score > 0); - score--; - const int idx = abs (lit); - ElimSchedule &schedule = eliminator.schedule; - if (schedule.contains (idx)) - schedule.update (idx); - else { - LOG ("rescheduling %d for elimination after removing clause", idx); - schedule.push_back (idx); - } -} - -void Internal::elim_update_removed_clause (Eliminator &eliminator, - Clause *c, int except) { - CADICAL_assert (!c->redundant); - for (const auto &lit : *c) { - if (lit == except) - continue; - CADICAL_assert (lit != -except); - elim_update_removed_lit (eliminator, lit); - } -} - -/*------------------------------------------------------------------------*/ - -// Since we do not have watches we have to do our own unit propagation -// during elimination as soon we find a unit clause. This finds new units -// and also marks clauses satisfied by those units as garbage immediately. - -void Internal::elim_propagate (Eliminator &eliminator, int root) { - CADICAL_assert (val (root) > 0); - vector work; - size_t i = 0; - work.push_back (root); - while (i < work.size ()) { - int lit = work[i++]; - LOG ("elimination propagation of %d", lit); - CADICAL_assert (val (lit) > 0); - const Occs &ns = occs (-lit); - for (const auto &c : ns) { - if (c->garbage) - continue; - int unit = 0, satisfied = 0; - for (const auto &other : *c) { - const signed char tmp = val (other); - if (tmp < 0) - continue; - if (tmp > 0) { - satisfied = other; - break; - } - if (unit) - unit = INT_MIN; - else - unit = other; - } - if (satisfied) { - LOG (c, "elimination propagation of %d finds %d satisfied", lit, - satisfied); - elim_update_removed_clause (eliminator, c, satisfied); - mark_garbage (c); - } else if (!unit) { - LOG ("empty clause during elimination propagation of %d", lit); - // need to set conflict = c for lrat - conflict = c; - learn_empty_clause (); - conflict = 0; - break; - } else if (unit != INT_MIN) { - LOG ("new unit %d during elimination propagation of %d", unit, lit); - build_chain_for_units (unit, c, 0); - assign_unit (unit); - work.push_back (unit); - } - } - if (unsat) - break; - const Occs &ps = occs (lit); - for (const auto &c : ps) { - if (c->garbage) - continue; - LOG (c, "elimination propagation of %d produces satisfied", lit); - elim_update_removed_clause (eliminator, c, lit); - mark_garbage (c); - } - } -} - -/*------------------------------------------------------------------------*/ - -// On-the-fly self-subsuming resolution during variable elimination is due -// to HyoJung Han, Fabio Somenzi, SAT'09. Basically while resolving two -// clauses we test the resolvent to be smaller than one of the antecedents. -// If this is the case the pivot can be removed from the antecedent -// on-the-fly and the resolution can be skipped during elimination. - -void Internal::elim_on_the_fly_self_subsumption (Eliminator &eliminator, - Clause *c, int pivot) { - LOG (c, "pivot %d on-the-fly self-subsuming resolution", pivot); - stats.elimotfstr++; - stats.strengthened++; - CADICAL_assert (clause.empty ()); - for (const auto &lit : *c) { - if (lit == pivot) - continue; - const signed char tmp = val (lit); - CADICAL_assert (tmp <= 0); - if (tmp < 0) - continue; - clause.push_back (lit); - } - Clause *r = new_resolved_irredundant_clause (); - elim_update_added_clause (eliminator, r); - clause.clear (); - lrat_chain.clear (); - elim_update_removed_clause (eliminator, c, pivot); - mark_garbage (c); -} - -/*------------------------------------------------------------------------*/ - -// Resolve two clauses on the pivot literal 'pivot', which is assumed to -// occur in opposite phases in 'c' and 'd'. The actual resolvent is stored -// in the temporary global 'clause' if it is not redundant. It is -// considered redundant if one of the clauses is already marked as garbage -// it is root level satisfied, the resolvent is empty, a unit, or produces a -// self-subsuming resolution, which results in the pivot to be removed from -// at least one of the antecedents. - -// Note that current root level assignments are taken into account, i.e., by -// removing root level falsified literals. The function returns true if the -// resolvent is not redundant and for instance has to be taken into account -// during bounded variable elimination. - -// Detected units are immediately assigned and in case the last argument is -// true also propagated eagerly in a elimination specific propagation -// routine, which not only finds units but also updates the schedule. - -// When this function is called during computation of the number of -// non-trivial (or non-satisfied) resolvents we can eagerly propagate units. -// But during actually adding the resolvents this results in problems as we -// found one rare test case '../test/trace/reg0056.trace' (out of billions), -// where the pivot itself was assigned during such a propagation while -// adding resolvents and lead to pushing a clause to the reconstruction -// stack that later flipped the value of the pivot (while all other literals -// in that clause were unit implied too). Not pushing the pivot clauses to -// the reconstruction stack produced a wrong model too. Our fix is to only -// eagerly propagate during computation of the number of resolvents and -// otherwise delay propagation until the end of elimination (which is less -// precise regarding scheduling but very rarely happens). - -bool Internal::resolve_clauses (Eliminator &eliminator, Clause *c, - int pivot, Clause *d, - const bool propagate_eagerly) { - - CADICAL_assert (!c->redundant); - CADICAL_assert (!d->redundant); - - stats.elimres++; - - if (c->garbage || d->garbage) - return false; - if (c->size > d->size) { - pivot = -pivot; - swap (c, d); - } - - CADICAL_assert (!level); - CADICAL_assert (clause.empty ()); - - int satisfied = 0; // Contains this satisfying literal. - int tautological = 0; // Clashing literal if tautological. - - int s = 0; // Actual literals from 'c'. - int t = 0; // Actual literals from 'd'. - - // First determine whether the first antecedent is satisfied, add its - // literals to 'clause' and mark them (except for 'pivot'). - // - for (const auto &lit : *c) { - if (lit == pivot) { - s++; - continue; - } - CADICAL_assert (lit != -pivot); - const signed char tmp = val (lit); - if (tmp > 0) { - satisfied = lit; - break; - } else if (tmp < 0) { - if (!lrat) - continue; - Flags &f = flags (lit); - if (f.seen) - continue; - analyzed.push_back (lit); - f.seen = true; - int64_t id = unit_id (-lit); - lrat_chain.push_back (id); - continue; - } else - mark (lit), clause.push_back (lit), s++; - } - if (satisfied) { - LOG (c, "satisfied by %d antecedent", satisfied); - elim_update_removed_clause (eliminator, c, satisfied); - mark_garbage (c); - clause.clear (); - lrat_chain.clear (); - clear_analyzed_literals (); - unmark (c); - return false; - } - - // Then determine whether the second antecedent is satisfied, add its - // literal to 'clause' and check whether a clashing literal is found, such - // that the resolvent would be tautological. - // - for (const auto &lit : *d) { - if (lit == -pivot) { - t++; - continue; - } - CADICAL_assert (lit != pivot); - signed char tmp = val (lit); - if (tmp > 0) { - satisfied = lit; - break; - } else if (tmp < 0) { - if (!lrat) - continue; - Flags &f = flags (lit); - if (f.seen) - continue; - analyzed.push_back (lit); - f.seen = true; - int64_t id = unit_id (-lit); - lrat_chain.push_back (id); - continue; - } else if ((tmp = marked (lit)) < 0) { - tautological = lit; - break; - } else if (!tmp) - clause.push_back (lit), t++; - else - CADICAL_assert (tmp > 0), t++; - } - - clear_analyzed_literals (); - unmark (c); - const int64_t size = clause.size (); - - if (lrat) { - lrat_chain.push_back (d->id); - lrat_chain.push_back (c->id); - } - - if (satisfied) { - LOG (d, "satisfied by %d antecedent", satisfied); - elim_update_removed_clause (eliminator, d, satisfied); - mark_garbage (d); - clause.clear (); - lrat_chain.clear (); - return false; - } - - LOG (c, "first antecedent"); - LOG (d, "second antecedent"); - - if (tautological) { - clause.clear (); - LOG ("resolvent tautological on %d", tautological); - lrat_chain.clear (); - return false; - } - - if (!size) { - clause.clear (); - LOG ("empty resolvent"); - learn_empty_clause (); // already clears lrat_chain. - return false; - } - - if (size == 1) { - int unit = clause[0]; - LOG ("unit resolvent %d", unit); - clause.clear (); - assign_unit (unit); // already clears lrat_chain. - if (propagate_eagerly) - elim_propagate (eliminator, unit); - return false; - } - - LOG (clause, "resolvent"); - CADICAL_assert (!lrat || !lrat_chain.empty ()); - - // Double self-subsuming resolution. The clauses 'c' and 'd' are - // identical except for the pivot which occurs in different phase. The - // resolvent subsumes both antecedents. - - if (s > size && t > size) { - CADICAL_assert (s == size + 1); - CADICAL_assert (t == size + 1); - clause.clear (); - // LRAT is c + d (+ eventual units) - elim_on_the_fly_self_subsumption (eliminator, c, pivot); - LOG (d, "double pivot %d on-the-fly self-subsuming resolution", -pivot); - stats.elimotfsub++; - stats.subsumed++; - elim_update_removed_clause (eliminator, d, -pivot); - mark_garbage (d); - return false; - } - - // Single self-subsuming resolution: The pivot can be removed from 'c', - // which is implemented by adding a clause which is the same as 'c' but - // with 'pivot' removed and then marking 'c' as garbage. - - if (s > size) { - CADICAL_assert (s == size + 1); - clause.clear (); - // LRAT is c + d (+ eventual units) - elim_on_the_fly_self_subsumption (eliminator, c, pivot); - return false; - } - - // Same single self-subsuming resolution situation, but only for 'd'. - - if (t > size) { - CADICAL_assert (t == size + 1); - clause.clear (); - // LRAT is c + d (+ eventual units) -> same. - elim_on_the_fly_self_subsumption (eliminator, d, -pivot); - return false; - } - if (propagate_eagerly) - lrat_chain.clear (); - return true; -} - -/*------------------------------------------------------------------------*/ - -// Check whether the number of non-tautological resolvents on 'pivot' is -// smaller or equal to the number of clauses with 'pivot' or '-pivot'. This -// is the main criteria of bounded variable elimination. As a side effect -// it flushes garbage clauses with that variable, sorts its occurrence lists -// (smallest clauses first) and also negates pivot if it has more positive -// than negative occurrences. - -bool Internal::elim_resolvents_are_bounded (Eliminator &eliminator, - int pivot) { - const bool substitute = !eliminator.gates.empty (); - const bool resolve_gates = eliminator.definition_unit; - if (substitute) - LOG ("trying to substitute %d", pivot); - - stats.elimtried++; - - CADICAL_assert (!unsat); - CADICAL_assert (active (pivot)); - - const Occs &ps = occs (pivot); - const Occs &ns = occs (-pivot); - const int64_t pos = ps.size (); - const int64_t neg = ns.size (); - if (!pos || !neg) - return lim.elimbound >= 0; - const int64_t bound = pos + neg + lim.elimbound; - - LOG ("checking number resolvents on %d bounded by " - "%" PRId64 " = %" PRId64 " + %" PRId64 " + %" PRId64, - pivot, bound, pos, neg, lim.elimbound); - - // Try all resolutions between a positive occurrence (outer loop) of - // 'pivot' and a negative occurrence of 'pivot' (inner loop) as long the - // bound on non-tautological resolvents is not hit and the size of the - // generated resolvents does not exceed the resolvent clause size limit. - - int64_t resolvents = 0; // Non-tautological resolvents. - - for (const auto &c : ps) { - CADICAL_assert (!c->redundant); - if (c->garbage) - continue; - for (const auto &d : ns) { - CADICAL_assert (!d->redundant); - if (d->garbage) - continue; - if (!resolve_gates && substitute && c->gate == d->gate) - continue; - stats.elimrestried++; - if (resolve_clauses (eliminator, c, pivot, d, true)) { - resolvents++; - int size = clause.size (); - clause.clear (); - LOG ("now at least %" PRId64 - " non-tautological resolvents on pivot %d", - resolvents, pivot); - if (size > opts.elimclslim) { - LOG ("resolvent size %d too big after %" PRId64 - " resolvents on %d", - size, resolvents, pivot); - return false; - } - if (resolvents > bound) { - LOG ("too many non-tautological resolvents on %d", pivot); - return false; - } - } else if (unsat) - return false; - else if (val (pivot)) - return false; - } - } - - LOG ("need %" PRId64 " <= %" PRId64 " non-tautological resolvents", - resolvents, bound); - - return true; -} - -/*------------------------------------------------------------------------*/ -// Add all resolvents on 'pivot' and connect them. - -inline void Internal::elim_add_resolvents (Eliminator &eliminator, - int pivot) { - - const bool substitute = !eliminator.gates.empty (); - const bool resolve_gates = eliminator.definition_unit; - if (substitute) { - LOG ("substituting pivot %d by resolving with %zd gate clauses", pivot, - eliminator.gates.size ()); - stats.elimsubst++; - } - switch (eliminator.gatetype) { - case EQUI: - stats.eliminated_equi++; - break; - case AND: - stats.eliminated_and++; - break; - case ITE: - stats.eliminated_ite++; - break; - case XOR: - stats.eliminated_xor++; - break; - case DEF: - stats.eliminated_def++; - break; - default: - CADICAL_assert (eliminator.gatetype == NO); - } - - LOG ("adding all resolvents on %d", pivot); - - CADICAL_assert (!val (pivot)); - CADICAL_assert (!flags (pivot).eliminated ()); - - const Occs &ps = occs (pivot); - const Occs &ns = occs (-pivot); -#ifdef LOGGING - int64_t resolvents = 0; -#endif - for (auto &c : ps) { - if (unsat) - break; - if (c->garbage) - continue; - for (auto &d : ns) { - if (unsat) - break; - if (d->garbage) - continue; - if (!resolve_gates && substitute && c->gate == d->gate) - continue; - if (!resolve_clauses (eliminator, c, pivot, d, false)) - continue; - CADICAL_assert (!lrat || !lrat_chain.empty ()); - Clause *r = new_resolved_irredundant_clause (); - elim_update_added_clause (eliminator, r); - eliminator.enqueue (r); - lrat_chain.clear (); - clause.clear (); -#ifdef LOGGING - resolvents++; -#endif - } - } - - LOG ("added %" PRId64 " resolvents to eliminate %d", resolvents, pivot); -} - -/*------------------------------------------------------------------------*/ - -// Remove clauses with 'pivot' and '-pivot' by marking them as garbage and -// push them on the extension stack. - -void Internal::mark_eliminated_clauses_as_garbage ( - Eliminator &eliminator, int pivot, bool &deleted_binary_clause) { - CADICAL_assert (!unsat); - - LOG ("marking irredundant clauses with %d as garbage", pivot); - - const int64_t substitute = eliminator.gates.size (); - if (substitute) - LOG ("pushing %" PRId64 " gate clauses on extension stack", substitute); -#ifndef CADICAL_NDEBUG - int64_t pushed = 0; -#endif - Occs &ps = occs (pivot); - for (const auto &c : ps) { - if (c->garbage) - continue; - CADICAL_assert (!c->redundant); - if (!substitute || c->gate) { - if (proof) - proof->weaken_minus (c); - if (c->size == 2) - deleted_binary_clause = true; - external->push_clause_on_extension_stack (c, pivot); -#ifndef CADICAL_NDEBUG - pushed++; -#endif - } - mark_garbage (c); - elim_update_removed_clause (eliminator, c, pivot); - } - erase_occs (ps); - - LOG ("marking irredundant clauses with %d as garbage", -pivot); - - Occs &ns = occs (-pivot); - for (const auto &d : ns) { - if (d->garbage) - continue; - CADICAL_assert (!d->redundant); - if (!substitute || d->gate) { - if (proof) - proof->weaken_minus (d); - if (d->size == 2) - deleted_binary_clause = true; - external->push_clause_on_extension_stack (d, -pivot); -#ifndef CADICAL_NDEBUG - pushed++; -#endif - } - mark_garbage (d); - elim_update_removed_clause (eliminator, d, -pivot); - } - erase_occs (ns); - - if (substitute) - CADICAL_assert (pushed <= substitute); - - // Unfortunately, we can not use the trick by Niklas Soerensson anymore, - // which avoids saving all clauses on the extension stack. This would - // break our new incremental 'restore' logic. -} - -/*------------------------------------------------------------------------*/ - -// Try to eliminate 'pivot' by bounded variable elimination. -void Internal::try_to_eliminate_variable (Eliminator &eliminator, int pivot, - bool &deleted_binary_clause) { - - if (!active (pivot)) - return; - CADICAL_assert (!frozen (pivot)); - - // First flush garbage clauses. - // - int64_t pos = flush_occs (pivot); - int64_t neg = flush_occs (-pivot); - - if (pos > neg) { - pivot = -pivot; - swap (pos, neg); - } - LOG ("pivot %d occurs positively %" PRId64 - " times and negatively %" PRId64 " times", - pivot, pos, neg); - CADICAL_assert (!eliminator.schedule.contains (abs (pivot))); - CADICAL_assert (pos <= neg); - - if (pos && neg > opts.elimocclim) { - LOG ("too many occurrences thus not eliminated %d", pivot); - CADICAL_assert (!eliminator.schedule.contains (abs (pivot))); - return; - } - - LOG ("trying to eliminate %d", pivot); - CADICAL_assert (!flags (pivot).eliminated ()); - - // Sort occurrence lists, such that shorter clauses come first. - Occs &ps = occs (pivot); - stable_sort (ps.begin (), ps.end (), clause_smaller_size ()); - Occs &ns = occs (-pivot); - stable_sort (ns.begin (), ns.end (), clause_smaller_size ()); - - if (pos) - find_gate_clauses (eliminator, pivot); - - if (!unsat && !val (pivot)) { - if (elim_resolvents_are_bounded (eliminator, pivot)) { - LOG ("number of resolvents on %d are bounded", pivot); - elim_add_resolvents (eliminator, pivot); - if (!unsat) - mark_eliminated_clauses_as_garbage (eliminator, pivot, - deleted_binary_clause); - if (active (pivot)) - mark_eliminated (pivot); - } else { - LOG ("too many resolvents on %d so not eliminated", pivot); - } - } - - unmark_gate_clauses (eliminator); - elim_backward_clauses (eliminator); -} - -/*------------------------------------------------------------------------*/ - -void Internal:: - mark_redundant_clauses_with_eliminated_variables_as_garbage () { - for (const auto &c : clauses) { - if (c->garbage || !c->redundant) - continue; - bool clean = true; - for (const auto &lit : *c) { - Flags &f = flags (lit); - if (f.eliminated ()) { - clean = false; - break; - } - if (f.pure ()) { - clean = false; - break; - } - } - if (!clean) - mark_garbage (c); - } -} - -/*------------------------------------------------------------------------*/ - -// This function performs one round of bounded variable elimination and -// returns the number of eliminated variables. The additional result -// 'completed' is true if this elimination round ran to completion (all -// variables have been tried). Otherwise it was asynchronously terminated -// or the resolution limit was hit. - -int Internal::elim_round (bool &completed, bool &deleted_binary_clause) { - - CADICAL_assert (opts.elim); - CADICAL_assert (!unsat); - - START_SIMPLIFIER (elim, ELIM); - stats.elimrounds++; - - int64_t marked_before = last.elim.marked; - last.elim.marked = stats.mark.elim; - CADICAL_assert (!level); - - int64_t resolution_limit; - - if (opts.elimlimited) { - int64_t delta = stats.propagations.search; - delta *= 1e-3 * opts.elimeffort; - if (delta < opts.elimmineff) - delta = opts.elimmineff; - if (delta > opts.elimmaxeff) - delta = opts.elimmaxeff; - delta = max (delta, (int64_t) 2l * active ()); - - PHASE ("elim-round", stats.elimrounds, - "limit of %" PRId64 " resolutions", delta); - - resolution_limit = stats.elimres + delta; - } else { - PHASE ("elim-round", stats.elimrounds, "resolutions unlimited"); - resolution_limit = LONG_MAX; - } - - init_noccs (); - - // First compute the number of occurrences of each literal and at the same - // time mark satisfied clauses and update 'elim' flags of variables in - // clauses with root level assigned literals (both false and true). - // - for (const auto &c : clauses) { - if (c->garbage || c->redundant) - continue; - bool satisfied = false, falsified = false; - for (const auto &lit : *c) { - const signed char tmp = val (lit); - if (tmp > 0) - satisfied = true; - else if (tmp < 0) - falsified = true; - else - CADICAL_assert (active (lit)); - } - if (satisfied) - mark_garbage (c); // forces more precise counts - else { - for (const auto &lit : *c) { - if (!active (lit)) - continue; - if (falsified) - mark_elim (lit); // simulate unit propagation - noccs (lit)++; - } - } - } - - init_occs (); - - Eliminator eliminator (this); - ElimSchedule &schedule = eliminator.schedule; - CADICAL_assert (schedule.empty ()); - - // Now find elimination candidates which occurred in clauses removed since - // the last time we ran bounded variable elimination, which in turned - // triggered their 'elim' bit to be set. - // - for (auto idx : vars) { - if (!active (idx)) - continue; - if (frozen (idx)) - continue; - if (!flags (idx).elim) - continue; - LOG ("scheduling %d for elimination initially", idx); - schedule.push_back (idx); - } - - schedule.shrink (); - -#ifndef CADICAL_QUIET - int64_t scheduled = schedule.size (); -#endif - - PHASE ("elim-round", stats.elimrounds, - "scheduled %" PRId64 " variables %.0f%% for elimination", - scheduled, percent (scheduled, active ())); - - // Connect irredundant clauses. - // - for (const auto &c : clauses) - if (!c->garbage && !c->redundant) - for (const auto &lit : *c) - if (active (lit)) - occs (lit).push_back (c); - -#ifndef CADICAL_QUIET - const int64_t old_resolutions = stats.elimres; -#endif - const int old_eliminated = stats.all.eliminated; - const int old_fixed = stats.all.fixed; - - // Limit on garbage literals during variable elimination. If the limit is - // hit a garbage collection is performed. - // - const int64_t garbage_limit = (2 * stats.irrlits / 3) + (1 << 20); - - // Main loops tries to eliminate variables according to the schedule. The - // schedule is updated dynamically and variables are potentially - // rescheduled to be tried again if they occur in a removed clause. - // -#ifndef CADICAL_QUIET - int64_t tried = 0; -#endif - while (!unsat && !terminated_asynchronously () && - stats.elimres <= resolution_limit && !schedule.empty ()) { - int idx = schedule.front (); - schedule.pop_front (); - flags (idx).elim = false; - try_to_eliminate_variable (eliminator, idx, deleted_binary_clause); -#ifndef CADICAL_QUIET - tried++; -#endif - if (stats.garbage.literals <= garbage_limit) - continue; - mark_redundant_clauses_with_eliminated_variables_as_garbage (); - garbage_collection (); - } - - // If the schedule is empty all variables have been tried (even - // rescheduled ones). Otherwise asynchronous termination happened or we - // ran into the resolution limit (or derived unsatisfiability). - // - completed = !schedule.size (); - - if (!completed) - last.elim.marked = marked_before; - - PHASE ("elim-round", stats.elimrounds, - "tried to eliminate %" PRId64 " variables %.0f%% (%zd remain)", - tried, percent (tried, scheduled), schedule.size ()); - - schedule.erase (); - - // Collect potential literal clause instantiation pairs, which needs full - // occurrence lists and thus we have it here before resetting them. - // - Instantiator instantiator; - if (!unsat && !terminated_asynchronously () && opts.instantiate) - collect_instantiation_candidates (instantiator); - - reset_occs (); - reset_noccs (); - - // Mark all redundant clauses with eliminated variables as garbage. - // - if (!unsat) - mark_redundant_clauses_with_eliminated_variables_as_garbage (); - - int eliminated = stats.all.eliminated - old_eliminated; -#ifndef CADICAL_QUIET - int64_t resolutions = stats.elimres - old_resolutions; - PHASE ("elim-round", stats.elimrounds, - "eliminated %d variables %.0f%% in %" PRId64 " resolutions", - eliminated, percent (eliminated, scheduled), resolutions); -#endif - - last.elim.subsumephases = stats.subsumephases; - const int units = stats.all.fixed - old_fixed; - report ('e', !opts.reportall && !(eliminated + units)); - STOP_SIMPLIFIER (elim, ELIM); - - if (!unsat && !terminated_asynchronously () && - instantiator) // Do we have candidate pairs? - instantiate (instantiator); - - return eliminated; // non-zero if successful -} - -/*------------------------------------------------------------------------*/ - -// Increase elimination bound (additional clauses allowed during variable -// elimination), which is triggered if elimination with last bound completed -// (including no new subsumptions). This was pioneered by GlueMiniSAT in -// the SAT Race 2015 and then picked up Chanseok Oh in his COMinisatPS -// solver, which in turn is used in the Maple series of SAT solvers. -// The bound is no increased if the maximum bound is reached. - -void Internal::increase_elimination_bound () { - - if (lim.elimbound >= opts.elimboundmax) - return; - - if (lim.elimbound < 0) - lim.elimbound = 0; - else if (!lim.elimbound) - lim.elimbound = 1; - else - lim.elimbound *= 2; - - if (lim.elimbound > opts.elimboundmax) - lim.elimbound = opts.elimboundmax; - - PHASE ("elim-phase", stats.elimphases, - "new elimination bound %" PRId64 "", lim.elimbound); - - // Now reschedule all active variables for elimination again. - // -#ifdef LOGGING - int count = 0; -#endif - for (auto idx : vars) { - if (!active (idx)) - continue; - if (flags (idx).elim) - continue; - mark_elim (idx); -#ifdef LOGGING - count++; -#endif - } - LOG ("marked %d variables as elimination candidates", count); - - report ('^'); -} - -void Internal::init_citten () { - if (!opts.elimdef) - return; - CADICAL_assert (!citten); - citten = cadical_kitten_init (); -} - -void Internal::reset_citten () { - if (citten) { - cadical_kitten_release (citten); - citten = 0; - } -} - -/*------------------------------------------------------------------------*/ - -void Internal::elim (bool update_limits) { - - if (unsat) - return; - if (level) - backtrack (); - if (!propagate ()) { - learn_empty_clause (); - return; - } - - stats.elimphases++; - PHASE ("elim-phase", stats.elimphases, - "starting at most %d elimination rounds", opts.elimrounds); - - if (external_prop) { - CADICAL_assert (!level); - private_steps = true; - } - -#ifndef CADICAL_QUIET - int old_active_variables = active (); - int old_eliminated = stats.all.eliminated; -#endif - - // Make sure there was a complete subsumption phase since last - // elimination including vivification etc. - // - if (last.elim.subsumephases == stats.subsumephases) - subsume (); - - reset_watches (); // saves lots of memory - - init_citten (); - - // Alternate one round of bounded variable elimination ('elim_round') and - // subsumption ('subsume_round'), blocked ('block') and covered clause - // elimination ('cover') until nothing changes, or the round limit is hit. - // The loop also aborts early if no variable could be eliminated, the - // empty clause is resolved, it is asynchronously terminated or a - // resolution limit is hit. - - // This variable determines whether the whole loop of this bounded - // variable elimination phase ('elim') ran until completion. This - // potentially triggers an incremental increase of the elimination bound. - // - bool phase_complete = false, deleted_binary_clause = false; - - int round = 1; -#ifndef CADICAL_QUIET - int eliminated = 0; -#endif - - bool round_complete = false; - while (!unsat && !phase_complete && !terminated_asynchronously ()) { -#ifndef CADICAL_QUIET - int eliminated = -#endif - elim_round (round_complete, deleted_binary_clause); - - if (!round_complete) { - PHASE ("elim-phase", stats.elimphases, "last round %d incomplete %s", - round, eliminated ? "but successful" : "and unsuccessful"); - CADICAL_assert (!phase_complete); - break; - } - - if (round++ >= opts.elimrounds) { - PHASE ("elim-phase", stats.elimphases, "round limit %d hit (%s)", - round - 1, - eliminated ? "though last round successful" - : "last round unsuccessful anyhow"); - CADICAL_assert (!phase_complete); - break; - } - - // Prioritize 'subsumption' over blocked and covered clause elimination. - - if (subsume_round ()) - continue; - if (block ()) - continue; - if (cover ()) - continue; - - // Was not able to generate new variable elimination candidates after - // variable elimination round, neither through subsumption, nor blocked, - // nor covered clause elimination. - // - PHASE ("elim-phase", stats.elimphases, - "no new variable elimination candidates"); - - CADICAL_assert (round_complete); - phase_complete = true; - } - - if (phase_complete) { - stats.elimcompleted++; - PHASE ("elim-phase", stats.elimphases, - "fully completed elimination %" PRId64 - " at elimination bound %" PRId64 "", - stats.elimcompleted, lim.elimbound); - } else { - PHASE ("elim-phase", stats.elimphases, - "incomplete elimination %" PRId64 - " at elimination bound %" PRId64 "", - stats.elimcompleted + 1, lim.elimbound); - } - - reset_citten (); - if (deleted_binary_clause) - delete_garbage_clauses (); - init_watches (); - connect_watches (); - - if (unsat) - LOG ("elimination derived empty clause"); - else if (propagated < trail.size ()) { - LOG ("elimination produced %zd units", - (size_t) (trail.size () - propagated)); - if (!propagate ()) { - LOG ("propagating units after elimination results in empty clause"); - learn_empty_clause (); - } - } - - // If we ran variable elimination until completion we increase the - // variable elimination bound and reschedule elimination of all variables. - // - if (phase_complete) - increase_elimination_bound (); - -#ifndef CADICAL_QUIET - eliminated = stats.all.eliminated - old_eliminated; - PHASE ("elim-phase", stats.elimphases, "eliminated %d variables %.2f%%", - eliminated, percent (eliminated, old_active_variables)); -#endif - - if (external_prop) { - CADICAL_assert (!level); - private_steps = false; - } - - if (!update_limits) - return; - - int64_t delta = scale (opts.elimint * (stats.elimphases + 1)); - lim.elim = stats.conflicts + delta; - - PHASE ("elim-phase", stats.elimphases, - "new limit at %" PRId64 " conflicts after %" PRId64 " conflicts", - lim.elim, delta); - - last.elim.fixed = stats.all.fixed; -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_elimfast.cpp b/src/sat/cadical/cadical_elimfast.cpp deleted file mode 100644 index 90dacf8c0..000000000 --- a/src/sat/cadical/cadical_elimfast.cpp +++ /dev/null @@ -1,576 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -/*------------------------------------------------------------------------*/ - -// Implements a variant of elimination with a much lower limit to be run as -// preprocessing. See elim for comments - -/*------------------------------------------------------------------------*/ - -// Flush garbage clause, check fast elimination limits and return number of -// remaining occurrences (or 'fastelimbound + 1' if some limit was hit). - -int64_t Internal::flush_elimfast_occs (int lit) { - const int64_t occslim = opts.fastelimbound; - const int64_t clslim = opts.fastelimocclim; - const int64_t failed = occslim + 1; - Occs &os = occs (lit); - const const_occs_iterator end = os.end (); - occs_iterator j = os.begin (), i = j; - int64_t res = 0; - while (i != end) { - Clause *c = *i++; - if (c->collect ()) - continue; - *j++ = c; - if (c->size > clslim) { - res = failed; - break; - } - if (++res > occslim) { - CADICAL_assert (opts.fastelimbound < 0 || res == failed); - break; - } - } - if (i != j) { - while (i != end) - *j++ = *i++; - os.resize (j - os.begin ()); - shrink_occs (os); - } - return res; -} - -/*------------------------------------------------------------------------*/ - -// Check whether the number of non-tautological resolvents on 'pivot' is -// smaller or equal to the number of clauses with 'pivot' or '-pivot'. This -// is the main criteria of bounded variable elimination. As a side effect -// it flushes garbage clauses with that variable, sorts its occurrence lists -// (smallest clauses first) and also negates pivot if it has more positive -// than negative occurrences. - -bool Internal::elimfast_resolvents_are_bounded (Eliminator &eliminator, - int pivot) { - CADICAL_assert (eliminator.gates.empty ()); - CADICAL_assert (!eliminator.definition_unit); - - stats.elimtried++; - - CADICAL_assert (!unsat); - CADICAL_assert (active (pivot)); - - const Occs &ps = occs (pivot); - const Occs &ns = occs (-pivot); - - int64_t pos = ps.size (); - int64_t neg = ns.size (); - - int64_t bound = opts.fastelimbound; - - if (!pos || !neg) - return bound >= 0; - - const int64_t sum = pos + neg; - const int64_t product = pos * neg; - if (bound > sum) - bound = sum; - - LOG ("checking number resolvents on %d bounded by " - "%" PRId64 " = %" PRId64 " + %" PRId64 " + %d", - pivot, bound, pos, neg, opts.fastelimbound); - - if (product <= bound) { - LOG ("fast elimination occurrence limits sufficiently small enough"); - return true; - } - - // Try all resolutions between a positive occurrence (outer loop) of - // 'pivot' and a negative occurrence of 'pivot' (inner loop) as long the - // bound on non-tautological resolvents is not hit and the size of the - // generated resolvents does not exceed the resolvent clause size limit. - - int64_t resolvents = 0; // Non-tautological resolvents. - - for (const auto &c : ps) { - CADICAL_assert (!c->redundant); - if (c->garbage) - continue; - for (const auto &d : ns) { - CADICAL_assert (!d->redundant); - if (d->garbage) - continue; - if (resolve_clauses (eliminator, c, pivot, d, true)) { - resolvents++; - int size = clause.size (); - clause.clear (); - LOG ("now at least %" PRId64 - " non-tautological resolvents on pivot %d", - resolvents, pivot); - if (size > opts.fastelimclslim) { - LOG ("resolvent size %d too big after %" PRId64 - " resolvents on %d", - size, resolvents, pivot); - return false; - } - if (resolvents > bound) { - LOG ("too many non-tautological resolvents on %d", pivot); - return false; - } - } else if (unsat) - return false; - else if (val (pivot)) - return false; - } - } - - LOG ("need %" PRId64 " <= %" PRId64 " non-tautological resolvents", - resolvents, bound); - - return true; -} -/*------------------------------------------------------------------------*/ - -/*------------------------------------------------------------------------*/ -// Add all resolvents on 'pivot' and connect them. - -inline void Internal::elimfast_add_resolvents (Eliminator &eliminator, - int pivot) { - - CADICAL_assert (eliminator.gates.empty ()); - CADICAL_assert (!eliminator.definition_unit); - - LOG ("adding all resolvents on %d", pivot); - - CADICAL_assert (!val (pivot)); - CADICAL_assert (!flags (pivot).eliminated ()); - - const Occs &ps = occs (pivot); - const Occs &ns = occs (-pivot); -#ifdef LOGGING - int64_t resolvents = 0; -#endif - for (auto &c : ps) { - if (unsat) - break; - if (c->garbage) - continue; - for (auto &d : ns) { - if (unsat) - break; - if (d->garbage) - continue; - if (!resolve_clauses (eliminator, c, pivot, d, false)) - continue; - CADICAL_assert (!lrat || !lrat_chain.empty ()); - Clause *r = new_resolved_irredundant_clause (); - elim_update_added_clause (eliminator, r); - eliminator.enqueue (r); - lrat_chain.clear (); - clause.clear (); -#ifdef LOGGING - resolvents++; -#endif - } - } - - LOG ("added %" PRId64 " resolvents to eliminate %d", resolvents, pivot); -} - -/*------------------------------------------------------------------------*/ - -// Try to eliminate 'pivot' by bounded variable elimination. -void Internal::try_to_fasteliminate_variable (Eliminator &eliminator, - int pivot, - bool &deleted_binary_clause) { - - if (!active (pivot)) - return; - CADICAL_assert (!frozen (pivot)); - - // First flush garbage clauses and check limits. - - int64_t bound = opts.fastelimbound; - - int64_t pos = flush_elimfast_occs (pivot); - if (pos > bound) { - LOG ("too many occurrences thus not eliminated %d", pivot); - CADICAL_assert (!eliminator.schedule.contains (abs (pivot))); - return; - } - - int64_t neg = flush_elimfast_occs (-pivot); - if (neg > bound) { - LOG ("too many occurrences thus not eliminated %d", -pivot); - CADICAL_assert (!eliminator.schedule.contains (abs (pivot))); - return; - } - - const int64_t product = pos * neg; - const int64_t sum = pos + neg; - if (bound > sum) - bound = sum; - - if (pos > neg) { - pivot = -pivot; - swap (pos, neg); - } - - LOG ("pivot %d occurs positively %" PRId64 - " times and negatively %" PRId64 " times", - pivot, pos, neg); - - CADICAL_assert (!eliminator.schedule.contains (abs (pivot))); - CADICAL_assert (pos <= neg); - - LOG ("trying to eliminate %d", pivot); - CADICAL_assert (!flags (pivot).eliminated ()); - - // Sort occurrence lists, such that shorter clauses come first. - Occs &ps = occs (pivot); - stable_sort (ps.begin (), ps.end (), clause_smaller_size ()); - Occs &ns = occs (-pivot); - stable_sort (ns.begin (), ns.end (), clause_smaller_size ()); - - if (!unsat && !val (pivot)) { - if (product <= bound || - elimfast_resolvents_are_bounded (eliminator, pivot)) { - LOG ("number of resolvents on %d are bounded", pivot); - elimfast_add_resolvents (eliminator, pivot); - if (!unsat) - mark_eliminated_clauses_as_garbage (eliminator, pivot, - deleted_binary_clause); - if (active (pivot)) - mark_eliminated (pivot); - } else { - LOG ("too many resolvents on %d so not eliminated", pivot); - } - } - - unmark_gate_clauses (eliminator); - elim_backward_clauses (eliminator); -} - -/*------------------------------------------------------------------------*/ - -// This function performs one round of bounded variable elimination and -// returns the number of eliminated variables. The additional result -// 'completed' is true if this elimination round ran to completion (all -// variables have been tried). Otherwise it was asynchronously terminated -// or the resolution limit was hit. - -int Internal::elimfast_round (bool &completed, - bool &deleted_binary_clause) { - - CADICAL_assert (opts.fastelim); - CADICAL_assert (!unsat); - - START_SIMPLIFIER (fastelim, ELIM); - - stats.elimfastrounds++; - - CADICAL_assert (!level); - - int64_t resolution_limit; - - if (opts.elimlimited) { - int64_t delta = stats.propagations.search; - delta *= 1e-3 * opts.elimeffort; - if (delta < opts.elimmineff) - delta = opts.elimmineff; - if (delta > opts.elimmaxeff) - delta = opts.elimmaxeff; - delta = max (delta, (int64_t) 2l * active ()); - - PHASE ("fastelim-round", stats.elimfastrounds, - "limit of %" PRId64 " resolutions", delta); - - resolution_limit = stats.elimres + delta; - } else { - PHASE ("fastelim-round", stats.elimfastrounds, "resolutions unlimited"); - resolution_limit = LONG_MAX; - } - - init_noccs (); - - // First compute the number of occurrences of each literal and at the same - // time mark satisfied clauses and update 'elim' flags of variables in - // clauses with root level assigned literals (both false and true). - // - for (const auto &c : clauses) { - if (c->garbage || c->redundant) - continue; - bool satisfied = false, falsified = false; - for (const auto &lit : *c) { - const signed char tmp = val (lit); - if (tmp > 0) - satisfied = true; - else if (tmp < 0) - falsified = true; - else - CADICAL_assert (active (lit)); - } - if (satisfied) - mark_garbage (c); // forces more precise counts - else { - for (const auto &lit : *c) { - if (!active (lit)) - continue; - if (falsified) - mark_elim (lit); // simulate unit propagation - noccs (lit)++; - } - } - } - - init_occs (); - - Eliminator eliminator (this); - ElimSchedule &schedule = eliminator.schedule; - CADICAL_assert (schedule.empty ()); - - // Now find elimination candidates which occurred in clauses removed since - // the last time we ran bounded variable elimination, which in turned - // triggered their 'elim' bit to be set. - // - for (auto idx : vars) { - if (!active (idx)) - continue; - if (frozen (idx)) - continue; - if (!flags (idx).elim) - continue; - LOG ("scheduling %d for elimination initially", idx); - schedule.push_back (idx); - } - - schedule.shrink (); - -#ifndef CADICAL_QUIET - int64_t scheduled = schedule.size (); -#endif - - PHASE ("fastelim-round", stats.elimfastrounds, - "scheduled %" PRId64 " variables %.0f%% for elimination", - scheduled, percent (scheduled, active ())); - - // Connect irredundant clauses. - // - for (const auto &c : clauses) - if (!c->garbage && !c->redundant) - for (const auto &lit : *c) - if (active (lit)) - occs (lit).push_back (c); - -#ifndef CADICAL_QUIET - const int64_t old_resolutions = stats.elimres; -#endif - const int old_eliminated = stats.all.eliminated; - const int old_fixed = stats.all.fixed; - - // Limit on garbage literals during variable elimination. If the limit is - // hit a garbage collection is performed. - // - const int64_t garbage_limit = (2 * stats.irrlits / 3) + (1 << 20); - - // Main loops tries to eliminate variables according to the schedule. The - // schedule is updated dynamically and variables are potentially - // rescheduled to be tried again if they occur in a removed clause. - // -#ifndef CADICAL_QUIET - int64_t tried = 0; -#endif - while (!unsat && !terminated_asynchronously () && - stats.elimres <= resolution_limit && !schedule.empty ()) { - int idx = schedule.front (); - schedule.pop_front (); - flags (idx).elim = false; - try_to_fasteliminate_variable (eliminator, idx, deleted_binary_clause); -#ifndef CADICAL_QUIET - tried++; -#endif - if (stats.garbage.literals <= garbage_limit) - continue; - mark_redundant_clauses_with_eliminated_variables_as_garbage (); - garbage_collection (); - } - - // If the schedule is empty all variables have been tried (even - // rescheduled ones). Otherwise asynchronous termination happened or we - // ran into the resolution limit (or derived unsatisfiability). - // - completed = !schedule.size (); - - PHASE ("fastelim-round", stats.elimfastrounds, - "tried to eliminate %" PRId64 " variables %.0f%% (%zd remain)", - tried, percent (tried, scheduled), schedule.size ()); - - schedule.erase (); - - reset_occs (); - reset_noccs (); - - // Mark all redundant clauses with eliminated variables as garbage. - // - if (!unsat) - mark_redundant_clauses_with_eliminated_variables_as_garbage (); - - int eliminated = stats.all.eliminated - old_eliminated; - stats.all.fasteliminated += eliminated; -#ifndef CADICAL_QUIET - int64_t resolutions = stats.elimres - old_resolutions; - PHASE ("fastelim-round", stats.elimfastrounds, - "eliminated %d variables %.0f%% in %" PRId64 " resolutions", - eliminated, percent (eliminated, scheduled), resolutions); -#endif - - const int units = stats.all.fixed - old_fixed; - report ('e', !opts.reportall && !(eliminated + units)); - STOP_SIMPLIFIER (fastelim, ELIM); - - return eliminated; // non-zero if successful -} - -/*------------------------------------------------------------------------*/ - -void Internal::elimfast () { - - if (unsat) - return; - if (level) - backtrack (); - if (!propagate ()) { - learn_empty_clause (); - return; - } - - stats.elimfastphases++; - PHASE ("fastelim-phase", stats.elimfastphases, - "starting at most %d elimination rounds", opts.fastelimrounds); - - if (external_prop) { - CADICAL_assert (!level); - private_steps = true; - } - -#ifndef CADICAL_QUIET - int old_active_variables = active (); - int old_eliminated = stats.all.eliminated; -#endif - - reset_watches (); // saves lots of memory - - // Alternate one round of bounded variable elimination ('elim_round') and - // subsumption ('subsume_round'), blocked ('block') and covered clause - // elimination ('cover') until nothing changes, or the round limit is hit. - // The loop also aborts early if no variable could be eliminated, the - // empty clause is resolved, it is asynchronously terminated or a - // resolution limit is hit. - - // This variable determines whether the whole loop of this bounded - // variable elimination phase ('elim') ran until completion. This - // potentially triggers an incremental increase of the elimination bound. - // - bool phase_complete = false, deleted_binary_clause = false; - - int round = 1; -#ifndef CADICAL_QUIET - int eliminated = 0; -#endif - - bool round_complete = false; - while (!unsat && !phase_complete && !terminated_asynchronously ()) { -#ifndef CADICAL_QUIET - int eliminated = -#endif - elimfast_round (round_complete, deleted_binary_clause); - - if (!round_complete) { - PHASE ("fastelim-phase", stats.elimphases, - "last round %d incomplete %s", round, - eliminated ? "but successful" : "and unsuccessful"); - CADICAL_assert (!phase_complete); - break; - } - - if (round++ >= opts.fastelimrounds) { - PHASE ("fastelim-phase", stats.elimphases, "round limit %d hit (%s)", - round - 1, - eliminated ? "though last round successful" - : "last round unsuccessful anyhow"); - CADICAL_assert (!phase_complete); - break; - } - - // Prioritize 'subsumption' over blocked and covered clause elimination. - - if (subsume_round ()) - continue; - - // Was not able to generate new variable elimination candidates after - // variable elimination round, neither through subsumption, nor blocked, - // nor covered clause elimination. - // - PHASE ("fastelim-phase", stats.elimphases, - "no new variable elimination candidates"); - - CADICAL_assert (round_complete); - phase_complete = true; - } - - for (auto idx : vars) { - if (active (idx)) - flags (idx).elim = true; - } - - if (phase_complete) { - stats.elimcompleted++; - PHASE ("fastelim-phase", stats.elimphases, - "fully completed elimination %" PRId64 - " at elimination bound %" PRId64 "", - stats.elimcompleted, lim.elimbound); - } else { - PHASE ("fastelim-phase", stats.elimphases, - "incomplete elimination %" PRId64 - " at elimination bound %" PRId64 "", - stats.elimcompleted + 1, lim.elimbound); - } - - if (deleted_binary_clause) - delete_garbage_clauses (); - init_watches (); - connect_watches (); - - if (unsat) - LOG ("elimination derived empty clause"); - else if (propagated < trail.size ()) { - LOG ("elimination produced %zd units", - (size_t) (trail.size () - propagated)); - if (!propagate ()) { - LOG ("propagating units after elimination results in empty clause"); - learn_empty_clause (); - } - } - -#ifndef CADICAL_QUIET - eliminated = stats.all.eliminated - old_eliminated; - PHASE ("fastelim-phase", stats.elimphases, - "eliminated %d variables %.2f%%", eliminated, - percent (eliminated, old_active_variables)); -#endif - - if (external_prop) { - CADICAL_assert (!level); - private_steps = false; - } -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_ema.cpp b/src/sat/cadical/cadical_ema.cpp deleted file mode 100644 index e8faf5d76..000000000 --- a/src/sat/cadical/cadical_ema.cpp +++ /dev/null @@ -1,101 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -// Updating an exponential moving average is placed here since we want to -// log both updates and phases of initialization, thus need 'LOG'. -// -// We now use initialization bias correction as in the ADAM method -// [KingmaBa-ICLR'15] instead of our ad-hoc initialization method used -// before. Our old variant used exponentially decreasing alphas: -// -// 1, -// 1/2, 1/2, -// 1/4, 1/4, 1/4, 1/4 -// 1/8, 1/8, 1/8, 1/8, 1/8, 1/8, 1/8, 1/8, -// ... -// 2^-n, ..., 2^-n 'n' times -// alpha, alpha, ... now 'alpha' forever. -// -// where 2^-n is the smallest negative power of two above 'alpha' -// -// This old method is better than the initializations described in our -// [BiereFroehlich-POS'15] paper and actually faster than the ADAM method, -// but less precise. We consider this old method obsolete now but it -// could still be useful for implementations relying on integers instead -// of floating points because it only needs shifts and integer arithmetic. -// -// Our new method for unbiased initialization of the exponential averages -// works as follows. First the biased moving average is computed as usual. -// Note that (as already before) we use the simpler equation -// -// new_biased = old_biased + alpha * (y - old_biased); -// -// which in principle (and thus easy to remember) can be implemented as -// -// biased += alpha * (y - biased); -// -// The original formulation in the ADAM paper (with 'alpha = 1 - beta') is -// -// new_biased = beta * old_biased + (1 - beta) * y -// -// To show that these are equivalent (modulo floating point issues) -// consider the following equivalent expressions: -// -// old_biased + alpha * (y - old_biased) -// old_biased + alpha * y - alpha * old_biased -// (1 - alpha) * old_biased + alpha * y -// beta * old_biased + (1 - beta) * y -// -// The real new idea taken from the ADAM paper is however to fix the biased -// moving average with a correction term '1.0 / (1.0 - pow (beta, updated))' -// by multiplication to obtain an unbiased moving average (called simply -// 'value' in our 'code'). In order to avoid computing 'pow' every time, we -// use 'exp' which is multiplied in every update with 'beta'. - -void EMA::update (Internal *internal, double y, const char *name) { -#ifdef LOGGING - updated++; - const double old_value = value; -#endif - const double old_biased = biased; - const double delta = y - old_biased; - const double scaled_delta = alpha * delta; - const double new_biased = old_biased + scaled_delta; - LOG ("update %" PRIu64 " of biased %s EMA %g with %g (delta %g) " - "yields %g (scaled delta %g)", - updated, name, old_biased, y, delta, new_biased, scaled_delta); - biased = new_biased; - const double old_exp = exp; - double new_exp, div, new_value; - if (old_exp) { - new_exp = old_exp * beta; - CADICAL_assert (new_exp < 1); - exp = new_exp; - div = 1 - new_exp; - CADICAL_assert (div > 0); - new_value = new_biased / div; - } else { - new_value = new_biased; -#ifdef LOGGING - new_exp = 0; - div = 1; -#endif - } - value = new_value; - LOG ("update %" PRIu64 " of corrected %s EMA %g with %g (delta %g) " - "yields %g (exponent %g, divisor %g)", - updated, name, old_value, y, delta, new_value, new_exp, div); -#ifndef LOGGING - (void) internal; - (void) name; -#endif -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_extend.cpp b/src/sat/cadical/cadical_extend.cpp deleted file mode 100644 index c549e90fa..000000000 --- a/src/sat/cadical/cadical_extend.cpp +++ /dev/null @@ -1,287 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -void External::push_zero_on_extension_stack () { - extension.push_back (0); - LOG ("pushing 0 on extension stack"); -} - -void External::push_id_on_extension_stack (int64_t id) { - const uint32_t higher_bits = static_cast (id << 32); - const uint32_t lower_bits = (id & (((int64_t) 1 << 32) - 1)); - extension.push_back (higher_bits); - extension.push_back (lower_bits); - LOG ("pushing id %" PRIu64 " = %d + %d", id, higher_bits, lower_bits); -} - -void External::push_clause_literal_on_extension_stack (int ilit) { - CADICAL_assert (ilit); - const int elit = internal->externalize (ilit); - CADICAL_assert (elit); - extension.push_back (elit); - LOG ("pushing clause literal %d on extension stack (internal %d)", elit, - ilit); -} - -void External::push_witness_literal_on_extension_stack (int ilit) { - CADICAL_assert (ilit); - const int elit = internal->externalize (ilit); - CADICAL_assert (elit); - extension.push_back (elit); - LOG ("pushing witness literal %d on extension stack (internal %d)", elit, - ilit); - if (marked (witness, elit)) - return; - LOG ("marking witness %d", elit); - mark (witness, elit); -} - -// The extension stack allows to reconstruct a satisfying assignment for the -// original formula after removing eliminated clauses. This was pioneered -// by Niklas Soerensson in MiniSAT and for instance is described in our -// inprocessing paper, published at IJCAR'12. This first function adds a -// clause to this stack. First the blocking or eliminated literal is added, -// and then the rest of the clause. - -void External::push_clause_on_extension_stack (Clause *c) { - internal->stats.weakened++; - internal->stats.weakenedlen += c->size; - push_zero_on_extension_stack (); - push_id_on_extension_stack (c->id); - push_zero_on_extension_stack (); - for (const auto &lit : *c) - push_clause_literal_on_extension_stack (lit); -} - -void External::push_clause_on_extension_stack (Clause *c, int pivot) { - push_zero_on_extension_stack (); - push_witness_literal_on_extension_stack (pivot); - push_clause_on_extension_stack (c); -} - -void External::push_binary_clause_on_extension_stack (int64_t id, int pivot, - int other) { - internal->stats.weakened++; - internal->stats.weakenedlen += 2; - push_zero_on_extension_stack (); - push_witness_literal_on_extension_stack (pivot); - push_zero_on_extension_stack (); - push_id_on_extension_stack (id); - push_zero_on_extension_stack (); - push_clause_literal_on_extension_stack (pivot); - push_clause_literal_on_extension_stack (other); -} - -/*------------------------------------------------------------------------*/ - -void External::push_external_clause_and_witness_on_extension_stack ( - const vector &c, const vector &w, int64_t id) { - CADICAL_assert (id); - extension.push_back (0); - for (const auto &elit : w) { - CADICAL_assert (elit != INT_MIN); - init (abs (elit)); - extension.push_back (elit); - mark (witness, elit); - } - extension.push_back (0); - const uint32_t higher_bits = static_cast (id << 32); - const uint32_t lower_bits = (id & (((int64_t) 1 << 32) - 1)); - extension.push_back (higher_bits); - extension.push_back (lower_bits); - extension.push_back (0); - for (const auto &elit : c) { - CADICAL_assert (elit != INT_MIN); - init (abs (elit)); - extension.push_back (elit); - } -} - -/*------------------------------------------------------------------------*/ - -// This is the actual extension process. It goes backward over the clauses -// on the extension stack and flips the assignment of one of the blocking -// literals in the conditional autarky stored before the clause. In the -// original algorithm for witness construction for variable elimination and -// blocked clause removal the conditional autarky consists of a single -// literal from the removed clause, while in general the autarky witness can -// contain an arbitrary set of literals. We are using the more general -// witness reconstruction here which for instance would also work for -// super-blocked or set-blocked clauses. - -void External::extend () { - - CADICAL_assert (!extended); - START (extend); - internal->stats.extensions++; - - PHASE ("extend", internal->stats.extensions, - "mapping internal %d assignments to %d assignments", - internal->max_var, max_var); - -#ifndef CADICAL_QUIET - int64_t updated = 0; -#endif - for (unsigned i = 1; i <= (unsigned) max_var; i++) { - const int ilit = e2i[i]; - if (!ilit) - continue; - if (i >= vals.size ()) - vals.resize (i + 1, false); - vals[i] = (internal->val (ilit) > 0); -#ifndef CADICAL_QUIET - updated++; -#endif - } - PHASE ("extend", internal->stats.extensions, - "updated %" PRId64 " external assignments", updated); - PHASE ("extend", internal->stats.extensions, - "extending through extension stack of size %zd", - extension.size ()); - const auto begin = extension.begin (); - auto i = extension.end (); -#ifndef CADICAL_QUIET - int64_t flipped = 0; -#endif - while (i != begin) { - bool satisfied = false; - int lit; - CADICAL_assert (i != begin); - while ((lit = *--i)) { - if (satisfied) - continue; - if (ival (lit) == lit) - satisfied = true; - CADICAL_assert (i != begin); - } - CADICAL_assert (i != begin); - LOG ("id=%" PRId64, ((int64_t) *i << 32) + *(i - 1)); - CADICAL_assert (*i || *(i - 1)); - --i; - CADICAL_assert (i != begin); - --i; - CADICAL_assert (i != begin); - CADICAL_assert (!*i); - --i; - CADICAL_assert (i != begin); - if (satisfied) - while (*--i) - CADICAL_assert (i != begin); - else { - while ((lit = *--i)) { - const int tmp = ival (lit); // not 'signed char'!!! - if (tmp != lit) { - LOG ("flipping blocking literal %d", lit); - CADICAL_assert (lit); - CADICAL_assert (lit != INT_MIN); - size_t idx = abs (lit); - if (idx >= vals.size ()) - vals.resize (idx + 1, false); - vals[idx] = !vals[idx]; - internal->stats.extended++; -#ifndef CADICAL_QUIET - flipped++; -#endif - } - CADICAL_assert (i != begin); - } - } - } - PHASE ("extend", internal->stats.extensions, - "flipped %" PRId64 " literals during extension", flipped); - extended = true; - LOG ("extended"); - STOP (extend); -} - -/*------------------------------------------------------------------------*/ - -bool External::traverse_witnesses_backward (WitnessIterator &it) { - if (internal->unsat) - return true; - vector clause, witness; - const auto begin = extension.begin (); - auto i = extension.end (); - while (i != begin) { - int lit; - while ((lit = *--i)) - clause.push_back (lit); - CADICAL_assert (!lit); - --i; - const int64_t id = - ((int64_t) * (i - 1) << 32) + static_cast (*i); - CADICAL_assert (id); - i -= 2; - CADICAL_assert (!*i); - CADICAL_assert (i != begin); - while ((lit = *--i)) - witness.push_back (lit); - reverse (clause.begin (), clause.end ()); - reverse (witness.begin (), witness.end ()); - LOG (clause, "traversing clause"); - if (!it.witness (clause, witness, id)) - return false; - clause.clear (); - witness.clear (); - } - return true; -} - -bool External::traverse_witnesses_forward (WitnessIterator &it) { - if (internal->unsat) - return true; - vector clause, witness; - const auto end = extension.end (); - auto i = extension.begin (); - if (i != end) { - int lit = *i++; - do { - CADICAL_assert (!lit), (void) lit; - while ((lit = *i++)) - witness.push_back (lit); - CADICAL_assert (!lit); - CADICAL_assert (i != end); - CADICAL_assert (!*i); - const int64_t id = - ((int64_t) *i << 32) + static_cast (*(i + 1)); - CADICAL_assert (id > 0); - i += 3; - CADICAL_assert (*i); - CADICAL_assert (i != end); - while (i != end && (lit = *i++)) - clause.push_back (lit); - if (!it.witness (clause, witness, id)) - return false; - clause.clear (); - witness.clear (); - } while (i != end); - } - return true; -} - -/*------------------------------------------------------------------------*/ - -void External::conclude_sat () { - if (!internal->proof || concluded) - return; - concluded = true; - if (!extended) - extend (); - vector model; - for (int idx = 1; idx <= max_var; idx++) { - if (ervars[idx]) - continue; - const int lit = ival (idx); - model.push_back (lit); - } - internal->proof->conclude_sat (model); -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_external.cpp b/src/sat/cadical/cadical_external.cpp deleted file mode 100644 index 67d1f918d..000000000 --- a/src/sat/cadical/cadical_external.cpp +++ /dev/null @@ -1,1028 +0,0 @@ -#include "global.h" - -#include "internal.hpp" -#include - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -External::External (Internal *i) - : internal (i), max_var (0), vsize (0), extended (false), - concluded (false), terminator (0), learner (0), fixed_listener (0), - propagator (0), solution (0), vars (max_var) { - CADICAL_assert (internal); - CADICAL_assert (!internal->external); - internal->external = this; -} - -External::~External () { - if (solution) - delete[] solution; -} - -void External::enlarge (int new_max_var) { - - CADICAL_assert (!extended); - - size_t new_vsize = vsize ? 2 * vsize : 1 + (size_t) new_max_var; - while (new_vsize <= (size_t) new_max_var) - new_vsize *= 2; - LOG ("enlarge external size from %zd to new size %zd", vsize, new_vsize); - vsize = new_vsize; -} - -void External::init (int new_max_var, bool extension) { - CADICAL_assert (!extended); - if (new_max_var <= max_var) - return; - int new_vars = new_max_var - max_var; - int old_internal_max_var = internal->max_var; - int new_internal_max_var = old_internal_max_var + new_vars; - internal->init_vars (new_internal_max_var); - if ((size_t) new_max_var >= vsize) - enlarge (new_max_var); - LOG ("initialized %d external variables", new_vars); - if (!max_var) { - CADICAL_assert (e2i.empty ()); - e2i.push_back (0); - ext_units.push_back (0); - ext_units.push_back (0); - ext_flags.push_back (0); - ervars.push_back (0); - CADICAL_assert (internal->i2e.empty ()); - internal->i2e.push_back (0); - } else { - CADICAL_assert (e2i.size () == (size_t) max_var + 1); - CADICAL_assert (internal->i2e.size () == (size_t) old_internal_max_var + 1); - } - unsigned iidx = old_internal_max_var + 1, eidx; - for (eidx = max_var + 1u; eidx <= (unsigned) new_max_var; - eidx++, iidx++) { - LOG ("mapping external %u to internal %u", eidx, iidx); - CADICAL_assert (e2i.size () == eidx); - e2i.push_back (iidx); - ext_units.push_back (0); - ext_units.push_back (0); - ext_flags.push_back (0); - ervars.push_back (0); - internal->i2e.push_back (eidx); - CADICAL_assert (internal->i2e[iidx] == (int) eidx); - CADICAL_assert (e2i[eidx] == (int) iidx); - } - if (extension) - internal->stats.variables_extension += new_vars; - else - internal->stats.variables_original += new_vars; - if (new_max_var >= (int64_t) is_observed.size ()) - is_observed.resize (1 + (size_t) new_max_var, false); - if (internal->opts.checkfrozen) - if (new_max_var >= (int64_t) moltentab.size ()) - moltentab.resize (1 + (size_t) new_max_var, false); - CADICAL_assert (iidx == (size_t) new_internal_max_var + 1); - CADICAL_assert (eidx == (size_t) new_max_var + 1); - CADICAL_assert (ext_units.size () == (size_t) new_max_var * 2 + 2); - max_var = new_max_var; -} - -/*------------------------------------------------------------------------*/ - -void External::reset_assumptions () { - assumptions.clear (); - internal->reset_assumptions (); -} - -void External::reset_concluded () { - concluded = false; - internal->reset_concluded (); -} - -void External::reset_constraint () { - constraint.clear (); - internal->reset_constraint (); -} - -void External::reset_extended () { - if (!extended) - return; - LOG ("reset extended"); - extended = false; -} - -void External::reset_limits () { internal->reset_limits (); } - -/*------------------------------------------------------------------------*/ - -// when extension is true, elit should be a fresh variable and -// we can set a flag that it is an extension variable. -// This is then used in the API contracts, that extension variables are -// never part of the input -int External::internalize (int elit, bool extension) { - int ilit; - if (elit) { - CADICAL_assert (elit != INT_MIN); - const int eidx = abs (elit); - if (extension && eidx <= max_var) - FATAL ("can not add a definition for an already used variable %d", - eidx); - if (eidx > max_var) { - init (eidx, extension); - } - if (extension) { - CADICAL_assert (ervars.size () > (size_t) eidx); - ervars[eidx] = true; - } - ilit = e2i[eidx]; - if (elit < 0) - ilit = -ilit; - if (!ilit) { - CADICAL_assert (internal->max_var < INT_MAX); - ilit = internal->max_var + 1u; - internal->init_vars (ilit); - e2i[eidx] = ilit; - LOG ("mapping external %d to internal %d", eidx, ilit); - e2i[eidx] = ilit; - internal->i2e.push_back (eidx); - CADICAL_assert (internal->i2e[ilit] == eidx); - CADICAL_assert (e2i[eidx] == ilit); - if (elit < 0) - ilit = -ilit; - } - if (internal->opts.checkfrozen) { - CADICAL_assert (eidx < (int64_t) moltentab.size ()); - if (moltentab[eidx]) - FATAL ("can not reuse molten literal %d", eidx); - } - Flags &f = internal->flags (ilit); - if (f.status == Flags::UNUSED) - internal->mark_active (ilit); - else if (f.status != Flags::ACTIVE && f.status != Flags::FIXED) - internal->reactivate (ilit); - if (!marked (tainted, elit) && marked (witness, -elit)) { - CADICAL_assert (!internal->opts.checkfrozen); - LOG ("marking tainted %d", elit); - mark (tainted, elit); - } - } else - ilit = 0; - return ilit; -} - -void External::add (int elit) { - CADICAL_assert (elit != INT_MIN); - reset_extended (); - - bool forgettable = false; - - if (internal->opts.check && - (internal->opts.checkwitness || internal->opts.checkfailed)) { - - forgettable = - internal->from_propagator && internal->ext_clause_forgettable; - - // Forgettable clauses (coming from the external propagator) are not - // saved into the external 'original' stack. They are stored separately - // in external 'forgettable_original', from where they are deleted when - // the corresponding clause is deleted (actually deleted, not just - // marked as garbage). - if (!forgettable) - original.push_back (elit); - } - - const int ilit = internalize (elit); - CADICAL_assert (!elit == !ilit); - - // The external literals of the new clause must be saved for later - // when the proof is printed during add_original_lit (0) - if (elit && (internal->proof || forgettable)) { - eclause.push_back (elit); - if (internal->lrat) { - // actually find unit of -elit (flips elit < 0) - unsigned eidx = (elit > 0) + 2u * (unsigned) abs (elit); - CADICAL_assert ((size_t) eidx < ext_units.size ()); - const int64_t id = ext_units[eidx]; - bool added = ext_flags[abs (elit)]; - if (id && !added) { - ext_flags[abs (elit)] = true; - internal->lrat_chain.push_back (id); - } - } - } - - if (!elit && internal->proof && internal->lrat) { - for (const auto &elit : eclause) { - ext_flags[abs (elit)] = false; - } - } - - if (elit) - LOG ("adding external %d as internal %d", elit, ilit); - internal->add_original_lit (ilit); - - // Clean-up saved external literals once proof line is printed - if (!elit && (internal->proof || forgettable)) - eclause.clear (); -} - -void External::assume (int elit) { - CADICAL_assert (elit); - reset_extended (); - if (internal->proof) - internal->proof->add_assumption (elit); - assumptions.push_back (elit); - const int ilit = internalize (elit); - CADICAL_assert (ilit); - LOG ("assuming external %d as internal %d", elit, ilit); - internal->assume (ilit); -} - -bool External::flip (int elit) { - CADICAL_assert (elit); - CADICAL_assert (elit != INT_MIN); - CADICAL_assert (!propagator); - - int eidx = abs (elit); - if (eidx > max_var) - return false; - if (marked (witness, elit)) - return false; - int ilit = e2i[eidx]; - if (!ilit) - return false; - bool res = internal->flip (ilit); - if (res && extended) - reset_extended (); - return res; -} - -bool External::flippable (int elit) { - CADICAL_assert (elit); - CADICAL_assert (elit != INT_MIN); - CADICAL_assert (!propagator); - - int eidx = abs (elit); - if (eidx > max_var) - return false; - if (marked (witness, elit)) - return false; - int ilit = e2i[eidx]; - if (!ilit) - return false; - return internal->flippable (ilit); -} - -bool External::failed (int elit) { - CADICAL_assert (elit); - CADICAL_assert (elit != INT_MIN); - int eidx = abs (elit); - if (eidx > max_var) - return 0; - int ilit = e2i[eidx]; - if (!ilit) - return 0; - if (elit < 0) - ilit = -ilit; - return internal->failed (ilit); -} - -void External::constrain (int elit) { - if (constraint.size () && !constraint.back ()) { - LOG (constraint, "replacing previous constraint"); - reset_constraint (); - } - CADICAL_assert (elit != INT_MIN); - reset_extended (); - const int ilit = internalize (elit); - CADICAL_assert (!elit == !ilit); - if (elit) - LOG ("adding external %d as internal %d to constraint", elit, ilit); - else if (!elit && internal->proof) { - internal->proof->add_constraint (constraint); - } - constraint.push_back (elit); - internal->constrain (ilit); -} - -bool External::failed_constraint () { - return internal->failed_constraint (); -} - -void External::phase (int elit) { - CADICAL_assert (elit); - CADICAL_assert (elit != INT_MIN); - const int ilit = internalize (elit); - internal->phase (ilit); -} - -void External::unphase (int elit) { - CADICAL_assert (elit); - CADICAL_assert (elit != INT_MIN); - int eidx = abs (elit); - if (eidx > max_var) { - UNUSED: - LOG ("resetting forced phase of unused external %d ignored", elit); - return; - } - int ilit = e2i[eidx]; - if (!ilit) - goto UNUSED; - if (elit < 0) - ilit = -ilit; - internal->unphase (ilit); -} - -/*------------------------------------------------------------------------*/ - -// External propagation related functions -// -// Note that when an already assigned variable is added as observed, the -// solver will backtrack to undo this assignment. -// -void External::add_observed_var (int elit) { - if (!propagator) { - LOG ("No connected propagator that could observe the variable, " - "observed flag is not set."); - return; - } - - CADICAL_assert (elit); - CADICAL_assert (elit != INT_MIN); - reset_extended (); // tainting! - - int eidx = abs (elit); - if (eidx <= max_var && - (marked (witness, elit) || marked (witness, -elit))) { - LOG ("Error, only clean variables are allowed to become observed."); - CADICAL_assert (false); - - // TODO: here needs to come the taint and restore of the newly - // observed variable. Restore_clauses must be called before continue. - // LOG ("marking tainted %d", elit); - // mark (tainted, elit); - // mark (tainted, -elit); - // restore_clauses ... - } - - if (eidx >= (int64_t) is_observed.size ()) - is_observed.resize (1 + (size_t) eidx, false); - - if (is_observed[eidx]) - return; - - LOG ("marking %d as externally watched", eidx); - - // Will do the necessary internalization - freeze (elit); - is_observed[eidx] = true; - - int ilit = internalize (elit); - // internal add-observed-var backtracks to a lower decision level to - // unassign the variable in case it was already assigned previously (but - // not on the current level) - internal->add_observed_var (ilit); - - if (propagator->is_lazy) - return; - - // In case this variable was already assigned (e.g. via unit clause) and - // got compacted to map to another (not observed) variable, it can not be - // unnasigned so it must be notified explicitly now. (-> Can lead to - // repeated fixed assignment notifications, in case it was unobserved and - // observed again. But a repeated notification is less error-prone than - // never notifying an assignment.) - const int tmp = fixed (elit); - if (!tmp) - return; - int unit = tmp < 0 ? -elit : elit; - - LOG ("notify propagator about fixed assignment upon observe for %d", - unit); - - // internal add-observed-var had to backtrack to root-level already - CADICAL_assert (!internal->level); - - std::vector assigned = {unit}; - propagator->notify_assignment (assigned); -} - -void External::remove_observed_var (int elit) { - if (!propagator) { - LOG ("No connected propagator that could have watched the variable"); - return; - } - int eidx = abs (elit); - - if (eidx > max_var) - return; - - if (is_observed[eidx]) { - // Follow opposite order of add_observed_var, first remove internal - // is_observed - int ilit = e2i[eidx]; // internalize (elit); - internal->remove_observed_var (ilit); - - is_observed[eidx] = false; - melt (elit); - LOG ("unmarking %d as externally watched", eidx); - } -} - -void External::reset_observed_vars () { - // Shouldn't be called if there is no connected propagator - CADICAL_assert (propagator); - reset_extended (); - - internal->notified = 0; - LOG ("reset notified counter to 0"); - - if (!is_observed.size ()) - return; - - CADICAL_assert (!max_var || (size_t) max_var + 1 == is_observed.size ()); - - for (auto elit : vars) { - int eidx = abs (elit); - CADICAL_assert (eidx <= max_var); - if (is_observed[eidx]) { - int ilit = internalize (elit); - internal->remove_observed_var (ilit); - LOG ("unmarking %d as externally watched", eidx); - is_observed[eidx] = false; - melt (elit); - } - } -} - -bool External::observed (int elit) { - CADICAL_assert (elit); - CADICAL_assert (elit != INT_MIN); - int eidx = abs (elit); - if (eidx > max_var) - return false; - if (eidx >= (int) is_observed.size ()) - return false; - - return is_observed[eidx]; -} - -bool External::is_witness (int elit) { - CADICAL_assert (elit); - CADICAL_assert (elit != INT_MIN); - int eidx = abs (elit); - if (eidx > max_var) - return false; - return (marked (witness, elit) || marked (witness, -elit)); -} - -bool External::is_decision (int elit) { - CADICAL_assert (elit); - CADICAL_assert (elit != INT_MIN); - int eidx = abs (elit); - if (eidx > max_var) - return false; - - int ilit = internalize (elit); - return internal->is_decision (ilit); -} - -void External::force_backtrack (size_t new_level) { - if (!propagator) { - LOG ("No connected propagator that could force backtracking"); - return; - } - LOG ("force backtrack to level %zd", new_level); - internal->force_backtrack (new_level); -} - -/*------------------------------------------------------------------------*/ - -int External::propagate_assumptions () { - int res = internal->propagate_assumptions (); - if (res == 10 && !extended) - extend (); // Call solution reconstruction - check_solve_result (res); - reset_limits (); - return res; -} - -void External::implied (std::vector &trailed) { - std::vector ilit_implicants; - internal->implied (ilit_implicants); - - // Those implied literals must be filtered out that are witnesses - // on the reconstruction stack -> no inplace externalize is possible. - // (Internal does not see these marks, so no earlier filter is - // possible.) - - trailed.clear(); - - for (const auto &ilit : ilit_implicants) { - CADICAL_assert (ilit); - const int elit = internal->externalize (ilit); - const int eidx = abs (elit); - const bool is_extension_var = ervars[eidx]; - if (!marked (tainted, elit) && !is_extension_var) { - trailed.push_back (elit); - } - } -} - -void External::conclude_unknown () { - if (!internal->proof || concluded) - return; - concluded = true; - - vector trail; - implied (trail); - internal->proof->conclude_unknown (trail); -} - -/*------------------------------------------------------------------------*/ - -// Internal checker if 'solve' claims the formula to be satisfiable. - -void External::check_satisfiable () { - LOG ("checking satisfiable"); - if (!extended) - extend (); - if (internal->opts.checkwitness) - check_assignment (&External::ival); - if (internal->opts.checkassumptions && !assumptions.empty ()) - check_assumptions_satisfied (); - if (internal->opts.checkconstraint && !constraint.empty ()) - check_constraint_satisfied (); -} - -// Internal checker if 'solve' claims formula to be unsatisfiable. - -void External::check_unsatisfiable () { - LOG ("checking unsatisfiable"); - if (!internal->opts.checkfailed) - return; - if (!assumptions.empty () || !constraint.empty ()) - check_failing (); -} - -// Check result of 'solve' to be correct. - -void External::check_solve_result (int res) { - if (!internal->opts.check) - return; - if (res == 10) - check_satisfiable (); - if (res == 20) - check_unsatisfiable (); -} - -// Prepare checking that completely molten literals are not used as argument -// of 'add' or 'assume', which is invalid under freezing semantics. This -// case would be caught by our 'restore' implementation so is only needed -// for checking the deprecated 'freeze' semantics. - -void External::update_molten_literals () { - if (!internal->opts.checkfrozen) - return; - CADICAL_assert ((size_t) max_var + 1 == moltentab.size ()); -#ifdef LOGGING - int registered = 0, molten = 0; -#endif - for (auto lit : vars) { - if (moltentab[lit]) { - LOG ("skipping already molten literal %d", lit); -#ifdef LOGGING - molten++; -#endif - } else if (frozen (lit)) - LOG ("skipping currently frozen literal %d", lit); - else { - LOG ("new molten literal %d", lit); - moltentab[lit] = true; -#ifdef LOGGING - registered++; - molten++; -#endif - } - } - LOG ("registered %d new molten literals", registered); - LOG ("reached in total %d molten literals", molten); -} - -int External::solve (bool preprocess_only) { - reset_extended (); - update_molten_literals (); - int res = internal->solve (preprocess_only); - check_solve_result (res); - reset_limits (); - return res; -} - -void External::terminate () { internal->terminate (); } - -int External::lookahead () { - reset_extended (); - update_molten_literals (); - int ilit = internal->lookahead (); - const int elit = - (ilit && ilit != INT_MIN) ? internal->externalize (ilit) : 0; - LOG ("lookahead internal %d external %d", ilit, elit); - return elit; -} - -CaDiCaL::CubesWithStatus External::generate_cubes (int depth, - int min_depth = 0) { - reset_extended (); - update_molten_literals (); - reset_limits (); - auto cubes = internal->generate_cubes (depth, min_depth); - auto externalize = [this] (int ilit) { - const int elit = ilit ? internal->externalize (ilit) : 0; - MSG ("lookahead internal %d external %d", ilit, elit); - return elit; - }; - auto externalize_map = [this, externalize] (std::vector cube) { - (void) this; - MSG ("Cube : "); - std::for_each (begin (cube), end (cube), externalize); - }; - std::for_each (begin (cubes.cubes), end (cubes.cubes), externalize_map); - - return cubes; -} - -/*------------------------------------------------------------------------*/ - -void External::freeze (int elit) { - reset_extended (); - int ilit = internalize (elit); - unsigned eidx = vidx (elit); - if (eidx >= frozentab.size ()) - frozentab.resize (eidx + 1, 0); - unsigned &ref = frozentab[eidx]; - if (ref < UINT_MAX) { - ref++; - LOG ("external variable %d frozen once and now frozen %u times", eidx, - ref); - } else - LOG ("external variable %d frozen but remains frozen forever", eidx); - internal->freeze (ilit); -} - -void External::melt (int elit) { - reset_extended (); - int ilit = internalize (elit); - unsigned eidx = vidx (elit); - CADICAL_assert (eidx < frozentab.size ()); - unsigned &ref = frozentab[eidx]; - CADICAL_assert (ref > 0); - if (ref < UINT_MAX) { - if (!--ref) { - if (observed (elit)) { - ref++; - LOG ("external variable %d is observed, can not be completely " - "molten", - eidx); - } else - LOG ("external variable %d melted once and now completely melted", - eidx); - } else - LOG ("external variable %d melted once but remains frozen %u times", - eidx, ref); - } else - LOG ("external variable %d melted but remains frozen forever", eidx); - internal->melt (ilit); -} - -/*------------------------------------------------------------------------*/ - -void External::check_assignment (int (External::*a) (int) const) { - - // First check all assigned and consistent. - // - for (auto idx : vars) { - if (!(this->*a) (idx)) - FATAL ("unassigned variable: %d", idx); - int value_idx = (this->*a) (idx); - int value_neg_idx = (this->*a) (-idx); - if (value_idx == idx) - CADICAL_assert (value_neg_idx == idx); - else { - CADICAL_assert (value_idx == -idx); - CADICAL_assert (value_neg_idx == -idx); - } - if (value_idx != value_neg_idx) - FATAL ("inconsistently assigned literals %d and %d", idx, -idx); - } - - // Then check that all (saved) original clauses are satisfied. - // - bool satisfied = false; - const auto end = original.end (); - auto start = original.begin (), i = start; -#ifndef CADICAL_QUIET - int64_t count = 0; -#endif - for (; i != end; i++) { - int lit = *i; - if (!lit) { - if (!satisfied) { - fatal_message_start (); - fputs ("unsatisfied clause:\n", stderr); - for (auto j = start; j != i; j++) - fprintf (stderr, "%d ", *j); - fputc ('0', stderr); - fatal_message_end (); - } - satisfied = false; - start = i + 1; -#ifndef CADICAL_QUIET - count++; -#endif - } else if (!satisfied && (this->*a) (lit) == lit) - satisfied = true; - } - - bool presence_flag; - // Check those forgettable external clauses that are still present, but - // only if the external propagator is still connected (otherwise solution - // reconstruction is allowed to touch the previously observed variables so - // there is no guarantee that the final model will satisfy these clauses.) - for (const auto &forgettables : forgettable_original) { - if (!propagator) - break; - presence_flag = true; - satisfied = false; -#ifndef CADICAL_QUIET - count++; -#endif - std::vector literals; - for (const auto lit : forgettables.second) { - if (presence_flag) { - // First integer is a Boolean flag, not a literal - if (!lit) { - // Deleted clauses can be ignored, they count as satisfied - satisfied = true; - break; - } - presence_flag = false; - continue; - } - - if ((this->*a) (lit) == lit) { - satisfied = true; - break; - } - } - - if (!satisfied) { - fatal_message_start (); - fputs ("unsatisfied external forgettable clause:\n", stderr); - for (size_t j = 1; j < forgettables.second.size (); j++) - fprintf (stderr, "%d ", forgettables.second[j]); - fputc ('0', stderr); - fatal_message_end (); - } - } -#ifndef CADICAL_QUIET - VERBOSE (1, "satisfying assignment checked on %" PRId64 " clauses", - count); -#endif -} - -/*------------------------------------------------------------------------*/ - -void External::check_assumptions_satisfied () { - for (const auto &lit : assumptions) { - // Not 'signed char' !!!! - const int tmp = ival (lit); - if (tmp != lit) - FATAL ("assumption %d falsified", lit); - if (!tmp) - FATAL ("assumption %d unassigned", lit); - } - VERBOSE (1, "checked that %zd assumptions are satisfied", - assumptions.size ()); -} - -void External::check_constraint_satisfied () { - for (const auto lit : constraint) { - if (ival (lit) == lit) { - VERBOSE (1, "checked that constraint is satisfied"); - return; - } - } - FATAL ("constraint not satisfied"); -} - -void External::check_failing () { - Solver *checker = new Solver (); - DeferDeletePtr delete_checker (checker); - checker->prefix ("checker "); -#ifdef LOGGING - if (internal->opts.log) - checker->set ("log", true); -#endif - - for (const auto lit : assumptions) { - if (!failed (lit)) - continue; - LOG ("checking failed literal %d in core", lit); - checker->add (lit); - checker->add (0); - } - if (failed_constraint ()) { - LOG (constraint, "checking failed constraint"); - for (const auto lit : constraint) - checker->add (lit); - } else if (constraint.size ()) - LOG (constraint, "constraint satisfied and ignored"); - - // Add original clauses as last step, failing () and failed_constraint () - // might add more external clauses (due to lazy explanation) - for (const auto lit : original) - checker->add (lit); - - // Add every forgettable external clauses - for (const auto &forgettables : forgettable_original) { - bool presence_flag = true; - for (const auto lit : forgettables.second) { - if (presence_flag) { - // First integer is a Boolean flag, not a literal, ignore it here - presence_flag = false; - continue; - } - checker->add (lit); - } - checker->add (0); - } - - int res = checker->solve (); - if (res != 20) - FATAL ("failed assumptions do not form a core"); - delete_checker.free (); - VERBOSE (1, "checked that %zd failing assumptions form a core", - assumptions.size ()); -} - -/*------------------------------------------------------------------------*/ - -// Traversal of unit clauses is implemented here. - -// In principle we want to traverse the clauses of the simplified formula -// only, particularly eliminated variables should be completely removed. -// This poses the question what to do with unit clauses. Should they be -// considered part of the simplified formula or of the witness to construct -// solutions for the original formula? Ideally they should be considered -// to be part of the witness only, i.e., as they have been simplified away. - -// Therefore we distinguish frozen and non-frozen units during clause -// traversal. Frozen units are treated as unit clauses while non-frozen -// units are treated as if they were already eliminated and put on the -// extension stack as witness clauses. - -// Furthermore, eliminating units during 'compact' could be interpreted as -// variable elimination, i.e., just add the resolvents (remove falsified -// literals), then drop the clauses with the unit, and push the unit on the -// extension stack. This is of course only OK if the user did not freeze -// that variable (even implicitly during assumptions). - -// Thanks go to Fahiem Bacchus for asking why there is a necessity to -// distinguish these two cases (frozen and non-frozen units). The answer is -// that it is not strictly necessary, and this distinction could be avoided -// by always treating units as remaining unit clauses, thus only using the -// first of the two following functions and dropping the 'if (!frozen (idx)) -// continue;' check in it. This has however the down-side that those units -// are still in the simplified formula and only as units. I would not -// consider such a formula as really being 'simplified'. On the other hand -// if the user explicitly freezes a literal, then it should continue to be -// in the simplified formula during traversal. So also only using the -// second function is not ideal. - -// There is however a catch where this solution breaks down (in the sense of -// producing less optimal results - that is keeping units in the formula -// which better would be witness clauses). The problem is with compact -// preprocessing which removes eliminated but also fixed internal variables. -// One internal unit (fixed) variable is kept and all the other external -// literals which became unit are mapped to that internal literal (negated -// or positively). Compact is called non-deterministically from the point -// of the user and thus there is no control on when this happens. If -// compact happens those external units are mapped to a single internal -// literal now and then all share the same 'frozen' counter. So if the -// user freezes one of them all in essence get frozen, which in turn then -// makes a difference in terms of traversing such a unit as unit clause or -// as unit witness. - -bool External::traverse_all_frozen_units_as_clauses (ClauseIterator &it) { - if (internal->unsat) - return true; - - vector clause; - - for (auto idx : vars) { - if (!frozen (idx)) - continue; - const int tmp = fixed (idx); - if (!tmp) - continue; - int unit = tmp < 0 ? -idx : idx; - clause.push_back (unit); - if (!it.clause (clause)) - return false; - clause.clear (); - } - - return true; -} - -bool External::traverse_all_non_frozen_units_as_witnesses ( - WitnessIterator &it) { - if (internal->unsat) - return true; - - vector clause_and_witness; - for (auto idx : vars) { - if (frozen (idx)) - continue; - const int tmp = fixed (idx); - if (!tmp) - continue; - int unit = tmp < 0 ? -idx : idx; - const int ilit = e2i[idx] * (tmp < 0 ? -1 : 1); - // heurstically add + max_var to the id to avoid reusing ids - const int64_t id = internal->lrat ? internal->unit_id (ilit) : 1; - CADICAL_assert (id); - clause_and_witness.push_back (unit); - if (!it.witness (clause_and_witness, clause_and_witness, id + max_var)) - return false; - clause_and_witness.clear (); - } - - return true; -} - -/*------------------------------------------------------------------------*/ - -void External::copy_flags (External &other) const { - const vector &this_ftab = internal->ftab; - vector &other_ftab = other.internal->ftab; - const unsigned limit = min (max_var, other.max_var); - for (unsigned eidx = 1; eidx <= limit; eidx++) { - const int this_ilit = e2i[eidx]; - if (!this_ilit) - continue; - const int other_ilit = other.e2i[eidx]; - if (!other_ilit) - continue; - if (!internal->active (this_ilit)) - continue; - if (!other.internal->active (other_ilit)) - continue; - CADICAL_assert (this_ilit != INT_MIN); - CADICAL_assert (other_ilit != INT_MIN); - const Flags &this_flags = this_ftab[abs (this_ilit)]; - Flags &other_flags = other_ftab[abs (other_ilit)]; - this_flags.copy (other_flags); - } -} - -/*------------------------------------------------------------------------*/ - -void External::export_learned_empty_clause () { - CADICAL_assert (learner); - if (learner->learning (0)) { - LOG ("exporting learned empty clause"); - learner->learn (0); - } else - LOG ("not exporting learned empty clause"); -} - -void External::export_learned_unit_clause (int ilit) { - CADICAL_assert (learner); - if (learner->learning (1)) { - LOG ("exporting learned unit clause"); - const int elit = internal->externalize (ilit); - CADICAL_assert (elit); - learner->learn (elit); - learner->learn (0); - } else - LOG ("not exporting learned unit clause"); -} - -void External::export_learned_large_clause (const vector &clause) { - CADICAL_assert (learner); - size_t size = clause.size (); - CADICAL_assert (size <= (unsigned) INT_MAX); - if (learner->learning ((int) size)) { - LOG ("exporting learned clause of size %zu", size); - for (auto ilit : clause) { - const int elit = internal->externalize (ilit); - CADICAL_assert (elit); - learner->learn (elit); - } - learner->learn (0); - } else - LOG ("not exporting learned clause of size %zu", size); -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_external_propagate.cpp b/src/sat/cadical/cadical_external_propagate.cpp deleted file mode 100644 index 215170c8b..000000000 --- a/src/sat/cadical/cadical_external_propagate.cpp +++ /dev/null @@ -1,1232 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -/*----------------------------------------------------------------------------*/ -// -// Mark a variable as an observed one. It can be a new variable. It is -// assumed to be clean (not eliminated by previous simplifications). -// -void Internal::add_observed_var (int ilit) { - int idx = vidx (ilit); - if (idx >= (int64_t) relevanttab.size ()) - relevanttab.resize (1 + (size_t) idx, 0); - unsigned &ref = relevanttab[idx]; - if (ref < UINT_MAX) { - ref++; - LOG ("variable %d is observed %u times", idx, ref); - } else - LOG ("variable %d remains observed forever", idx); - // TODO: instead of actually backtracking, it would be enough to notify - // backtrack and re-play again every levels' notification to the - // propagator - if (val (ilit) && level && !fixed (ilit)) { - // The variable is already assigned, but we can not send a notification - // about it because it happened on an earlier decision level. - // To not break the stack-like view of the trail, we simply backtrack to - // undo this unnotifiable assignment. - const int assignment_level = var (ilit).level; - backtrack (assignment_level - 1); - } else if (level && fixed (ilit)) { - backtrack (0); - } -} - -/*----------------------------------------------------------------------------*/ -// -// Removing an observed variable should happen only once it is ensured -// that there is no unexplained propagation in the implication -// graph involving this variable. -// -void Internal::remove_observed_var (int ilit) { - if (!fixed (ilit) && level) { - backtrack (); - } - - CADICAL_assert (fixed (ilit) || !level); - - const int idx = vidx (ilit); - CADICAL_assert ((size_t) idx < relevanttab.size ()); - unsigned &ref = relevanttab[idx]; - CADICAL_assert (fixed (ilit) || ref > 0); - if (fixed (ilit)) - ref = 0; - else if (ref < UINT_MAX) { - if (!--ref) { - LOG ("variable %d is not observed anymore", idx); - } else - LOG ("variable %d is unobserved once but remains observed %u times", - ilit, ref); - } else - LOG ("variable %d remains observed forever", idx); -} - -/*----------------------------------------------------------------------------*/ -// -// Supposed to be used only by mobical. -// -bool Internal::observed (int ilit) const { - CADICAL_assert ((size_t) vidx (ilit) < relevanttab.size ()); - return relevanttab[vidx (ilit)] > 0; -} - -/*----------------------------------------------------------------------------*/ -// -// Check for unexplained propagations upon disconnecting external propagator -// -void Internal::set_tainted_literal () { - if (!opts.ilb) { - return; - } - for (auto idx : vars) { - if (!val (idx)) - continue; - if (var (idx).reason != external_reason) - continue; - if (!tainted_literal) { - tainted_literal = idx; - continue; - } - CADICAL_assert (val (tainted_literal)); - if (var (idx).level < var (tainted_literal).level) { - tainted_literal = idx; - } - } -} - -void Internal::renotify_trail_after_ilb () { - if (!external_prop || external_prop_is_lazy || !trail.size () || - !opts.ilb) { - return; - } - LOG ("notify external propagator about new assignments (after ilb)"); -#ifndef CADICAL_NDEBUG - LOG ("(decision level: %d, trail size: %zd, notified %zd)", level, - trail.size (), notified); -#endif - renotify_full_trail (); -} - -void Internal::renotify_trail_after_local_search () { - if (!external_prop || external_prop_is_lazy || !trail.size ()) { - return; - } - LOG ("notify external propagator about new assignments (after local " - "search)"); -#ifndef CADICAL_NDEBUG - LOG ("(decision level: %d, trail size: %zd, notified %zd)", level, - trail.size (), notified); -#endif - renotify_full_trail (); -} - -// It repeats ALL assignments of the trail, so the already notified -// root-level assignments will be notified multiple times. - -void Internal::renotify_full_trail () { - const size_t end_of_trail = trail.size (); - if (level) { - notified = 0; // TODO: save the last notified root-level position - // somewhere and use it here - notify_backtrack (0); - } - std::vector assigned; - - int prev_max_level = 0; - int current_level = 0; - int propagator_level = 0; - - while (notified < end_of_trail) { - int ilit = trail[notified++]; - // In theory, 0 ilit can happen due to pseudo-decision levels - if (!ilit) - current_level = prev_max_level + 1; - else - current_level = var (ilit).level; - - if (current_level > propagator_level) { - if (assigned.size ()) - external->propagator->notify_assignment (assigned); - while (current_level > propagator_level) { - external->propagator->notify_new_decision_level (); - propagator_level++; - } - assigned.clear (); - } - // Current level can be smaller than prev_max_level due to chrono - if (current_level > prev_max_level) - prev_max_level = current_level; - - if (!observed (ilit)) - continue; - - int elit = externalize (ilit); // TODO: double-check tainting - CADICAL_assert (elit); - // Fixed variables might get mapped (during compact) to another - // non-observed but fixed variable. - // This happens on root level, so notification about their assignment is - // already done. - CADICAL_assert (external->observed (elit) || fixed (ilit)); - if (!external->ervars[abs (elit)]) - assigned.push_back (elit); - } - if (assigned.size ()) - external->propagator->notify_assignment (assigned); - assigned.clear (); - - // In case there are some left over empty levels on the top of the trail, - // the external propagtor must be notified about them so the levels are - // synced - while (level > propagator_level) { - external->propagator->notify_new_decision_level (); - propagator_level++; - } - - return; -} - -/*----------------------------------------------------------------------------*/ -// -// Check if the variable is assigned by decision. -// -bool Internal::is_decision (int ilit) { - if (!level || fixed (ilit) || !val (ilit)) - return false; - - const int idx = vidx (ilit); - Var &v = var (idx); -#ifndef CADICAL_NDEBUG - LOG (v.reason, - "is_decision: i%d (current level: %d, is_fixed: %d, v.level: %d, " - "is_external_reason: %d, v.reason: )", - ilit, level, fixed (ilit), v.level, v.reason == external_reason); -#endif - if (!v.level || v.reason) - return false; - CADICAL_assert (!v.reason); - return true; -} - -void Internal::force_backtrack (size_t new_level) { - if (!forced_backt_allowed || level <= 0 || new_level >= (size_t) level) - return; - -#ifndef CADICAL_NDEBUG - LOG ("external propagator forces backtrack to decision level" - "%zd (from level %d)", - new_level, level); -#endif - backtrack (new_level); -} - -/*----------------------------------------------------------------------------*/ -// -// Call external propagator to check if there is a literal to be propagated. -// The reason of the propagation is not necessarily asked at that point. -// -// In case the externally propagated literal is already falsified, the -// reason is asked and conflict analysis starts. In case the externally -// propagated literal is already satisfied, nothing happens. -// -bool Internal::external_propagate () { - if (level) - require_mode (SEARCH); - CADICAL_assert (!unsat); - - size_t before = num_assigned; - bool cb_repropagate_needed = true; - while (cb_repropagate_needed && !conflict && external_prop && - !external_prop_is_lazy && !private_steps) { -#ifndef CADICAL_NDEBUG - LOG ("external propagation starts (decision level: %d, trail size: " - "%zd, notified %zd)", - level, trail.size (), notified); -#endif - cb_repropagate_needed = false; - // external->reset_extended (); //TODO for inprocessing - - notify_assignments (); - - int elit = external->propagator->cb_propagate (); - stats.ext_prop.ext_cb++; - stats.ext_prop.eprop_call++; - while (elit) { - CADICAL_assert (external->is_observed[abs (elit)]); - int ilit = external->e2i[abs (elit)]; - if (elit < 0) - ilit = -ilit; - int tmp = val (ilit); -#ifndef CADICAL_NDEBUG - CADICAL_assert (fixed (ilit) || observed (ilit)); - LOG ("External propagation of e%d (i%d val: %d)", elit, ilit, tmp); -#endif - if (!tmp) { - // variable is not assigned, it can be propagated - if (!level) { - Clause *res = learn_external_reason_clause (ilit, elit); -#ifndef LOGGING - LOG (res, "reason clause of external propagation of %d:", elit); -#endif - (void) res; - } else - search_assign_external (ilit); - stats.ext_prop.eprop_prop++; - - if (unsat || conflict) - break; - propagate (); - if (unsat || conflict) - break; - notify_assignments (); - } else if (tmp < 0) { - LOG ("External propgation of %d is falsified under current trail", - ilit); - stats.ext_prop.eprop_conf++; - int level_before = level; - size_t assigned = num_assigned; - Clause *res = learn_external_reason_clause (ilit, elit); -#ifndef LOGGING - LOG (res, "reason clause of external propagation of %d:", elit); -#endif - (void) res; - bool trail_changed = - (num_assigned != assigned || level != level_before || - propagated < trail.size ()); - - if (unsat || conflict) - break; - - if (trail_changed) { - propagate (); - if (unsat || conflict) - break; - notify_assignments (); - } - } // else (tmp > 0) -> the case of a satisfied literal is ignored - elit = external->propagator->cb_propagate (); - stats.ext_prop.ext_cb++; - stats.ext_prop.eprop_call++; - } - -#ifndef CADICAL_NDEBUG - LOG ("External propagation ends (decision level: %d, trail size: %zd, " - "notified %zd)", - level, trail.size (), notified); -#endif - if (!unsat && !conflict) { - int level_before = level; - size_t assigned = num_assigned; - bool has_external_clause = ask_external_clause (); - // New observed variable might have triggered a backtrack during this - // ask_external_clause call, so we need to propagate before continuing - stats.ext_prop.ext_cb++; - stats.ext_prop.elearn_call++; - - bool trail_changed = - (num_assigned != assigned || level != level_before || - propagated < trail.size ()); - if (trail_changed) { - propagate (); // unsat or conflict will be caught later - if (!unsat || !conflict) - notify_assignments (); - } - -#ifndef CADICAL_NDEBUG - if (has_external_clause) - LOG ("New external clauses are to be added."); - else - LOG ("No external clauses to be added."); -#endif - - while (has_external_clause) { - level_before = level; - assigned = num_assigned; - - add_external_clause (0); - trail_changed = - (num_assigned != assigned || level != level_before || - propagated < trail.size ()); - cb_repropagate_needed = true; - - if (unsat || conflict) { - cb_repropagate_needed = false; - break; - } - - if (trail_changed) { - propagate (); - if (unsat || conflict) { - cb_repropagate_needed = false; - break; - } - - notify_assignments (); - } - has_external_clause = ask_external_clause (); - stats.ext_prop.ext_cb++; - stats.ext_prop.elearn_call++; - } - } -#ifndef CADICAL_NDEBUG - LOG ("External clause addition ends on decision level %d at trail " - "size " - "%zd (notified %zd)", - level, trail.size (), notified); -#endif - } - if (before < num_assigned) - did_external_prop = true; - return !conflict; -} - -/*----------------------------------------------------------------------------*/ -// -// Helper function, calls 'cb_has_external_clause', while maintains the -// related redundancy type of the clause. -// - -bool Internal::ask_external_clause () { - ext_clause_forgettable = false; - bool res = - external->propagator->cb_has_external_clause (ext_clause_forgettable); - - return res; -} -/*----------------------------------------------------------------------------*/ -// -// Literals of the externally learned clause must be reordered based on the -// assignment levels of the literals. -// -void Internal::move_literals_to_watch () { - if (clause.size () < 2) - return; - if (!level) - return; - - for (int i = 0; i < 2; i++) { - int highest_position = i; - int highest_literal = clause[i]; - - int highest_level = var (highest_literal).level; - int highest_value = val (highest_literal); - - for (size_t j = i + 1; j < clause.size (); j++) { - const int other = clause[j]; - const int other_level = var (other).level; - const int other_value = val (other); - - if (other_value < 0) { - if (highest_value >= 0) - continue; - if (other_level <= highest_level) - continue; - } else if (other_value > 0) { - if (highest_value > 0 && other_level >= highest_level) - continue; - } else { - if (highest_value >= 0) - continue; - } - - highest_position = j; - highest_literal = other; - highest_level = other_level; - highest_value = other_value; - } -#ifndef CADICAL_NDEBUG - LOG ("highest position: %d highest level: %d highest value: %d", - highest_position, highest_level, highest_value); -#endif - - if (highest_position == i) - continue; - if (highest_position > i) { - std::swap (clause[i], clause[highest_position]); - } - } -} - -/*----------------------------------------------------------------------------*/ -// -// Reads out from the external propagator the lemma/proapgation reason -// clause literal by literal. In case propagated_elit is 0, it is about an -// external clause via 'cb_add_external_clause_lit'. Otherwise, it is about -// learning the reason of 'propagated_elit' via 'cb_add_reason_clause_lit'. -// The learned clause is simplified by the current root-level assignment -// (i.e. root-level falsified literals are removed, root satisfied clauses -// are skipped). Duplicate literals are removed, tauotologies are detected -// and skipped. It always adds the original (un-simplified) external clause -// to the proof as an input clause and -// the simplified version of it (except exceptions below) as a derived -// clause. -// -// In case the external clause, after simplifications, is satisfied, no -// clause is constructed, and the function returns 0. In case the external -// clause, after simplifications, is empty, no clause is constructed, unsat -// is set true and the function returns 0. In case the external clause, -// after simplifications, is unit, no clause is constructed, -// 'Internal::clause' has the unit literal (without 0) and the function -// returns 0. -// -// In every other cases a new clause is constructed and the pointer is in -// newest_clause -// -void Internal::add_external_clause (int propagated_elit, - bool no_backtrack) { - CADICAL_assert (original.empty ()); - int elit = 0; - - if (propagated_elit) { - // Propagation reason clauses are by default assumed to be forgettable - // irredundant. In case they would be unforgettably important, the - // propagator can add them as an explicit unforgettable external clause - // or set 'are_reasons_forgettable' to false. - ext_clause_forgettable = external->propagator->are_reasons_forgettable; -#ifndef CADICAL_NDEBUG - LOG ("add external reason of propagated lit: %d", propagated_elit); -#endif - elit = external->propagator->cb_add_reason_clause_lit (propagated_elit); - } else - elit = external->propagator->cb_add_external_clause_lit (); - - // we need to be build a new LRAT chain if we are already in the middle of - // the analysis (like during failed assumptions) - LOG (lrat_chain, "lrat chain before"); - std::vector lrat_chain_ext = std::move (lrat_chain); - lrat_chain.clear (); - clause.clear (); - - // Read out the external lemma into original and simplify it into clause - CADICAL_assert (clause.empty ()); - CADICAL_assert (original.empty ()); - - CADICAL_assert (!force_no_backtrack); - CADICAL_assert (!from_propagator); - force_no_backtrack = no_backtrack; - from_propagator = true; - while (elit) { - CADICAL_assert (external->is_observed[abs (elit)]); - external->add (elit); - if (propagated_elit) - elit = - external->propagator->cb_add_reason_clause_lit (propagated_elit); - else - elit = external->propagator->cb_add_external_clause_lit (); - } - external->add (elit); - CADICAL_assert (original.empty ()); - CADICAL_assert (clause.empty ()); - force_no_backtrack = false; - from_propagator = false; - lrat_chain = std::move (lrat_chain_ext); - LOG (lrat_chain, "lrat chain after"); -} - -/*----------------------------------------------------------------------------*/ -// -// Recursively calls 'learn_external_reason_clause' to explain every -// backward reachable externally propagated literal starting from 'ilit'. -// -void Internal::explain_reason (int ilit, Clause *reason, int &open) { - if (!opts.exteagerreasons) - return; -#ifndef CADICAL_NDEBUG - LOG (reason, "explain_reason of %d (open: %d)", ilit, open); -#endif - CADICAL_assert (reason); - CADICAL_assert (reason != external_reason); - for (const auto &other : *reason) { - if (other == ilit) - continue; - Flags &f = flags (other); - if (f.seen) - continue; - Var &v = var (other); - if (!v.level) - continue; - CADICAL_assert (val (other) < 0); - CADICAL_assert (v.level <= level); - if (v.reason == external_reason) { - v.reason = learn_external_reason_clause (-other, 0, true); - } - if (v.level && v.reason) { - f.seen = true; - open++; - } - } -} - -/*----------------------------------------------------------------------------*/ -// -// In case external propagation was used, the reason clauses of the relevant -// propagations must be learned lazily before/during conflict analysis. -// While conflict analysis needs to analyze only the current level, lazy -// clause learning must check every clause on every level that is backward -// reachable from the conflicting clause to guarantee that the assignment -// levels of the variables are accurate. So this explanation round is -// separated from the conflict analysis, thereby guranteeing that the flags -// and datastructures can be properly used later. -// -// This function must be called before the conflict analysis, in order to -// guarantee that every relevant reason clause is indeed learned already and -// to be sure that the levels of assignments are set correctly. -// -// Later TODO: experiment with bounded explanation (explain only those -// literals that are directly used during conflict analysis + -// minimizing/shrinking). The assignment levels are then only -// over-approximated. -// -void Internal::explain_external_propagations () { - CADICAL_assert (conflict); - CADICAL_assert (clause.empty ()); - - Clause *reason = conflict; - std::vector seen_lits; - int open = 0; // Seen but not explained literal - - explain_reason (0, reason, open); // marks conflict clause lits as seen - int i = trail.size (); // Start at end-of-trail - while (i > 0) { - const int lit = trail[--i]; - if (!flags (lit).seen) - continue; - seen_lits.push_back (lit); - Var &v = var (lit); - if (!v.level) - continue; - if (v.reason) { - open--; - explain_reason (lit, v.reason, open); - } - if (!open) - break; - } - CADICAL_assert (!open); - - if (!opts.exteagerrecalc) { - for (auto lit : seen_lits) { - Flags &f = flags (lit); - f.seen = false; - } -#ifndef CADICAL_NDEBUG - for (auto idx : vars) { - CADICAL_assert (!flags (idx).seen); - } -#endif - } - - // Traverse now in the opposite direction (from lower to higher levels) - // and calculate the actual assignment level for the seen assignments. - for (auto it = seen_lits.rbegin (); it != seen_lits.rend (); ++it) { - const int lit = *it; - Flags &f = flags (lit); - Var &v = var (lit); - if (v.reason) { - int real_level = 0; - for (const auto &other : *v.reason) { - if (other == lit) - continue; - int tmp = var (other).level; - if (tmp > real_level) - real_level = tmp; - } - if (v.level && !real_level) { - build_chain_for_units (lit, v.reason, 1); - learn_unit_clause (lit); - lrat_chain.clear (); - v.reason = 0; - } - CADICAL_assert (v.level >= real_level); - if (v.level > real_level) { - v.level = real_level; - } - } - f.seen = false; - } - -#if 0 // has been fuzzed extensively - for (auto idx : vars) { - CADICAL_assert (!flags (idx).seen); - } -#endif -} - -/*----------------------------------------------------------------------------*/ -// -// Learns the reason clause of the propagation of ilit from the -// external propagator via 'add_external_clause'. -// In case of falsified propagation steps, if the propagated literal is -// already fixed to the opposite value, externalize will not necessarily -// give back the original elit (but an equivalent one). To avoid that, in -// falsified propagation cases the propagated elit is added as a second -// argument. -// -Clause *Internal::learn_external_reason_clause (int ilit, - int falsified_elit, - bool no_backtrack) { - CADICAL_assert (external->propagator); - // we cannot modify clause during analysis - auto clause_tmp = std::move (clause); - - CADICAL_assert (clause.empty ()); - CADICAL_assert (original.empty ()); - - stats.ext_prop.eprop_expl++; - - int elit = 0; - if (!falsified_elit) { - CADICAL_assert (!fixed (ilit)); - elit = externalize (ilit); - } else - elit = falsified_elit; - - LOG ("ilit: %d, elit: %d", ilit, elit); - add_external_clause (elit, no_backtrack); - -#ifndef CADICAL_NDEBUG - if (!falsified_elit && newest_clause) { - // Check if external propagation is correct wrt to the topological order - // defined by the trail. In case it is a falsified external propagation - // step, the order does not matter, the reason simply supposed to be a - // falsified clause. - const int propagated_ilit = ilit; - for (auto const reason_ilit : *newest_clause) { - CADICAL_assert (var (reason_ilit).trail <= var (propagated_ilit).trail); - } - } -#endif - - clause = std::move (clause_tmp); - return newest_clause; -} - -/*----------------------------------------------------------------------------*/ -// -// Helper function to be able to call learn_external_reason_clause when the -// internal clause is already used in the caller side (for example during -// proof checking). These calls are assumed to be without a falsified elit. -// Dont use it in general instead of learn_external_reason_clause because it -// does not support the corner cases where a literal remains in clause. -// -Clause *Internal::wrapped_learn_external_reason_clause (int ilit) { - Clause *res; - std::vector chain_tmp{std::move (lrat_chain)}; - lrat_chain.clear (); - if (clause.empty ()) { - res = learn_external_reason_clause (ilit, 0, true); - } else { - std::vector clause_tmp{std::move (clause)}; - clause.clear (); - res = learn_external_reason_clause (ilit, 0, true); - // The learn_external_reason clause can leave a literal in clause when - // there is a falsified elit arg. Here it is not allowed to - // happen. - CADICAL_assert (clause.empty ()); - - clause = std::move (clause_tmp); - clause_tmp.clear (); - } - CADICAL_assert (lrat_chain.empty ()); - lrat_chain = std::move (chain_tmp); - chain_tmp.clear (); - return res; -} - -/*----------------------------------------------------------------------------*/ -// -// Checks if the new clause forces backtracking, new assignments or conflict -// analysis -// -void Internal::handle_external_clause (Clause *res) { - if (from_propagator) - stats.ext_prop.elearned++; - // at level 0 we have to do nothing... - if (!level) - return; - if (!res) { - if (from_propagator) - stats.ext_prop.elearn_prop++; - // new unit clause. For now just backtrack. - CADICAL_assert (!force_no_backtrack); - CADICAL_assert (level); - // if (!opts.chrono) { - backtrack (); - // } - return; - } - if (from_propagator) - stats.ext_prop.elearned++; - CADICAL_assert (res->size >= 2); - const int pos0 = res->literals[0]; - const int pos1 = res->literals[1]; - if (force_no_backtrack) { - CADICAL_assert (val (pos1) < 0); - CADICAL_assert (val (pos0) >= 0); - return; - // TODO: maybe fix levels - } - const int l1 = var (pos1).level; - if (val (pos0) < 0) { // conflicting or propagating clause - CADICAL_assert (0 < l1 && l1 <= var (pos0).level); - if (!opts.chrono) { - backtrack (l1); - } - if (val (pos0) < 0) { - conflict = res; - if (!from_propagator) { - // its better to backtrack instead of analyze - backtrack (l1 - 1); - conflict = 0; - CADICAL_assert (!val (pos0) && !val (pos1)); - } - } else { - search_assign_driving (pos0, res); - } - if (from_propagator) - stats.ext_prop.elearn_conf++; - return; - } - if (val (pos1) < 0 && !val (pos0)) { // propagating clause - if (!opts.chrono) { - backtrack (l1); - } - search_assign_driving (pos0, res); - if (from_propagator) - stats.ext_prop.elearn_conf++; - return; - } -} - -/*----------------------------------------------------------------------------*/ -// -// Asks the external propagator if the current solution is OK -// by calling 'cb_check_found_model (model)'. -// -// The checked model is built up after everything is restored -// from the reconstruction stack and every variable is reactivated -// and so it is not just simply the trail (i.e. it can be expensive). -// -// If the external propagator approves the model, the function -// returns true. -// -// If the propagator does not approve the model, the solver asks -// the propagator to add an external clause. -// This external clause, however, does NOT have to be falsified by -// the current model. The possible cases and reactions are described -// below in the function. The possible states after that function: -// - A solution was found and accepted by the external propagator -// - A conflicting clause was learned from the external propagator -// - The empty clause was learned due to something new learned from -// the external propagator. -// -// In case only new variables were introduced, but no new clauses were -// added, the function will return without a conflict to the outer CDCL -// loop, where the new (not yet satisfied) variables are recognized and -// the search continues. -bool Internal::external_check_solution () { - if (!external_prop) - return true; - - bool trail_changed = true; - bool added_new_clauses = false; - while (trail_changed || added_new_clauses) { - notify_assignments (); - if (!satisfied ()) - break; - trail_changed = false; // to be on the safe side - added_new_clauses = false; - LOG ("Final check by external propagator is invoked."); - stats.ext_prop.echeck_call++; - external->reset_extended (); - external->extend (); - - std::vector etrail; - - // Here the variables must be filtered by external->is_observed, - // because fixed variables are internally not necessarily observed - // anymore. - for (int idx = 1; idx <= external->max_var; idx++) { - if (!external->is_observed[idx]) - continue; - const int lit = external->ival (idx); - etrail.push_back (lit); -#ifndef CADICAL_NDEBUG -#ifdef LOGGING - bool p = external->vals[idx]; - LOG ("evals[%d]: %d ival(%d): %d", idx, p, idx, lit); -#endif -#endif - } - - bool is_consistent = - external->propagator->cb_check_found_model (etrail); - stats.ext_prop.ext_cb++; - if (is_consistent) { - LOG ("Found solution is approved by external propagator."); - return true; - } - - bool has_external_clause = ask_external_clause (); - - stats.ext_prop.ext_cb++; - stats.ext_prop.elearn_call++; - - if (has_external_clause) - LOG ( - "Found solution triggered new clauses from external propagator."); - - while (has_external_clause) { - int level_before = level; - size_t assigned = num_assigned; - add_external_clause (0); - bool trail_changed = - (num_assigned != assigned || level != level_before || - propagated < trail.size ()); - added_new_clauses = true; - // - // There are many possible scenarios here: - // - Learned conflicting clause: return to CDCL loop (conflict true) - // - Learned conflicting unit clause that after backtrack+BCP leads to - // a new complete solution: force the outer loop to check the new - // model (trail_changed is true, but (conflict & unsat) is false) - // - Learned empty clause: return to CDCL loop (unsat true) - // - Learned a non-conflicting unit clause: - // Though it does not invalidate the current solution, the solver - // will backtrack to the root level and will repropagate it. The - // search will start again (saved phases hopefully make it quick), - // but it is needed in order to guarantee that every fixed variable - // is properly handled+notified (important for incremental use - // cases). - // - Otherwise: the solution is considered approved and the CDCL-loop - // can return with res = 10. - // - if (unsat || conflict || trail_changed) - break; - has_external_clause = ask_external_clause (); - stats.ext_prop.ext_cb++; - stats.ext_prop.elearn_call++; - } - LOG ("No more external clause to add."); - if (unsat || conflict) - break; - } - - if (!unsat && conflict) { - const int conflict_level = var (conflict->literals[0]).level; - if (conflict_level != level) { - backtrack (conflict_level); - } - } - - return !conflict; -} - -/*----------------------------------------------------------------------------*/ -// -// Notify the external propagator that an observed variable got assigned. -// -void Internal::notify_assignments () { - if (!external_prop || external_prop_is_lazy || private_steps) - return; - - const size_t end_of_trail = trail.size (); - - if (notified >= end_of_trail) - return; - - LOG ("notify external propagator about new assignments"); - std::vector assigned; - - while (notified < end_of_trail) { - int ilit = trail[notified++]; - if (!observed (ilit)) - continue; - - int elit = externalize (ilit); // TODO: double-check tainting - CADICAL_assert (elit); - if (external->ervars[abs (elit)]) - continue; - // Fixed variables might get mapped (during compact) to another - // non-observed but fixed variable. - // This happens on root level, so notification about their assignment is - // already done. - CADICAL_assert (external->observed (elit) || - (fixed (ilit) && !external->ervars[abs (elit)])); - assigned.push_back (elit); - } - - external->propagator->notify_assignment (assigned); - return; -} - -/*----------------------------------------------------------------------------*/ - -void Internal::connect_propagator () { - if (level) - backtrack (); -} - -/*----------------------------------------------------------------------------*/ -// -// Notify the external propagator that a new decision level is started. -// -void Internal::notify_decision () { - if (!external_prop || external_prop_is_lazy || private_steps) - return; - external->propagator->notify_new_decision_level (); -} - -/*----------------------------------------------------------------------------*/ -// -// Notify the external propagator that backtrack to new_level. -// -void Internal::notify_backtrack (size_t new_level) { - if (!external_prop || external_prop_is_lazy || private_steps) - return; - external->propagator->notify_backtrack (new_level); -} - -/*----------------------------------------------------------------------------*/ -// -// Ask the external propagator if there is a suggested literal as next -// decision. -// -int Internal::ask_decision () { - if (!external_prop || external_prop_is_lazy || private_steps) - return 0; - - CADICAL_assert (!unsat); - CADICAL_assert (!conflict); - notify_assignments (); - int level_before = level; - forced_backt_allowed = true; - int elit = external->propagator->cb_decide (); - forced_backt_allowed = false; - stats.ext_prop.ext_cb++; - - if (level_before != level) { - - propagate (); - CADICAL_assert (!unsat); - CADICAL_assert (!conflict); - notify_assignments (); - - // In case the external propagator forced to backtrack below the - // pseduo decision levels, we must go back to the CDCL loop instead of - // making a decision. - if ((size_t) level < assumptions.size () || - ((size_t) level == assumptions.size () && constraint.size ())) { - return 0; - } - } - - if (!elit) - return 0; - LOG ("external propagator proposes decision: %d", elit); - CADICAL_assert (external->is_observed[abs (elit)]); - if (!external->is_observed[abs (elit)]) - return 0; - - int ilit = external->e2i[abs (elit)]; - if (elit < 0) - ilit = -ilit; - - CADICAL_assert (fixed (ilit) || observed (ilit)); - - LOG ("Asking external propagator for decision returned: %d (internal: " - "%d, fixed: %d, val: %d)", - elit, ilit, fixed (ilit), val (ilit)); - - if (fixed (ilit) || val (ilit)) { - LOG ("Proposed decision variable is already assigned, falling back to " - "internal decision."); - return 0; - } - - return ilit; -} - -/*----------------------------------------------------------------------------*/ -// -// Check if the clause is a forgettable clause coming from the external -// propagator. -// -bool Internal::is_external_forgettable (int64_t id) { - CADICAL_assert (opts.check); - return (external->forgettable_original.find (id) != - external->forgettable_original.end ()); -} - -/*----------------------------------------------------------------------------*/ -// -// When an external forgettable clause is deleted, it is marked in the -// 'forgettable_original' hash, so that the internal model checking can -// ignore it. -// -void Internal::mark_garbage_external_forgettable (int64_t id) { - CADICAL_assert (opts.check); - CADICAL_assert (is_external_forgettable (id)); - - LOG (external->forgettable_original[id], - "forgettable external lemma is deleted:"); - // Mark as removed by flipping the first flag to false. - external->forgettable_original[id][0] = 0; -} - -/*----------------------------------------------------------------------------*/ -// -// Check that the literals in the clause are properly ordered. Used only -// internally for debug purposes. -// -void Internal::check_watched_literal_invariants () { -#ifndef CADICAL_NDEBUG - int v0 = 0; - int v1 = 0; - - if (val (clause[0]) > 0) - v0 = 1; - else if (val (clause[0]) < 0) - v0 = -1; - - if (val (clause[1]) > 0) - v1 = 1; - else if (val (clause[1]) < 0) - v1 = -1; - CADICAL_assert (v0 >= v1); -#endif - if (val (clause[0]) > 0) { - if (val (clause[1]) > 0) { // Case 1: Both literals are satisfied - // They are ordered by lower to higher decision level - CADICAL_assert (var (clause[0]).level <= var (clause[1]).level); - - // Every other literal of the clause is either - // - satisfied at higher level - // - unassigned - // - falsified - for (size_t i = 2; i < clause.size (); i++) - CADICAL_assert (val (clause[i]) <= 0 || - (var (clause[1]).level <= var (clause[i]).level)); - - } else if (val (clause[1]) == - 0) { // Case 2: First satisfied, next unassigned - - // Every other literal of the clause is either - // - unassigned - // - falsified - for (size_t i = 2; i < clause.size (); i++) - CADICAL_assert (val (clause[i]) <= 0); - - } else { // Case 3: First satisfied, next falsified -> could have been a - // reason of a previous propagation - // Every other literal of the clause is falsified but at a lower - // decision level - for (size_t i = 2; i < clause.size (); i++) - CADICAL_assert (val (clause[i]) < 0 && - (var (clause[1]).level >= var (clause[i]).level)); - } - } else if (val (clause[0]) == 0) { - if (val (clause[1]) == 0) { // Case 4: Both literals are unassigned - - // Every other literal of the clause is either - // - unassigned - // - falsified - for (size_t i = 2; i < clause.size (); i++) - CADICAL_assert (val (clause[i]) <= 0); - - } else { // Case 5: First unassigned, next falsified -> PROPAGATE - // Every other literal of the clause is falsified but at a lower - // decision level - for (size_t i = 2; i < clause.size (); i++) - CADICAL_assert (val (clause[i]) < 0 && - (var (clause[1]).level >= var (clause[i]).level)); - } - } else { - CADICAL_assert (val (clause[0]) < 0 && - val (clause[1]) < 0); // Case 6: Both literals are falsified - - // They are ordered by higher to lower decision level - CADICAL_assert (var (clause[0]).level >= var (clause[1]).level); - - // Every other literal of the clause is falsified, but at a lower level - for (size_t i = 2; i < clause.size (); i++) - CADICAL_assert (val (clause[i]) < 0 && - (var (clause[1]).level >= var (clause[i]).level)); - } -} - -#ifndef CADICAL_NDEBUG - -/*----------------------------------------------------------------------------*/ -// -// An expensive function that can be used for deep-debug trail-related -// issues in mobical. Do not use it unless it is really unavoidable. -// -// eq_class contains all the merged external literals that are currently -// compacted to the internal literal of trail[0] and return true. -// -// In case trail[0] does not exists or is not on the root level, the -// function returns false (indicating that there was no merger literal -// found). -// -bool Internal::get_merged_literals (std::vector &eq_class) { - eq_class.clear (); - - if (!trail.size ()) - return false; - - int ilit = trail[0]; - size_t lit_level = var (ilit).level; - - if (!lit_level) { - // Collect all the variables that are merged and mapped to that ilit - size_t e2i_size = external->e2i.size (); - int ivar = abs (ilit); - for (size_t i = 0; i < e2i_size; i++) { - int other = abs (external->e2i[i]); - if (other == ivar) { - if (external->e2i[i] == ilit) - eq_class.push_back (i); - else - eq_class.push_back (-1 * i); - } - } - - return true; - } - - return false; -} - -/*----------------------------------------------------------------------------*/ -// -// Collect all external variables that are FIXED internally. Again an -// expensive function that should be called only for debugging in mobical. -// -// Do not use it unless it is really unavoidable. -// -void Internal::get_all_fixed_literals (std::vector &fixed_lits) { - fixed_lits.clear (); - if (!trail.size ()) - return; - - int e2i_size = external->e2i.size (); - int ilit; - for (int eidx = 1; eidx < e2i_size; eidx++) { - ilit = external->e2i[eidx]; - if (ilit && !external->ervars[eidx]) { - Flags &f = flags (ilit); - if (f.status == Flags::FIXED) { - fixed_lits.push_back (vals[abs (ilit)] * eidx); - } - } - } -} -#endif - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_factor.cpp b/src/sat/cadical/cadical_factor.cpp deleted file mode 100644 index 3fee40685..000000000 --- a/src/sat/cadical/cadical_factor.cpp +++ /dev/null @@ -1,927 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -#define FACTORS 1 -#define QUOTIENT 2 -#define NOUNTED 4 - -inline bool factor_occs_size::operator() (unsigned a, unsigned b) { - size_t s = internal->occs (internal->u2i (a)).size (); - size_t t = internal->occs (internal->u2i (b)).size (); - if (s > t) - return true; - if (s < t) - return false; - return a > b; -} - -// do full occurence list as in elim.cpp but filter out useless clauses -void Internal::factor_mode () { - reset_watches (); - - CADICAL_assert (!watching ()); - init_occs (); - - const int size_limit = opts.factorsize; - - vector bincount, largecount; - const unsigned max_lit = 2 * (max_var + 1); - enlarge_zero (bincount, max_lit); - if (size_limit > 2) - enlarge_zero (largecount, max_lit); - - vector candidates; - int64_t &ticks = stats.ticks.factor; - ticks += 1 + cache_lines (clauses.size (), sizeof (Clause *)); - - // push binary clauses on the occurrence stack. - for (const auto &c : clauses) { - ticks++; - if (c->garbage) - continue; - if (c->redundant && c->size > 2) - continue; - if (c->size > size_limit) - continue; - if (c->size == 2) { - const int lit = c->literals[0]; - const int other = c->literals[1]; - bincount[vlit (lit)]++; - bincount[vlit (other)]++; - occs (lit).push_back (c); - occs (other).push_back (c); - continue; - } - candidates.push_back (c); - for (const auto &lit : *c) { - largecount[vlit (lit)]++; - } - } - if (size_limit == 2) - return; - - // iterate counts of larger clauses rounds often - const unsigned rounds = opts.factorcandrounds; - unsigned candidates_before = 0; - for (unsigned round = 1; round <= rounds; round++) { - LOG ("factor round %d", round); - if (candidates.size () == candidates_before) - break; - ticks += 1 + cache_lines (candidates.size (), sizeof (Clause *)); - candidates_before = candidates.size (); - vector newlargecount; - enlarge_zero (newlargecount, max_lit); - const auto begin = candidates.begin (); - auto p = candidates.begin (); - auto q = p; - const auto end = candidates.end (); - while (p != end) { - Clause *c = *q++ = *p++; - ticks++; - for (const auto &lit : *c) { - const auto idx = vlit (lit); - if (bincount[idx] + largecount[idx] < 2) { - q--; - goto CONTINUE_WITH_NEXT_CLAUSE; - } - } - for (const auto &lit : *c) { - const auto idx = vlit (lit); - newlargecount[idx]++; - } - CONTINUE_WITH_NEXT_CLAUSE: - continue; - } - candidates.resize (q - begin); - largecount.swap (newlargecount); - } - - // finally push remaining clause on the occurrence stack - for (const auto &c : candidates) - for (const auto &lit : *c) - occs (lit).push_back (c); -} - -// go back to two watch scheme -void Internal::reset_factor_mode () { - reset_occs (); - init_watches (); - connect_watches (); -} - -Factoring::Factoring (Internal *i, int64_t l) - : internal (i), limit (l), schedule (i) { - const unsigned max_var = internal->max_var; - const unsigned max_lit = 2 * (max_var + 1); - initial = max_var; - bound = internal->lim.elimbound; - enlarge_zero (count, max_lit); - quotients.first = quotients.last = 0; -} - -Factoring::~Factoring () { - CADICAL_assert (counted.empty ()); - CADICAL_assert (nounted.empty ()); - CADICAL_assert (flauses.empty ()); - internal->release_quotients (*this); - schedule.erase (); // actually not necessary -} - -double Internal::tied_next_factor_score (int lit) { - double res = occs (lit).size (); - LOG ("watches score %g of %d", res, lit); - return res; -} - -// the marks in cadical have 6 bits for marking but work on idx -// to mark everything (FACTORS, QUOTIENT, NOUNTED) we shift the bits -// depending on the sign of factor (+ bitmask) -// i.e. if factor is positive, we apply a bitmask to only get -// the first three bits (& 7u) -// otherwise we leftshift by 3 (>> 3) to get the bits 4,5,6 -// use markfact, unmarkfact, getfact for this purpose. -// -Quotient *Internal::new_quotient (Factoring &factoring, int factor) { - CADICAL_assert (!getfact (factor, FACTORS)); - markfact (factor, FACTORS); - Quotient *res = new Quotient (factor); - res->next = 0; - res->matched = 0; - Quotient *last = factoring.quotients.last; - res->bid = 0; - if (last) { - CADICAL_assert (factoring.quotients.first); - CADICAL_assert (!last->next); - last->next = res; - res->id = last->id + 1; - } else { - CADICAL_assert (!factoring.quotients.first); - factoring.quotients.first = res; - res->id = 0; - } - factoring.quotients.last = res; - res->prev = last; - LOG ("new quotient[%zu] with factor %d", res->id, factor); - return res; -} - -void Internal::release_quotients (Factoring &factoring) { - for (Quotient *q = factoring.quotients.first, *next; q; q = next) { - next = q->next; - int factor = q->factor; - CADICAL_assert (getfact (factor, FACTORS)); - unmarkfact (factor, FACTORS); - delete q; - } - factoring.quotients.first = factoring.quotients.last = 0; -} - -size_t Internal::first_factor (Factoring &factoring, int factor) { - CADICAL_assert (!factoring.quotients.first); - Quotient *quotient = new_quotient (factoring, factor); - vector &qlauses = quotient->qlauses; - int64_t ticks = 0; - for (const auto &c : occs (factor)) { - qlauses.push_back (c); - ticks++; - } - size_t res = qlauses.size (); - LOG ("quotient[0] factor %d size %zu", factor, res); - // This invariant can of course be broken by previous factorings - // CADICAL_assert (res > 1); - stats.ticks.factor += ticks; - return res; -} - -void Internal::clear_nounted (vector &nounted) { - for (const auto &lit : nounted) { - CADICAL_assert (getfact (lit, NOUNTED)); - unmarkfact (lit, NOUNTED); - } - nounted.clear (); -} - -void Internal::clear_flauses (vector &flauses) { - for (auto c : flauses) { - CADICAL_assert (c->swept); - c->swept = false; - } - flauses.clear (); -} - -Quotient *Internal::best_quotient (Factoring &factoring, - size_t *best_reduction_ptr) { - size_t factors = 1, best_reduction = 0; - Quotient *best = 0; - for (Quotient *q = factoring.quotients.first; q; q = q->next) { - size_t quotients = q->qlauses.size (); - size_t before_factorization = quotients * factors; - size_t after_factorization = quotients + factors; - if (before_factorization == after_factorization) - LOG ("quotient[%zu] factors %zu clauses into %zu thus no change", - factors - 1, before_factorization, after_factorization); - else if (before_factorization < after_factorization) - LOG ("quotient[%zu] factors %zu clauses into %zu thus %zu more", - factors - 1, before_factorization, after_factorization, - after_factorization - before_factorization); - else { - size_t delta = before_factorization - after_factorization; - LOG ("quotient[%zu] factors %zu clauses into %zu thus %zu less", - factors - 1, before_factorization, after_factorization, delta); - if (!best || best_reduction < delta) { - best_reduction = delta; - best = q; - } - } - factors++; - } - if (!best) { - LOG ("no decreasing quotient found"); - return 0; - } - LOG ("best decreasing quotient[%zu] with reduction %zu", best->id, - best_reduction); - *best_reduction_ptr = best_reduction; - return best; -} - -int Internal::next_factor (Factoring &factoring, unsigned *next_count_ptr) { - Quotient *last_quotient = factoring.quotients.last; - CADICAL_assert (last_quotient); - vector &last_clauses = last_quotient->qlauses; - vector &count = factoring.count; - vector &counted = factoring.counted; - vector &flauses = factoring.flauses; - CADICAL_assert (counted.empty ()); - CADICAL_assert (flauses.empty ()); - const int initial = factoring.initial; - int64_t ticks = 1 + cache_lines (last_clauses.size (), sizeof (Clause *)); - for (auto c : last_clauses) { - CADICAL_assert (!c->swept); - int min_lit = 0; - unsigned factors = 0; - size_t min_size = 0; - ticks++; - for (const auto &other : *c) { - if (getfact (other, FACTORS)) { - if (factors++) - break; - } else { - CADICAL_assert (!getfact (other, QUOTIENT)); - markfact (other, QUOTIENT); - const size_t other_size = occs (other).size (); - if (!min_lit || other_size < min_size) { - min_lit = other; - min_size = other_size; - } - } - } - CADICAL_assert (factors); - if (factors == 1) { - CADICAL_assert (min_lit); - const int c_size = c->size; - vector &nounted = factoring.nounted; - CADICAL_assert (nounted.empty ()); - ticks += 1 + cache_lines (occs (min_lit).size (), sizeof (Clause *)); - for (auto d : occs (min_lit)) { - if (c == d) - continue; - ticks++; - if (d->swept) - continue; - if (d->size != c_size) - continue; - int next = 0; - for (const auto &other : *d) { - if (getfact (other, QUOTIENT)) - continue; - if (getfact (other, FACTORS)) - goto CONTINUE_WITH_NEXT_MIN_WATCH; - if (getfact (other, NOUNTED)) - goto CONTINUE_WITH_NEXT_MIN_WATCH; - if (next) - goto CONTINUE_WITH_NEXT_MIN_WATCH; - next = other; - } - CADICAL_assert (next); - if (abs (next) > abs (initial)) - continue; - if (!active (next)) - continue; - CADICAL_assert (!getfact (next, FACTORS)); - CADICAL_assert (!getfact (next, NOUNTED)); - markfact (next, NOUNTED); - nounted.push_back (next); - d->swept = true; - flauses.push_back (d); - if (!count[vlit (next)]) - counted.push_back (next); - count[vlit (next)]++; - CONTINUE_WITH_NEXT_MIN_WATCH:; - } - clear_nounted (nounted); - } - for (const auto &other : *c) - if (getfact (other, QUOTIENT)) - unmarkfact (other, QUOTIENT); - stats.ticks.factor += ticks; - ticks = 0; - if (stats.ticks.factor > factoring.limit) - break; - } - clear_flauses (flauses); - unsigned next_count = 0; - int next = 0; - if (stats.ticks.factor <= factoring.limit) { - unsigned ties = 0; - for (const auto &lit : counted) { - const unsigned lit_count = count[vlit (lit)]; - if (lit_count < next_count) - continue; - if (lit_count == next_count) { - CADICAL_assert (lit_count); - ties++; - } else { - CADICAL_assert (lit_count > next_count); - next_count = lit_count; - next = lit; - ties = 1; - } - } - if (next_count < 2) { - LOG ("next factor count %u smaller than 2", next_count); - next = 0; - } else if (ties > 1) { - LOG ("found %u tied next factor candidate literals with count %u", - ties, next_count); - double next_score = -1; - for (const auto &lit : counted) { - const unsigned lit_count = count[vlit (lit)]; - if (lit_count != next_count) - continue; - double lit_score = tied_next_factor_score (lit); - CADICAL_assert (lit_score >= 0); - LOG ("score %g of next factor candidate %d", lit_score, lit); - if (lit_score <= next_score) - continue; - next_score = lit_score; - next = lit; - } - CADICAL_assert (next_score >= 0); - CADICAL_assert (next); - LOG ("best score %g of next factor %d", next_score, next); - } else { - CADICAL_assert (ties == 1); - LOG ("single next factor %d with count %u", next, next_count); - } - } - for (const auto &lit : counted) - count[vlit (lit)] = 0; - counted.clear (); - CADICAL_assert (!next || next_count > 1); - *next_count_ptr = next_count; - return next; -} - -void Internal::factorize_next (Factoring &factoring, int next, - unsigned expected_next_count) { - Quotient *last_quotient = factoring.quotients.last; - Quotient *next_quotient = new_quotient (factoring, next); - - CADICAL_assert (last_quotient); - vector &last_clauses = last_quotient->qlauses; - vector &next_clauses = next_quotient->qlauses; - vector &matches = next_quotient->matches; - vector &flauses = factoring.flauses; - CADICAL_assert (flauses.empty ()); - - int64_t ticks = 1 + cache_lines (last_clauses.size (), sizeof (Clause *)); - - size_t i = 0; - - for (auto c : last_clauses) { - CADICAL_assert (!c->swept); - int min_lit = 0; - unsigned factors = 0; - size_t min_size = 0; - ticks++; - for (const auto &other : *c) { - if (getfact (other, FACTORS)) { - if (factors++) - break; - } else { - CADICAL_assert (!getfact (other, QUOTIENT)); - markfact (other, QUOTIENT); - const size_t other_size = occs (other).size (); - if (!min_lit || other_size < min_size) { - min_lit = other; - min_size = other_size; - } - } - } - CADICAL_assert (factors); - if (factors == 1) { - CADICAL_assert (min_lit); - const int c_size = c->size; - ticks += 1 + cache_lines (occs (min_lit).size (), sizeof (Clause *)); - for (auto d : occs (min_lit)) { - if (c == d) - continue; - ticks++; - if (d->swept) - continue; - if (d->size != c_size) - continue; - for (const auto &other : *d) { - if (getfact (other, QUOTIENT)) - continue; - if (other != next) - goto CONTINUE_WITH_NEXT_MIN_WATCH; - } - LOG (c, "matched"); - LOG (d, "keeping"); - - next_clauses.push_back (d); - matches.push_back (i); - flauses.push_back (d); - d->swept = true; - break; - - CONTINUE_WITH_NEXT_MIN_WATCH:; - } - } - for (const auto &other : *c) - if (getfact (other, QUOTIENT)) - unmarkfact (other, QUOTIENT); - i++; - } - clear_flauses (flauses); - stats.ticks.factor += ticks; - - CADICAL_assert (expected_next_count <= next_clauses.size ()); - (void) expected_next_count; -} - -// We only need to enlarge factoring.count as everything else is -// initialized in internal -void Internal::resize_factoring (Factoring &factoring, int lit) { - CADICAL_assert (lit > 0); - size_t new_var_size = lit + 1; - size_t new_lit_size = 2 * new_var_size; - enlarge_zero (factoring.count, new_lit_size); -} - -void Internal::flush_unmatched_clauses (Quotient *q) { - Quotient *prev = q->prev; - vector &q_matches = q->matches, &prev_matches = prev->matches; - vector &q_clauses = q->qlauses, &prev_clauses = prev->qlauses; - const size_t n = q_clauses.size (); - CADICAL_assert (n == q_matches.size ()); - bool prev_is_first = !prev->id; - size_t i = 0; - while (i < q_matches.size ()) { - size_t j = q_matches[i]; - q_matches[i] = i; - CADICAL_assert (i <= j); - if (!prev_is_first) { - size_t matches = prev_matches[j]; - prev_matches[i] = matches; - } - Clause *c = prev_clauses[j]; - prev_clauses[i] = c; - i++; - } - LOG ("flushing %zu clauses of quotient[%zu]", prev_clauses.size () - n, - prev->id); - if (!prev_is_first) - prev_matches.resize (n); - prev_clauses.resize (n); -} - -// special case when we have two quotients with negated factors. -// in this case, factoring does not make sense, and instead we -// can resolve the clauses of the two quotients. -// this subsumes all clauses in all quotients. -void Internal::add_self_subsuming_factor (Quotient *q, Quotient *p) { - const int factor = q->factor; - const int not_factor = p->factor; - CADICAL_assert (-factor == not_factor); - LOG ( - "adding self subsuming factor because blocked clause is a tautology"); - for (auto c : q->qlauses) { - for (const auto &lit : *c) { - if (lit == factor) - continue; - clause.push_back (lit); - } - if (lrat) { - for (auto d : p->qlauses) { - bool match = true; - for (const auto &lit : *d) { - if (lit == not_factor) - continue; - if (std::find (clause.begin (), clause.end (), lit) == - clause.end ()) { - match = false; - break; - } - } - if (match) { - lrat_chain.push_back (d->id); - break; - } - } - lrat_chain.push_back (c->id); - CADICAL_assert (lrat_chain.size () == 2); - } - if (clause.size () > 1) { - new_factor_clause (); - } else { - const int unit = clause[0]; - const signed char tmp = val (unit); - if (!tmp) - assign_unit (unit); - else if (tmp < 0) { - if (lrat) { - int64_t id = unit_id (-unit); - lrat_chain.push_back (id); - std::reverse (lrat_chain.begin (), lrat_chain.end ()); - } - learn_empty_clause (); - clause.clear (); - lrat_chain.clear (); - break; - } - } - clause.clear (); - lrat_chain.clear (); - } -} - -bool Internal::self_subsuming_factor (Quotient *q) { - Quotient *x = 0, *y = 0; - bool found = false; - for (Quotient *p = q; p; p = p->prev) { - const int factor = p->factor; - Flags &f = flags (factor); - if (f.seen) { - CADICAL_assert (std::find (analyzed.begin (), analyzed.end (), -factor) != - analyzed.end ()); - found = true; - x = p; - for (Quotient *r = q; r; r = r->prev) { - if (r->factor != -factor) - continue; - y = r; - break; - } - break; - } - analyzed.push_back (factor); - f.seen = true; - } - CADICAL_assert (!found || (x && y)); - clear_analyzed_literals (); - if (found) { - add_self_subsuming_factor (x, y); - return true; - } - return false; -} - -// this is a pure binary clauses containing fresh and one other literal -// it is added for all applicable quotients. -void Internal::add_factored_divider (Quotient *q, int fresh) { - const int factor = q->factor; - LOG ("factored %d divider %d", factor, fresh); - clause.push_back (factor); - clause.push_back (fresh); - new_factor_clause (); - clause.clear (); - if (lrat) - mini_chain.push_back (-clause_id); -} - -// this clause is blocked on fresh, i.e., it contains all literals from -// the binaries above, but negated. This is only added to the proof, to -// make checking easier. -void Internal::blocked_clause (Quotient *q, int not_fresh) { - if (!proof) - return; - int64_t new_id = ++clause_id; - q->bid = new_id; - CADICAL_assert (clause.empty ()); - for (Quotient *p = q; p; p = p->prev) - clause.push_back (-p->factor); - clause.push_back (not_fresh); - CADICAL_assert (!lrat || mini_chain.size ()); - proof->add_derived_clause (new_id, true, clause, mini_chain); - mini_chain.clear (); - clause.clear (); -} - -// this is the other side of the factored clauses. To derive these, -// one can resolved the blocked clause on all matching clauses of -// one type -void Internal::add_factored_quotient (Quotient *q, int not_fresh) { - LOG ("adding factored quotient[%zu] clauses", q->id); - const int factor = q->factor; - CADICAL_assert (lrat_chain.empty ()); - auto qlauses = q->qlauses; - for (unsigned idx = 0; idx < qlauses.size (); idx++) { - const auto c = qlauses[idx]; - CADICAL_assert (clause.empty ()); - for (const auto &other : *c) { - if (other == factor) { - continue; - } - clause.push_back (other); - } - if (lrat) { - CADICAL_assert (proof); - CADICAL_assert (q->bid); - unsigned idxtoo = idx; - for (Quotient *p = q; p; p = p->prev) { - lrat_chain.push_back (p->qlauses[idxtoo]->id); - if (p->prev) - idxtoo = p->matches[idx]; - } - lrat_chain.push_back (q->bid); - } - clause.push_back (not_fresh); - new_factor_clause (); - clause.clear (); - lrat_chain.clear (); - } - if (proof) { - for (Quotient *p = q; p; p = p->prev) { - clause.push_back (-p->factor); - } - clause.push_back (not_fresh); - proof->delete_clause (q->bid, true, clause); - clause.clear (); - } -} - -// remove deleted clauses once factored. -void Internal::eagerly_remove_from_occurences (Clause *c) { - for (const auto &lit : *c) { - auto &occ = occs (lit); - auto p = occ.begin (); - auto q = occ.begin (); - auto begin = occ.begin (); - auto end = occ.end (); - while (p != end) { - *q = *p++; - if (*q != c) - q++; - } - CADICAL_assert (q + 1 == p); - occ.resize (q - begin); - } -} - -// delete the factored clauses -void Internal::delete_unfactored (Quotient *q) { - LOG ("deleting unfactored quotient[%zu] clauses", q->id); - for (auto c : q->qlauses) { - eagerly_remove_from_occurences (c); - mark_garbage (c); - stats.literals_unfactored += c->size; - stats.clauses_unfactored++; - } -} - -// update the priority queue for scheduling -void Internal::update_factored (Factoring &factoring, Quotient *q) { - const int factor = q->factor; - update_factor_candidate (factoring, factor); - update_factor_candidate (factoring, -factor); - for (auto c : q->qlauses) { - LOG (c, "deleting unfactored"); - for (const auto &lit : *c) - if (lit != factor) - update_factor_candidate (factoring, lit); - } -} - -bool Internal::apply_factoring (Factoring &factoring, Quotient *q) { - for (Quotient *p = q; p->prev; p = p->prev) - flush_unmatched_clauses (p); - if (self_subsuming_factor (q)) { - for (Quotient *p = q; p; p = p->prev) - delete_unfactored (p); - for (Quotient *p = q; p; p = p->prev) - update_factored (factoring, p); - return true; - } - const int fresh = get_new_extension_variable (); - if (!fresh) - return false; - stats.factored++; - factoring.fresh.push_back (fresh); - for (Quotient *p = q; p; p = p->prev) - add_factored_divider (p, fresh); - const int not_fresh = -fresh; - blocked_clause (q, not_fresh); - add_factored_quotient (q, not_fresh); - for (Quotient *p = q; p; p = p->prev) - delete_unfactored (p); - for (Quotient *p = q; p; p = p->prev) - update_factored (factoring, p); - CADICAL_assert (fresh > 0); - resize_factoring (factoring, fresh); - return true; -} - -void Internal::update_factor_candidate (Factoring &factoring, int lit) { - FactorSchedule &schedule = factoring.schedule; - const size_t size = occs (lit).size (); - const unsigned idx = vlit (lit); - if (schedule.contains (idx)) - schedule.update (idx); - else if (size > 1) { - schedule.push_back (idx); - } -} - -void Internal::schedule_factorization (Factoring &factoring) { - for (const auto &idx : vars) { - if (active (idx)) { - Flags &f = flags (idx); - const int lit = idx; - const int not_lit = -lit; - if (f.factor & 1) - update_factor_candidate (factoring, lit); - if (f.factor & 2) - update_factor_candidate (factoring, not_lit); - } - } -#ifndef CADICAL_QUIET - size_t size_cands = factoring.schedule.size (); - VERBOSE (2, "scheduled %zu factorization candidate literals %.0f %%", - size_cands, percent (size_cands, max_var)); -#endif -} - -bool Internal::run_factorization (int64_t limit) { - Factoring factoring = Factoring (this, limit); - schedule_factorization (factoring); - bool done = false; -#ifndef CADICAL_QUIET - unsigned factored = 0; -#endif - int64_t *ticks = &stats.ticks.factor; - VERBOSE (3, "factorization limit of %" PRIu64 " ticks", limit - *ticks); - - while (!unsat && !done && !factoring.schedule.empty ()) { - const unsigned ufirst = factoring.schedule.pop_front (); - LOG ("next factor candidate %d", ufirst); - const int first = u2i (ufirst); - const int first_idx = vidx (first); - if (!active (first_idx)) - continue; - if (!occs (first).size ()) { - factoring.schedule.clear (); - break; - } - if (*ticks > limit) { - VERBOSE (2, "factorization ticks limit hit"); - break; - } - if (terminated_asynchronously ()) - break; - Flags &f = flags (first_idx); - const unsigned bit = 1u << (first < 0); - if (!(f.factor & bit)) - continue; - f.factor &= ~bit; - const size_t first_count = first_factor (factoring, first); - if (first_count > 1) { - for (;;) { - unsigned next_count; - const int next = next_factor (factoring, &next_count); - if (next == 0) - break; - CADICAL_assert (next_count > 1); - if (next_count < 2) - break; - factorize_next (factoring, next, next_count); - } - size_t reduction; - Quotient *q = best_quotient (factoring, &reduction); - if (q && (int) reduction > factoring.bound) { - if (apply_factoring (factoring, q)) { -#ifndef CADICAL_QUIET - factored++; -#endif - } else - done = true; - } - } - release_quotients (factoring); - } - - // since we cannot remove elements from the heap we check wether the - // first element in the heap has occurences - bool completed = factoring.schedule.empty (); - if (!completed) { - const unsigned idx = factoring.schedule.front (); - completed = occs (u2i (idx)).empty (); - } - // kissat initializes scores for new variables at this point, however - // this is actually done already during resize of internal -#ifndef CADICAL_QUIET - report ('f', !factored); -#endif - return completed; -} - -int Internal::get_new_extension_variable () { - const int current_max_external = external->max_var; - const int new_external = current_max_external + 1; - const int new_internal = external->internalize (new_external, true); - // one sideeffect of internalize is enlarging the internal datastructures - // which can initialize the watches (wtab) - if (watching ()) - reset_watches (); - // it does not enlarge otab, however, so we do this manually - init_occs (); - CADICAL_assert (vlit (new_internal)); - return new_internal; -} - -bool Internal::factor () { - if (unsat) - return false; - if (terminated_asynchronously ()) - return false; - if (!opts.factor) - return false; - // The following CADICAL_assertion fails if there are *only* user propagator - // clauses (which are redundant). - // CADICAL_assert (stats.mark.factor || clauses.empty ()); - if (last.factor.marked >= stats.mark.factor) { - VERBOSE (3, - "factorization skipped as no literals have been" - "marked to be added (%" PRIu64 " < %" PRIu64 ")", - last.factor.marked, stats.mark.factor); - return false; - } - CADICAL_assert (!level); - - SET_EFFORT_LIMIT (limit, factor, stats.factor); - if (!stats.factor) - limit += opts.factoriniticks * 1e6; - - START_SIMPLIFIER (factor, FACTOR); - stats.factor++; - -#ifndef CADICAL_QUIET - struct { - int64_t variables, clauses, ticks; - } before, after, delta; - before.variables = stats.variables_extension + stats.variables_original; - before.ticks = stats.ticks.factor; - before.clauses = stats.current.irredundant; -#endif - - factor_mode (); - bool completed = run_factorization (limit); - reset_factor_mode (); - - propagated = 0; - if (!unsat && !propagate ()) { - learn_empty_clause (); - } - -#ifndef CADICAL_QUIET - after.variables = stats.variables_extension + stats.variables_original; - after.clauses = stats.current.irredundant; - after.ticks = stats.ticks.factor; - delta.variables = after.variables - before.variables; - delta.clauses = before.clauses - after.clauses; - delta.ticks = after.ticks - before.ticks; - VERBOSE (2, "used %f million factorization ticks", delta.ticks * 1e-6); - phase ("factorization", stats.factor, - "introduced %" PRId64 " extension variables %.0f%%", - delta.variables, percent (delta.variables, before.variables)); - phase ("factorization", stats.factor, - "removed %" PRId64 " irredundant clauses %.0f%%", delta.clauses, - percent (delta.clauses, before.clauses)); -#endif - - if (completed) - last.factor.marked = stats.mark.factor; - STOP_SIMPLIFIER (factor, FACTOR); - return true; -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_file.cpp b/src/sat/cadical/cadical_file.cpp deleted file mode 100644 index 98f19f752..000000000 --- a/src/sat/cadical/cadical_file.cpp +++ /dev/null @@ -1,527 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -/*------------------------------------------------------------------------*/ - -// Some more low-level 'C' headers. - -extern "C" { -#include -#include -#include -#include -#include -#include -} - -#ifdef WIN32 - -#include -#include -#include - -#define access _access -#define popen _popen -#define pclose _pclose -#define R_OK 4 -#define W_OK 2 -#define S_IFIFO _S_IFIFO -#define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO) -#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) - -#else - -extern "C" { -#include -#include -} - -#endif - -#if defined(__APPLE__) || defined(__MACH__) - -extern "C" { -#include -#include -} - -#include - -#endif - -ABC_NAMESPACE_IMPL_START - -/*------------------------------------------------------------------------*/ - -namespace CaDiCaL { - -/*------------------------------------------------------------------------*/ - -// Private constructor. - -File::File (Internal *i, bool w, int c, int p, FILE *f, const char *n) - : internal (i), -#if !defined(CADICAL_QUIET) || !defined(CADICAL_NDEBUG) - writing (w), -#endif - close_file (c), child_pid (p), file (f), _name (strdup (n)), - _lineno (1), _bytes (0) { - (void) w; - CADICAL_assert (f), CADICAL_assert (n); -} - -/*------------------------------------------------------------------------*/ - -bool File::exists (const char *path) { - struct stat buf; - if (stat (path, &buf)) - return false; - if (access (path, R_OK)) - return false; - return true; -} - -bool File::writable (const char *path) { - int res; - if (!path) - res = 1; - else if (!strcmp (path, "/dev/null")) - res = 0; - else { - if (!*path) - res = 2; - else { - struct stat buf; - const char *p = strrchr (path, '/'); - if (!p) { - if (stat (path, &buf)) - res = ((errno == ENOENT) ? 0 : -2); - else if (S_ISDIR (buf.st_mode)) - res = 3; - else - res = (access (path, W_OK) ? 4 : 0); - } else if (!p[1]) - res = 5; - else { - size_t len = p - path; - char *dirname = new char[len + 1]; - strncpy (dirname, path, len); - dirname[len] = 0; - if (stat (dirname, &buf)) - res = 6; - else if (!S_ISDIR (buf.st_mode)) - res = 7; - else if (access (dirname, W_OK)) - res = 8; - else if (stat (path, &buf)) - res = (errno == ENOENT) ? 0 : -3; - else - res = access (path, W_OK) ? 9 : 0; - delete[] dirname; - } - } - } - return !res; -} - -bool File::piping () { - struct stat stat; - int fd = fileno (file); - if (fstat (fd, &stat)) - return true; - return S_ISFIFO (stat.st_mode); -} - -// These are signatures for supported compressed file types. In 2018 the -// SAT Competition was running on StarExec and used internally 'bzip2' -// compressed files, but gave them uncompressed to the solver using exactly -// the same path (with '.bz2' suffix). Then 'CaDiCaL' tried to read that -// actually uncompressed file through 'bzip2', which of course failed. Now -// we double check and fall back to reading the file as is, if the signature -// does not match after issuing a warning. - -static int xzsig[] = {0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, EOF}; -static int bz2sig[] = {0x42, 0x5A, 0x68, EOF}; -static int gzsig[] = {0x1F, 0x8B, EOF}; -static int sig7z[] = {0x37, 0x7A, 0xBC, 0xAF, 0x27, 0x1C, EOF}; -static int lzmasig[] = {0x5D, EOF}; - -bool File::match (Internal *internal, const char *path, const int *sig) { - CADICAL_assert (path); - FILE *tmp = fopen (path, "r"); - if (!tmp) { - WARNING ("failed to open '%s' to check signature", path); - return false; - } - bool res = true; - for (const int *p = sig; res && (*p != EOF); p++) - res = (cadical_getc_unlocked (tmp) == *p); - fclose (tmp); - if (!res) - WARNING ("file type signature check for '%s' failed", path); - return res; -} - -size_t File::size (const char *path) { - struct stat buf; - if (stat (path, &buf)) - return 0; - return (size_t) buf.st_size; -} - -// Check that 'prg' is in the 'PATH' and thus can be found if executed -// through 'popen' or 'exec'. - -char *File::find_program (const char *prg) { - size_t prglen = strlen (prg); - const char *c = getenv ("PATH"); - if (!c) - return 0; - size_t len = strlen (c); - char *e = new char[len + 1]; - strcpy (e, c); - char *res = 0; - for (char *p = e, *q; !res && p < e + len; p = q) { - for (q = p; *q && *q != ':'; q++) - ; - *q++ = 0; - size_t pathlen = (q - p) + prglen; - char *path = new char[pathlen + 1]; - snprintf (path, pathlen + 1, "%s/%s", p, prg); - CADICAL_assert (strlen (path) == pathlen); - if (exists (path)) - res = path; - else - delete[] path; - } - delete[] e; - return res; -} - -/*------------------------------------------------------------------------*/ - -FILE *File::open_file (Internal *internal, const char *path, - const char *mode) { - (void) internal; - return fopen (path, mode); -} - -FILE *File::read_file (Internal *internal, const char *path) { - MSG ("opening file to read '%s'", path); - return open_file (internal, path, "r"); -} - -FILE *File::write_file (Internal *internal, const char *path) { - MSG ("opening file to write '%s'", path); - return open_file (internal, path, "wb"); -} - -/*------------------------------------------------------------------------*/ - -void File::split_str (const char *command, std::vector &argv) { - const char *c = command; - while (*c && *c == ' ') - c++; - while (*c) { - const char *p = c; - while (*p && *p != ' ') - p++; - const size_t bytes = p - c; - char *arg = new char[bytes + 1]; - (void) strncpy (arg, c, bytes); - arg[bytes] = 0; - argv.push_back (arg); - while (*p && *p == ' ') - p++; - c = p; - } -} - -void File::delete_str_vector (std::vector &argv) { - for (auto str : argv) - delete[] str; -} - -FILE *File::open_pipe (Internal *internal, const char *fmt, - const char *path, const char *mode) { -#ifdef CADICAL_QUIET - (void) internal; -#endif - size_t prglen = 0; - while (fmt[prglen] && fmt[prglen] != ' ') - prglen++; - char *prg = new char[prglen + 1]; - strncpy (prg, fmt, prglen); - prg[prglen] = 0; - char *found = find_program (prg); - if (found) - MSG ("found '%s' in path for '%s'", found, prg); - if (!found) - MSG ("did not find '%s' in path", prg); - delete[] prg; - if (!found) - return 0; - delete[] found; - size_t cmd_size = strlen (fmt) + strlen (path); - char *cmd = new char[cmd_size]; - snprintf (cmd, cmd_size, fmt, path); - FILE *res = popen (cmd, mode); - delete[] cmd; - return res; -} - -FILE *File::read_pipe (Internal *internal, const char *fmt, const int *sig, - const char *path) { - if (!File::exists (path)) { - LOG ("file '%s' does not exist", path); - return 0; - } - LOG ("file '%s' exists", path); - if (sig && !File::match (internal, path, sig)) - return 0; - LOG ("file '%s' matches signature for '%s'", path, fmt); - MSG ("opening pipe to read '%s'", path); - return open_pipe (internal, fmt, path, "r"); -} - -#ifndef _WIN32 - -#if defined(__APPLE__) || defined(__MACH__) -static std::mutex compressed_file_writing_mutex; -#endif - -FILE *File::write_pipe (Internal *internal, const char *command, - const char *path, int &child_pid) { - CADICAL_assert (command[0] && command[0] != ' '); - MSG ("writing through command '%s' to '%s'", command, path); -#ifdef CADICAL_QUIET - (void) internal; -#endif - std::vector args; - split_str (command, args); - CADICAL_assert (!args.empty ()); - args.push_back (0); - char **argv = args.data (); - char *absolute_command_path = find_program (argv[0]); - int pipe_fds[2], out; - FILE *res = 0; -#if defined(__APPLE__) || defined(__MACH__) - compressed_file_writing_mutex.lock (); -#endif - if (!absolute_command_path) - MSG ("could not find '%s' in 'PATH' environment variable", argv[0]); - else if (::pipe (pipe_fds) < 0) - MSG ("could not generate pipe to '%s' command", command); - else if ((out = ::open (path, O_CREAT | O_TRUNC | O_WRONLY, 0644)) < 0) - MSG ("could not open '%s' for writing", path); - else if ((child_pid = ::fork ()) < 0) { - MSG ("could not fork process to execute '%s' command", command); - ::close (out); - } else if (child_pid) { - ::close (pipe_fds[0]); - res = ::fdopen (pipe_fds[1], "wb"); - } else { - - // Connect stdin and stdout in child - - ::dup2 (pipe_fds[0], 0); - ::dup2 (out, 1); - - // Make sure to close all non-required fds to not cause hangs. - // This is handled now by closefrom and remains for documentation - // purposes: - // - // ::close (pipe_fds[0]); - // ::close (pipe_fds[1]); - // ::close (out); - - // Surpress '7z' verbose output on 'stderr'. - - if (command[0] == '7') { - ::close (2); - } - - // Before the fork another thread could have created more fds. These - // fds are cloned into the child process. As this inhibits pipes to - // be closed by the parent process we have to close all of the - // erroneously cloned fds here. - -#ifndef CADICAL_NCLOSEFROM - ::closefrom (3); -#else - // Simplistic replacement on Unix without 'closefrom'. - for (int fd = 3; fd != FD_SETSIZE; fd++) - ::close (fd); -#endif - execv (absolute_command_path, argv); - _exit (1); - } - if (absolute_command_path) - delete[] absolute_command_path; - delete_str_vector (args); -#ifdef CADICAL_QUIET - (void) internal; -#endif -#if defined(__APPLE__) || defined(__MACH__) - if (!res) - compressed_file_writing_mutex.unlock (); -#endif - return res; -} - -#endif - -/*------------------------------------------------------------------------*/ - -File *File::read (Internal *internal, FILE *f, const char *n) { - return new File (internal, false, 0, 0, f, n); -} - -File *File::write (Internal *internal, FILE *f, const char *n) { - return new File (internal, true, 0, 0, f, n); -} - -File *File::read (Internal *internal, const char *path) { - FILE *file; - int close_input = 2; - if (has_suffix (path, ".xz")) { - file = read_pipe (internal, "xz -c -d %s", xzsig, path); - if (!file) - goto READ_FILE; - } else if (has_suffix (path, ".lzma")) { - file = read_pipe (internal, "lzma -c -d %s", lzmasig, path); - if (!file) - goto READ_FILE; - } else if (has_suffix (path, ".bz2")) { - file = read_pipe (internal, "bzip2 -c -d %s", bz2sig, path); - if (!file) - goto READ_FILE; - } else if (has_suffix (path, ".gz")) { - file = read_pipe (internal, "gzip -c -d %s", gzsig, path); - if (!file) - goto READ_FILE; - } else if (has_suffix (path, ".7z")) { - file = read_pipe (internal, "7z x -so %s 2>/dev/null", sig7z, path); - if (!file) - goto READ_FILE; - } else { - READ_FILE: - file = read_file (internal, path); - close_input = 1; - } - - if (!file) - return 0; - - return new File (internal, false, close_input, 0, file, path); -} - -File *File::write (Internal *internal, const char *path) { - FILE *file; - int close_output = 3, child_pid = 0; -#ifndef _WIN32 - if (has_suffix (path, ".xz")) - file = write_pipe (internal, "xz -c", path, child_pid); - else if (has_suffix (path, ".bz2")) - file = write_pipe (internal, "bzip2 -c", path, child_pid); - else if (has_suffix (path, ".gz")) - file = write_pipe (internal, "gzip -c", path, child_pid); - else if (has_suffix (path, ".7z")) - file = write_pipe (internal, "7z a -an -txz -si -so", path, child_pid); - else -#endif - file = write_file (internal, path), close_output = 1; - - if (!file) - return 0; - - return new File (internal, true, close_output, child_pid, file, path); -} - -void File::close (bool print) { - CADICAL_assert (file); -#ifndef CADICAL_QUIET - if (internal->opts.quiet) - print = false; - else if (internal->opts.verbose > 0) - print = true; -#endif - if (close_file == 0) { - if (print) - MSG ("disconnecting from '%s'", name ()); - } - if (close_file == 1) { - if (print) - MSG ("closing file '%s'", name ()); - fclose (file); - } - if (close_file == 2) { - if (print) - MSG ("closing input pipe to read '%s'", name ()); - pclose (file); - } -#ifndef _WIN32 - if (close_file == 3) { - if (print) - MSG ("closing output pipe to write '%s'", name ()); - fclose (file); - waitpid (child_pid, 0, 0); -#if defined(__APPLE__) || defined(__MACH__) - compressed_file_writing_mutex.unlock (); -#endif - } -#endif - file = 0; // mark as closed - - // TODO what about error checking for 'fclose', 'pclose' or 'waitpid'? - -#ifndef CADICAL_QUIET - if (print) { - if (writing) { - uint64_t written_bytes = bytes (); - double written_mb = written_bytes / (double) (1 << 20); - MSG ("after writing %" PRIu64 " bytes %.1f MB", written_bytes, - written_mb); - if (close_file == 3) { - size_t actual_bytes = size (name ()); - if (actual_bytes) { - double actual_mb = actual_bytes / (double) (1 << 20); - MSG ("deflated to %zd bytes %.1f MB", actual_bytes, actual_mb); - MSG ("factor %.2f (%.2f%% compression)", - relative (written_bytes, actual_bytes), - percent (actual_bytes, written_bytes)); - } else - MSG ("but could not determine actual size of written file"); - } - } else { - uint64_t read_bytes = bytes (); - double read_mb = read_bytes / (double) (1 << 20); - MSG ("after reading %" PRIu64 " bytes %.1f MB", read_bytes, read_mb); - if (close_file == 2) { - size_t actual_bytes = size (name ()); - double actual_mb = actual_bytes / (double) (1 << 20); - MSG ("inflated from %zd bytes %.1f MB", actual_bytes, actual_mb); - MSG ("factor %.2f (%.2f%% compression)", - relative (read_bytes, actual_bytes), - percent (actual_bytes, read_bytes)); - } - } - } -#endif -} - -void File::flush () { - CADICAL_assert (file); - fflush (file); -} - -File::~File () { - if (file) - close (); - free (_name); -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_flags.cpp b/src/sat/cadical/cadical_flags.cpp deleted file mode 100644 index 5c06a33b4..000000000 --- a/src/sat/cadical/cadical_flags.cpp +++ /dev/null @@ -1,141 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -void Internal::mark_fixed (int lit) { - if (external->fixed_listener) { - int elit = externalize (lit); - CADICAL_assert (elit); - const int eidx = abs (elit); - if (!external->ervars[eidx]) - external->fixed_listener->notify_fixed_assignment (elit); - } - Flags &f = flags (lit); - CADICAL_assert (f.status == Flags::ACTIVE); - f.status = Flags::FIXED; - LOG ("fixed %d", abs (lit)); - stats.all.fixed++; - stats.now.fixed++; - stats.inactive++; - CADICAL_assert (stats.active); - stats.active--; - CADICAL_assert (!active (lit)); - CADICAL_assert (f.fixed ()); - - if (external_prop && private_steps) { - // If pre/inprocessing found a fixed assignment, we want the propagator - // to know about it. - // But at that point it is not guaranteed to be already on the trail, so - // notification will happen only later. - CADICAL_assert (!level); - } -} - -void Internal::mark_eliminated (int lit) { - Flags &f = flags (lit); - CADICAL_assert (f.status == Flags::ACTIVE); - f.status = Flags::ELIMINATED; - LOG ("eliminated %d", abs (lit)); - stats.all.eliminated++; - stats.now.eliminated++; - stats.inactive++; - CADICAL_assert (stats.active); - stats.active--; - CADICAL_assert (!active (lit)); - CADICAL_assert (f.eliminated ()); -} - -void Internal::mark_pure (int lit) { - Flags &f = flags (lit); - CADICAL_assert (f.status == Flags::ACTIVE); - f.status = Flags::PURE; - LOG ("pure %d", abs (lit)); - stats.all.pure++; - stats.now.pure++; - stats.inactive++; - CADICAL_assert (stats.active); - stats.active--; - CADICAL_assert (!active (lit)); - CADICAL_assert (f.pure ()); -} - -void Internal::mark_substituted (int lit) { - Flags &f = flags (lit); - CADICAL_assert (f.status == Flags::ACTIVE); - f.status = Flags::SUBSTITUTED; - LOG ("substituted %d", abs (lit)); - stats.all.substituted++; - stats.now.substituted++; - stats.inactive++; - CADICAL_assert (stats.active); - stats.active--; - CADICAL_assert (!active (lit)); - CADICAL_assert (f.substituted ()); -} - -void Internal::mark_active (int lit) { - Flags &f = flags (lit); - CADICAL_assert (f.status == Flags::UNUSED); - f.status = Flags::ACTIVE; - LOG ("activate %d previously unused", abs (lit)); - CADICAL_assert (stats.inactive); - stats.inactive--; - CADICAL_assert (stats.unused); - stats.unused--; - stats.active++; - CADICAL_assert (active (lit)); -} - -void Internal::reactivate (int lit) { - CADICAL_assert (!active (lit)); - Flags &f = flags (lit); - CADICAL_assert (f.status != Flags::FIXED); - CADICAL_assert (f.status != Flags::UNUSED); -#ifdef LOGGING - const char *msg = 0; -#endif - switch (f.status) { - default: - case Flags::ELIMINATED: - CADICAL_assert (f.status == Flags::ELIMINATED); - CADICAL_assert (stats.now.eliminated > 0); - stats.now.eliminated--; -#ifdef LOGGING - msg = "eliminated"; -#endif - break; - case Flags::SUBSTITUTED: -#ifdef LOGGING - msg = "substituted"; -#endif - CADICAL_assert (stats.now.substituted > 0); - stats.now.substituted--; - break; - case Flags::PURE: -#ifdef LOGGING - msg = "pure literal"; -#endif - CADICAL_assert (stats.now.pure > 0); - stats.now.pure--; - break; - } -#ifdef LOGGING - CADICAL_assert (msg); - LOG ("reactivate previously %s %d", msg, abs (lit)); -#endif - f.status = Flags::ACTIVE; - f.sweep = false; - CADICAL_assert (active (lit)); - stats.reactivated++; - CADICAL_assert (stats.inactive > 0); - stats.inactive--; - stats.active++; -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_flip.cpp b/src/sat/cadical/cadical_flip.cpp deleted file mode 100644 index a89e3abb7..000000000 --- a/src/sat/cadical/cadical_flip.cpp +++ /dev/null @@ -1,275 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -bool Internal::flip (int lit) { - - // Do not try to flip inactive literals except for unused variables. - - if (!active (lit) && !flags (lit).unused ()) - return false; - - /* - if (flags (lit).unused ()) { - CADICAL_assert (lit <= max_var); - mark_active (lit); - set_val (lit, 1); - return true; - } - */ - - // TODO: Unused case is not handled yet. - // if (flags (lit).unused ()) return false; - - // Need to reestablish proper watching invariants as if there are no - // blocking literals as flipping in principle does not work with them. - - if (propergated < trail.size ()) - propergate (); - - LOG ("trying to flip %d", lit); - - const int idx = vidx (lit); - const signed char original_value = vals[idx]; - CADICAL_assert (original_value); - lit = original_value < 0 ? -idx : idx; - CADICAL_assert (val (lit) > 0); - - // Here we go over all the clauses in which 'lit' is watched by 'lit' and - // check whether assigning 'lit' to false would break watching invariants - // or even make the clause false. We also try to find replacement - // watches in case this fixes the watching invariant. This code is very - // similar to propagation of a literal in 'Internal::propagate'. - - bool res = true; - - Watches &ws = watches (lit); - const const_watch_iterator eow = ws.end (); - watch_iterator bow = ws.begin (); - - // We first go over binary watches/clauses first as this is cheaper and - // has higher chance of failure and we can not use blocking literals. - - for (const_watch_iterator i = bow; i != eow; i++) { - const Watch w = *i; - if (!w.binary ()) - continue; - const signed char b = val (w.blit); - if (b > 0) - continue; - CADICAL_assert (b < 0); - res = false; - break; - } - - if (res) { - const_watch_iterator i = bow; - watch_iterator j = bow; - - while (i != eow) { - - const Watch w = *j++ = *i++; - - if (w.binary ()) - continue; - - if (w.clause->garbage) { - j--; - continue; - } - - literal_iterator lits = w.clause->begin (); - - const int other = lits[0] ^ lits[1] ^ lit; - const signed char u = val (other); - if (u > 0) - continue; - - const int size = w.clause->size; - const literal_iterator middle = lits + w.clause->pos; - const const_literal_iterator end = lits + size; - literal_iterator k = middle; - - int r = 0; - signed char v = -1; - while (k != end && (v = val (r = *k)) < 0) - k++; - if (v < 0) { - k = lits + 2; - CADICAL_assert (w.clause->pos <= size); - while (k != middle && (v = val (r = *k)) < 0) - k++; - } - - if (v < 0) { - res = false; - break; - } - - CADICAL_assert (v > 0); - CADICAL_assert (lits + 2 <= k), CADICAL_assert (k <= w.clause->end ()); - w.clause->pos = k - lits; - lits[0] = other, lits[1] = r, *k = lit; - watch_literal (r, lit, w.clause); - j--; - } - - if (j != i) { - - while (i != eow) - *j++ = *i++; - - ws.resize (j - ws.begin ()); - } - } -#ifdef LOGGING - if (res) - LOG ("literal %d can be flipped", lit); - else - LOG ("literal %d can not be flipped", lit); -#endif - - if (res) { - - const int idx = vidx (lit); - const signed char original_value = vals[idx]; - CADICAL_assert (original_value); - lit = original_value < 0 ? -idx : idx; - CADICAL_assert (val (lit) > 0); - - LOG ("flipping value of %d = 1 to %d = -1", lit, lit); - - set_val (idx, -original_value); - CADICAL_assert (val (-lit) > 0); - CADICAL_assert (val (lit) < 0); - - Var &v = var (idx); - CADICAL_assert (trail[v.trail] == lit); - trail[v.trail] = -lit; - if (opts.ilb) { - if (!tainted_literal) - tainted_literal = lit; - else { - CADICAL_assert (val (tainted_literal)); - if (v.level < var (tainted_literal).level) { - tainted_literal = lit; - } - } - } - } else - LOG ("flipping value of %d failed", lit); - - return res; -} - -bool Internal::flippable (int lit) { - - // Can not check inactive literals except for unused variables. - - if (!active (lit) && !flags (lit).unused ()) - return false; - - /* - if (flags (lit).unused ()) { - CADICAL_assert (lit <= max_var); - mark_active (lit); - return true; - } - */ - // TODO: Unused case is not handled yet - // if (flags (lit).unused ()) return false; - - // Need to reestablish proper watching invariants as if there are no - // blocking literals as flipping in principle does not work with them. - - if (propergated < trail.size ()) - propergate (); - - LOG ("checking whether %d is flippable", lit); - - const int idx = vidx (lit); - const signed char original_value = vals[idx]; - CADICAL_assert (original_value); - lit = original_value < 0 ? -idx : idx; - CADICAL_assert (val (lit) > 0); - - // Here we go over all the clauses in which 'lit' is watched by 'lit' and - // check whether assigning 'lit' to false would break watching invariants - // or even make the clause false. In contrast to 'flip' we do not try to - // find replacement literals but do use blocking literals'. Therefore we - // also do not split the traversal code into two parts. - - bool res = true; - - Watches &ws = watches (lit); - const const_watch_iterator eow = ws.end (); - for (watch_iterator i = ws.begin (); i != eow; i++) { - - const Watch w = *i; - const signed char b = val (w.blit); - if (b > 0) - continue; - CADICAL_assert (b < 0); - - if (w.binary ()) { - res = false; - break; - } - - if (w.clause->garbage) - continue; - - literal_iterator lits = w.clause->begin (); - - const int other = lits[0] ^ lits[1] ^ lit; - const signed char u = val (other); - if (u > 0) { - i->blit = other; - continue; - } - - const int size = w.clause->size; - const literal_iterator middle = lits + w.clause->pos; - const const_literal_iterator end = lits + size; - literal_iterator k = middle; - - int r = 0; - signed char v = -1; - while (k != end && (v = val (r = *k)) < 0) - k++; - if (v < 0) { - k = lits + 2; - CADICAL_assert (w.clause->pos <= size); - while (k != middle && (v = val (r = *k)) < 0) - k++; - } - - if (v < 0) { - res = false; - break; - } - - CADICAL_assert (v > 0); - CADICAL_assert (lits + 2 <= k); - CADICAL_assert (k <= w.clause->end ()); - w.clause->pos = k - lits; - i->blit = r; - } - -#ifdef LOGGING - if (res) - LOG ("literal %d can be flipped", lit); - else - LOG ("literal %d can not be flipped", lit); -#endif - - return res; -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_format.cpp b/src/sat/cadical/cadical_format.cpp deleted file mode 100644 index 942d9d74a..000000000 --- a/src/sat/cadical/cadical_format.cpp +++ /dev/null @@ -1,95 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -void Format::enlarge () { - char *old = buffer; - buffer = new char[size = size ? 2 * size : 1]; - memcpy (buffer, old, count); - delete[] old; -} - -inline void Format::push_char (char ch) { - if (size == count) - enlarge (); - buffer[count++] = ch; -} - -void Format::push_string (const char *s) { - char ch; - while ((ch = *s++)) - push_char (ch); -} - -void Format::push_int (int d) { - char tmp[16]; - snprintf (tmp, sizeof tmp, "%d", d); - push_string (tmp); -} - -void Format::push_uint64 (uint64_t u) { - char tmp[16]; - snprintf (tmp, sizeof tmp, "%" PRIu64, u); - push_string (tmp); -} - -static bool match_format (const char *&str, const char *pattern) { - CADICAL_assert (pattern); - const char *p = str; - const char *q = pattern; - while (*q) - if (*q++ != *p++) - return false; - str = p; - return true; -} - -const char *Format::add (const char *fmt, va_list &ap) { - const char *p = fmt; - char ch; - while ((ch = *p++)) { - if (ch != '%') - push_char (ch); - else if (*p == 'c') - push_char (va_arg (ap, int)), p++; - else if (*p == 'd') - push_int (va_arg (ap, int)), p++; - else if (*p == 's') - push_string (va_arg (ap, const char *)), p++; - else if (match_format (p, PRIu64)) - push_uint64 (va_arg (ap, uint64_t)); - else { - push_char ('%'); - push_char (*p); - break; - } // unsupported - } - push_char (0); - count--; // thus automatic append in subsequent calls. - return buffer; -} - -const char *Format::init (const char *fmt, ...) { - count = 0; - va_list ap; - va_start (ap, fmt); - const char *res = add (fmt, ap); - va_end (ap); - return res; -} - -const char *Format::append (const char *fmt, ...) { - va_list ap; - va_start (ap, fmt); - const char *res = add (fmt, ap); - va_end (ap); - return res; -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_frattracer.cpp b/src/sat/cadical/cadical_frattracer.cpp deleted file mode 100644 index d35a18271..000000000 --- a/src/sat/cadical/cadical_frattracer.cpp +++ /dev/null @@ -1,283 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -/*------------------------------------------------------------------------*/ - -FratTracer::FratTracer (Internal *i, File *f, bool b, bool a) - : internal (i), file (f), binary (b), with_antecedents (a) -#ifndef CADICAL_QUIET - , - added (0), deleted (0), finalized (0), original (0) -#endif -{ - (void) internal; -} - -void FratTracer::connect_internal (Internal *i) { - internal = i; - file->connect_internal (internal); - LOG ("FRAT TRACER connected to internal"); -} - -FratTracer::~FratTracer () { - LOG ("FRAT TRACER delete"); - delete file; -} - -/*------------------------------------------------------------------------*/ - -inline void FratTracer::put_binary_zero () { - CADICAL_assert (binary); - CADICAL_assert (file); - file->put ((unsigned char) 0); -} - -inline void FratTracer::put_binary_lit (int lit) { - CADICAL_assert (binary); - CADICAL_assert (file); - CADICAL_assert (lit != INT_MIN); - unsigned x = 2 * abs (lit) + (lit < 0); - unsigned char ch; - while (x & ~0x7f) { - ch = (x & 0x7f) | 0x80; - file->put (ch); - x >>= 7; - } - ch = x; - file->put (ch); -} - -inline void FratTracer::put_binary_id (int64_t id, bool can_be_negative) { - CADICAL_assert (binary); - CADICAL_assert (file); - uint64_t x = abs (id); - if (can_be_negative) { - x = 2 * x + (id < 0); - } - unsigned char ch; - while (x & ~0x7f) { - ch = (x & 0x7f) | 0x80; - file->put (ch); - x >>= 7; - } - ch = x; - file->put (ch); -} - -/*------------------------------------------------------------------------*/ - -void FratTracer::frat_add_original_clause (int64_t id, - const vector &clause) { - if (binary) - file->put ('o'); - else - file->put ("o "); - if (binary) - put_binary_id (id); - else - file->put (id), file->put (" "); - for (const auto &external_lit : clause) - if (binary) - put_binary_lit (external_lit); - else - file->put (external_lit), file->put (' '); - if (binary) - put_binary_zero (); - else - file->put ("0\n"); -} - -void FratTracer::frat_add_derived_clause (int64_t id, - const vector &clause) { - if (binary) - file->put ('a'); - else - file->put ("a "); - if (binary) - put_binary_id (id); - else - file->put (id), file->put (" "); - for (const auto &external_lit : clause) - if (binary) - put_binary_lit (external_lit); - else - file->put (external_lit), file->put (' '); - if (binary) - put_binary_zero (); - else - file->put ("0\n"); -} - -void FratTracer::frat_add_derived_clause (int64_t id, - const vector &clause, - const vector &chain) { - if (binary) - file->put ('a'); - else - file->put ("a "); - if (binary) - put_binary_id (id); - else - file->put (id), file->put (" "); - for (const auto &external_lit : clause) - if (binary) - put_binary_lit (external_lit); - else - file->put (external_lit), file->put (' '); - if (binary) - put_binary_zero (), file->put ('l'); - else - file->put ("0 l "); - for (const auto &c : chain) - if (binary) - put_binary_id (c, true); // LRAT can have negative ids - else - file->put (c), file->put (' '); // in proof chain, so they get - if (binary) - put_binary_zero (); // since cadical has no rat-steps - else - file->put ("0\n"); // this is just 2c here -} - -void FratTracer::frat_delete_clause (int64_t id, - const vector &clause) { - if (binary) - file->put ('d'); - else - file->put ("d "); - if (binary) - put_binary_id (id); - else - file->put (id), file->put (" "); - for (const auto &external_lit : clause) - if (binary) - put_binary_lit (external_lit); - else - file->put (external_lit), file->put (' '); - if (binary) - put_binary_zero (); - else - file->put ("0\n"); -} - -void FratTracer::frat_finalize_clause (int64_t id, - const vector &clause) { - if (binary) - file->put ('f'); - else - file->put ("f "); - if (binary) - put_binary_id (id); - else - file->put (id), file->put (" "); - for (const auto &external_lit : clause) - if (binary) - put_binary_lit (external_lit); - else - file->put (external_lit), file->put (' '); - if (binary) - put_binary_zero (); - else - file->put ("0\n"); -} - -/*------------------------------------------------------------------------*/ - -void FratTracer::add_original_clause (int64_t id, bool, - const vector &clause, bool) { - if (file->closed ()) - return; - LOG ("FRAT TRACER tracing addition of original clause"); - frat_add_original_clause (id, clause); -} - -void FratTracer::add_derived_clause (int64_t id, bool, - const vector &clause, - const vector &chain) { - if (file->closed ()) - return; - LOG ("FRAT TRACER tracing addition of derived clause"); - if (with_antecedents) - frat_add_derived_clause (id, clause, chain); - else - frat_add_derived_clause (id, clause); -#ifndef CADICAL_QUIET - added++; -#endif -} - -void FratTracer::delete_clause (int64_t id, bool, - const vector &clause) { - if (file->closed ()) - return; - LOG ("FRAT TRACER tracing deletion of clause"); - frat_delete_clause (id, clause); -#ifndef CADICAL_QUIET - deleted++; -#endif -} - -void FratTracer::finalize_clause (int64_t id, const vector &clause) { - if (file->closed ()) - return; - LOG ("FRAT TRACER tracing finalization of clause"); - frat_finalize_clause (id, clause); -} - -/*------------------------------------------------------------------------*/ - -bool FratTracer::closed () { return file->closed (); } - -#ifndef CADICAL_QUIET - -void FratTracer::print_statistics () { - uint64_t bytes = file->bytes (); - uint64_t total = original + added + deleted + finalized; - MSG ("FRAT %" PRId64 " original clauses %.2f%%", original, - percent (original, total)); - MSG ("FRAT %" PRId64 " added clauses %.2f%%", added, - percent (added, total)); - MSG ("FRAT %" PRId64 " deleted clauses %.2f%%", deleted, - percent (deleted, total)); - MSG ("FRAT %" PRId64 " finalized clauses %.2f%%", finalized, - percent (finalized, total)); - MSG ("FRAT %" PRId64 " bytes (%.2f MB)", bytes, - bytes / (double) (1 << 20)); -} - -#endif - -void FratTracer::close (bool print) { - CADICAL_assert (!closed ()); - file->close (); -#ifndef CADICAL_QUIET - if (print) { - MSG ("FRAT proof file '%s' closed", file->name ()); - print_statistics (); - } -#else - (void) print; -#endif -} - -void FratTracer::flush (bool print) { - CADICAL_assert (!closed ()); - file->flush (); -#ifndef CADICAL_QUIET - if (print) { - MSG ("FRAT proof file '%s' flushed", file->name ()); - print_statistics (); - } -#else - (void) print; -#endif -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_gates.cpp b/src/sat/cadical/cadical_gates.cpp deleted file mode 100644 index 06a73d1eb..000000000 --- a/src/sat/cadical/cadical_gates.cpp +++ /dev/null @@ -1,772 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -/*------------------------------------------------------------------------*/ - -// As in our original SATeLite published at SAT'05 we are trying to find -// gates in order to restrict the number of resolutions that need to be -// tried. If there is such a gate, we only need to consider resolvents -// among gate and one non-gate clauses. Resolvents between definitions will -// be tautological anyhow and resolvents among non-gates can actually be -// shown to be redundant too. - -/*------------------------------------------------------------------------*/ - -// The next function returns a non-zero if the clause 'c', which is assumed -// to contain the literal 'first', after removing falsified literals is a -// binary clause. Then the actual second literal is returned. - -int Internal::second_literal_in_binary_clause (Eliminator &eliminator, - Clause *c, int first) { - CADICAL_assert (!c->garbage); - int second = 0; - for (const auto &lit : *c) { - if (lit == first) - continue; - const signed char tmp = val (lit); - if (tmp < 0) - continue; - if (tmp > 0) { - mark_garbage (c); - elim_update_removed_clause (eliminator, c); - return 0; - } - if (second) { - second = INT_MIN; - break; - } - second = lit; - } - if (!second) - return 0; - if (second == INT_MIN) - return 0; - CADICAL_assert (active (second)); -#ifdef LOGGING - if (c->size == 2) - LOG (c, "found binary"); - else - LOG (c, "found actual binary %d %d", first, second); -#endif - return second; -} - -/*------------------------------------------------------------------------*/ - -// need a copy from above that does not care about garbage - -int Internal::second_literal_in_binary_clause_lrat (Clause *c, int first) { - if (c->garbage) - return 0; - int second = 0; - for (const auto &lit : *c) { - if (lit == first) - continue; - const signed char tmp = val (lit); - if (tmp < 0) - continue; - if (tmp > 0) - return 0; - if (!tmp) { - if (second) { - second = INT_MIN; - break; - } - second = lit; - } - } - if (!second) - return 0; - if (second == INT_MIN) - return 0; - return second; -} - -// I needed to find the second clause for hyper unary resolution to build -// LRAT this is not efficient but I could not find a better way then just -// finding the corresponding clause in all possible clauses -// -Clause *Internal::find_binary_clause (int first, int second) { - int best = first; - int other = second; - if (occs (first).size () > occs (second).size ()) { - best = second; - other = first; - } - for (auto c : occs (best)) - if (second_literal_in_binary_clause_lrat (c, best) == other) - return c; - return 0; -} - -/*------------------------------------------------------------------------*/ - -// Mark all other literals in binary clauses with 'first'. During this -// marking we might also detect hyper unary resolvents producing a unit. -// If such a unit is found we propagate it and return immediately. - -void Internal::mark_binary_literals (Eliminator &eliminator, int first) { - - if (unsat) - return; - if (val (first)) - return; - if (!eliminator.gates.empty ()) - return; - - CADICAL_assert (!marked (first)); - CADICAL_assert (eliminator.marked.empty ()); - - const Occs &os = occs (first); - for (const auto &c : os) { - if (c->garbage) - continue; - const int second = - second_literal_in_binary_clause (eliminator, c, first); - if (!second) - continue; - const int tmp = marked (second); - if (tmp < 0) { - // had a bug where units could occur multiple times here - // solved with flags - LOG ("found binary resolved unit %d", first); - if (lrat) { - Clause *d = find_binary_clause (first, -second); - CADICAL_assert (d); - for (auto &lit : *d) { - if (lit == first || lit == -second) - continue; - CADICAL_assert (val (lit) < 0); - Flags &f = flags (lit); - if (f.seen) - continue; - analyzed.push_back (lit); - f.seen = true; - int64_t id = unit_id (-lit); - lrat_chain.push_back (id); - // LOG ("gates added id %" PRId64, id); - } - for (auto &lit : *c) { - if (lit == first || lit == second) - continue; - CADICAL_assert (val (lit) < 0); - Flags &f = flags (lit); - if (f.seen) - continue; - analyzed.push_back (lit); - f.seen = true; - int64_t id = unit_id (-lit); - lrat_chain.push_back (id); - // LOG ("gates added id %" PRId64, id); - } - lrat_chain.push_back (c->id); - lrat_chain.push_back (d->id); - // LOG ("gates added id %" PRId64, c->id); - // LOG ("gates added id %" PRId64, d->id); - clear_analyzed_literals (); - } - assign_unit (first); - elim_propagate (eliminator, first); - return; - } - if (tmp > 0) { - LOG (c, "duplicated actual binary clause"); - elim_update_removed_clause (eliminator, c); - mark_garbage (c); - continue; - } - eliminator.marked.push_back (second); - mark (second); - LOG ("marked second literal %d in binary clause %d %d", second, first, - second); - } -} - -// Unmark all literals saved on the 'marked' stack. - -void Internal::unmark_binary_literals (Eliminator &eliminator) { - LOG ("unmarking %zd literals", eliminator.marked.size ()); - for (const auto &lit : eliminator.marked) - unmark (lit); - eliminator.marked.clear (); -} - -/*------------------------------------------------------------------------*/ - -// Find equivalence for 'pivot'. Requires that all other literals in binary -// clauses with 'pivot' are marked (through 'mark_binary_literals'); - -void Internal::find_equivalence (Eliminator &eliminator, int pivot) { - - if (!opts.elimequivs) - return; - - CADICAL_assert (opts.elimsubst); - - if (unsat) - return; - if (val (pivot)) - return; - if (!eliminator.gates.empty ()) - return; - - mark_binary_literals (eliminator, pivot); - if (unsat || val (pivot)) - goto DONE; - - for (const auto &c : occs (-pivot)) { - - if (c->garbage) - continue; - - const int second = - second_literal_in_binary_clause (eliminator, c, -pivot); - if (!second) - continue; - const int tmp = marked (second); - if (tmp > 0) { - LOG ("found binary resolved unit %d", second); - // did not find a bug where units could occur multiple times here - // still solved potential issues with flags - if (lrat) { - Clause *d = find_binary_clause (pivot, second); - CADICAL_assert (d); - for (auto &lit : *d) { - if (lit == pivot || lit == second) - continue; - CADICAL_assert (val (lit) < 0); - Flags &f = flags (lit); - if (f.seen) - continue; - analyzed.push_back (lit); - f.seen = true; - int64_t id = unit_id (-lit); - lrat_chain.push_back (id); - // LOG ("gates added id %" PRId64, id); - } - for (auto &lit : *c) { - if (lit == -pivot || lit == second) - continue; - CADICAL_assert (val (lit) < 0); - Flags &f = flags (lit); - if (f.seen) - continue; - analyzed.push_back (lit); - f.seen = true; - int64_t id = unit_id (-lit); - lrat_chain.push_back (id); - // LOG ("gates added id %" PRId64, id); - } - lrat_chain.push_back (c->id); - lrat_chain.push_back (d->id); - clear_analyzed_literals (); - // LOG ("gates added id %" PRId64, c->id); - // LOG ("gates added id %" PRId64, d->id); - } - assign_unit (second); - elim_propagate (eliminator, second); - if (val (pivot)) - break; - if (unsat) - break; - } - if (tmp >= 0) - continue; - - LOG ("found equivalence %d = %d", pivot, -second); - stats.elimequivs++; - stats.elimgates++; - - LOG (c, "first gate clause"); - CADICAL_assert (!c->gate); - c->gate = true; - eliminator.gates.push_back (c); - - Clause *d = 0; - const Occs &ps = occs (pivot); - for (const auto &e : ps) { - if (e->garbage) - continue; - const int other = - second_literal_in_binary_clause (eliminator, e, pivot); - if (other == -second) { - d = e; - break; - } - } - CADICAL_assert (d); - - LOG (d, "second gate clause"); - CADICAL_assert (!d->gate); - d->gate = true; - eliminator.gates.push_back (d); - eliminator.gatetype = EQUI; - - break; - } - -DONE: - unmark_binary_literals (eliminator); -} - -/*------------------------------------------------------------------------*/ - -// Find and gates for 'pivot' with a long clause, in which the pivot occurs -// positively. Requires that all other literals in binary clauses with -// 'pivot' are marked (through 'mark_binary_literals'); - -void Internal::find_and_gate (Eliminator &eliminator, int pivot) { - - if (!opts.elimands) - return; - - CADICAL_assert (opts.elimsubst); - - if (unsat) - return; - if (val (pivot)) - return; - if (!eliminator.gates.empty ()) - return; - - mark_binary_literals (eliminator, pivot); - if (unsat || val (pivot)) - goto DONE; - - for (const auto &c : occs (-pivot)) { - - if (c->garbage) - continue; - if (c->size < 3) - continue; - - bool all_literals_marked = true; - unsigned arity = 0; - int satisfied = 0; - - for (const auto &lit : *c) { - if (lit == -pivot) - continue; - CADICAL_assert (lit != pivot); - signed char tmp = val (lit); - if (tmp < 0) - continue; - if (tmp > 0) { - satisfied = lit; - break; - } - tmp = marked (lit); - if (tmp < 0) { - arity++; - continue; - } - all_literals_marked = false; - break; - } - - if (!all_literals_marked) - continue; - - if (satisfied) { - LOG (c, "satisfied by %d candidate base clause", satisfied); - mark_garbage (c); - continue; - } - -#ifdef LOGGING - if (opts.log) { - Logger::print_log_prefix (this); - tout.magenta (); - printf ("found arity %u AND gate %d = ", arity, -pivot); - bool first = true; - for (const auto &lit : *c) { - if (lit == -pivot) - continue; - CADICAL_assert (lit != pivot); - if (!first) - fputs (" & ", stdout); - printf ("%d", -lit); - first = false; - } - fputc ('\n', stdout); - tout.normal (); - fflush (stdout); - } -#endif - stats.elimands++; - stats.elimgates++; - eliminator.gatetype = AND; - - (void) arity; - CADICAL_assert (!c->gate); - c->gate = true; - eliminator.gates.push_back (c); - for (const auto &lit : *c) { - if (lit == -pivot) - continue; - CADICAL_assert (lit != pivot); - signed char tmp = val (lit); - if (tmp < 0) - continue; - CADICAL_assert (!tmp); - CADICAL_assert (marked (lit) < 0); - marks[vidx (lit)] *= 2; - } - - unsigned count = 0; - for (const auto &d : occs (pivot)) { - if (d->garbage) - continue; - const int other = - second_literal_in_binary_clause (eliminator, d, pivot); - if (!other) - continue; - const int tmp = marked (other); - if (tmp != 2) - continue; - LOG (d, "AND gate binary side clause"); - CADICAL_assert (!d->gate); - d->gate = true; - eliminator.gates.push_back (d); - count++; - } - CADICAL_assert (count >= arity); - (void) count; - - break; - } - -DONE: - unmark_binary_literals (eliminator); -} - -/*------------------------------------------------------------------------*/ - -// Find and extract ternary clauses. - -bool Internal::get_ternary_clause (Clause *d, int &a, int &b, int &c) { - if (d->garbage) - return false; - if (d->size < 3) - return false; - int found = 0; - a = b = c = 0; - for (const auto &lit : *d) { - if (val (lit)) - continue; - if (++found == 1) - a = lit; - else if (found == 2) - b = lit; - else if (found == 3) - c = lit; - else - return false; - } - return found == 3; -} - -// This function checks whether 'd' exists as ternary clause. - -bool Internal::match_ternary_clause (Clause *d, int a, int b, int c) { - if (d->garbage) - return false; - int found = 0; - for (const auto &lit : *d) { - if (val (lit)) - continue; - if (a != lit && b != lit && c != lit) - return false; - found++; - } - return found == 3; -} - -Clause *Internal::find_ternary_clause (int a, int b, int c) { - if (occs (b).size () > occs (c).size ()) - swap (b, c); - if (occs (a).size () > occs (b).size ()) - swap (a, b); - for (auto d : occs (a)) - if (match_ternary_clause (d, a, b, c)) - return d; - return 0; -} - -/*------------------------------------------------------------------------*/ - -// Find if-then-else gate. - -void Internal::find_if_then_else (Eliminator &eliminator, int pivot) { - - if (!opts.elimites) - return; - - CADICAL_assert (opts.elimsubst); - - if (unsat) - return; - if (val (pivot)) - return; - if (!eliminator.gates.empty ()) - return; - - const Occs &os = occs (pivot); - const auto end = os.end (); - for (auto i = os.begin (); i != end; i++) { - Clause *di = *i; - int ai, bi, ci; - if (!get_ternary_clause (di, ai, bi, ci)) - continue; - if (bi == pivot) - swap (ai, bi); - if (ci == pivot) - swap (ai, ci); - CADICAL_assert (ai == pivot); - for (auto j = i + 1; j != end; j++) { - Clause *dj = *j; - int aj, bj, cj; - if (!get_ternary_clause (dj, aj, bj, cj)) - continue; - if (bj == pivot) - swap (aj, bj); - if (cj == pivot) - swap (aj, cj); - CADICAL_assert (aj == pivot); - if (abs (bi) == abs (cj)) - swap (bj, cj); - if (abs (ci) == abs (cj)) - continue; - if (bi != -bj) - continue; - Clause *d1 = find_ternary_clause (-pivot, bi, -ci); - if (!d1) - continue; - Clause *d2 = find_ternary_clause (-pivot, bj, -cj); - if (!d2) - continue; - LOG (di, "1st if-then-else"); - LOG (dj, "2nd if-then-else"); - LOG (d1, "3rd if-then-else"); - LOG (d2, "4th if-then-else"); - LOG ("found ITE gate %d == (%d ? %d : %d)", pivot, -bi, -ci, -cj); - CADICAL_assert (!di->gate); - CADICAL_assert (!dj->gate); - CADICAL_assert (!d1->gate); - CADICAL_assert (!d2->gate); - di->gate = true; - dj->gate = true; - d1->gate = true; - d2->gate = true; - eliminator.gates.push_back (di); - eliminator.gates.push_back (dj); - eliminator.gates.push_back (d1); - eliminator.gates.push_back (d2); - stats.elimgates++; - stats.elimites++; - eliminator.gatetype = ITE; - return; - } - } -} - -/*------------------------------------------------------------------------*/ - -// Find and extract clause. - -bool Internal::get_clause (Clause *c, vector &l) { - if (c->garbage) - return false; - l.clear (); - for (const auto &lit : *c) { - if (val (lit) < 0) - continue; - if (val (lit) > 0) { - l.clear (); - return false; - } - l.push_back (lit); - } - return true; -} - -// Check whether 'c' contains only the literals in 'l'. - -bool Internal::is_clause (Clause *c, const vector &lits) { - if (c->garbage) - return false; - int size = lits.size (); - if (c->size < size) - return false; - int found = 0; - for (const auto &lit : *c) { - if (val (lit) < 0) - continue; - if (val (lit) > 0) - return false; - const auto it = find (lits.begin (), lits.end (), lit); - if (it == lits.end ()) - return false; - if (++found > size) - return false; - } - return found == size; -} - -Clause *Internal::find_clause (const vector &lits) { - int best = 0; - size_t len = 0; - for (const auto &lit : lits) { - size_t l = occs (lit).size (); - if (best && l >= len) - continue; - len = l, best = lit; - } - for (auto c : occs (best)) - if (is_clause (c, lits)) - return c; - return 0; -} - -void Internal::find_xor_gate (Eliminator &eliminator, int pivot) { - - if (!opts.elimxors) - return; - - CADICAL_assert (opts.elimsubst); - - if (unsat) - return; - if (val (pivot)) - return; - if (!eliminator.gates.empty ()) - return; - - vector lits; - - for (auto d : occs (pivot)) { - - if (!get_clause (d, lits)) - continue; - - const int size = lits.size (); // clause size - const int arity = size - 1; // arity of XOR - - if (size < 3) - continue; - if (arity > opts.elimxorlim) - continue; - - CADICAL_assert (eliminator.gates.empty ()); - - unsigned needed = (1u << arity) - 1; // additional clauses - unsigned signs = 0; // literals to negate - - do { - const unsigned prev = signs; - while (parity (++signs)) - ; - for (int j = 0; j < size; j++) { - const unsigned bit = 1u << j; - int lit = lits[j]; - if ((prev & bit) != (signs & bit)) - lits[j] = lit = -lit; - } - Clause *e = find_clause (lits); - if (!e) - break; - eliminator.gates.push_back (e); - } while (--needed); - - if (needed) { - eliminator.gates.clear (); - continue; - } - - eliminator.gates.push_back (d); - CADICAL_assert (eliminator.gates.size () == (1u << arity)); - -#ifdef LOGGING - if (opts.log) { - Logger::print_log_prefix (this); - tout.magenta (); - printf ("found arity %u XOR gate %d = ", arity, -pivot); - bool first = true; - for (const auto &lit : *d) { - if (lit == pivot) - continue; - CADICAL_assert (lit != -pivot); - if (!first) - fputs (" ^ ", stdout); - printf ("%d", lit); - first = false; - } - fputc ('\n', stdout); - tout.normal (); - fflush (stdout); - } -#endif - stats.elimgates++; - stats.elimxors++; - const auto end = eliminator.gates.end (); - auto j = eliminator.gates.begin (); - for (auto i = j; i != end; i++) { - Clause *e = *i; - if (e->gate) - continue; - e->gate = true; - LOG (e, "contributing"); - *j++ = e; - } - eliminator.gates.resize (j - eliminator.gates.begin ()); - eliminator.gatetype = XOR; - break; - } -} - -/*------------------------------------------------------------------------*/ - -// Find a gate for 'pivot'. If such a gate is found, the gate clauses are -// marked and pushed on the stack of gates. Further hyper unary resolution -// might detect units, which are propagated. This might assign the pivot or -// even produce the empty clause. - -void Internal::find_gate_clauses (Eliminator &eliminator, int pivot) { - if (!opts.elimsubst) - return; - - if (unsat) - return; - if (val (pivot)) - return; - - CADICAL_assert (eliminator.gates.empty ()); - - find_equivalence (eliminator, pivot); - find_and_gate (eliminator, pivot); - find_and_gate (eliminator, -pivot); - find_if_then_else (eliminator, pivot); - find_xor_gate (eliminator, pivot); - find_definition (eliminator, pivot); -} - -void Internal::unmark_gate_clauses (Eliminator &eliminator) { - LOG ("unmarking %zd gate clauses", eliminator.gates.size ()); - for (const auto &c : eliminator.gates) { - CADICAL_assert (c->gate); - c->gate = false; - } - eliminator.gates.clear (); - eliminator.definition_unit = 0; -} - -/*------------------------------------------------------------------------*/ - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_idruptracer.cpp b/src/sat/cadical/cadical_idruptracer.cpp deleted file mode 100644 index ec6467163..000000000 --- a/src/sat/cadical/cadical_idruptracer.cpp +++ /dev/null @@ -1,572 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -/*------------------------------------------------------------------------*/ - -IdrupTracer::IdrupTracer (Internal *i, File *f, bool b) - : internal (i), file (f), binary (b), num_clauses (0), size_clauses (0), - clauses (0), last_hash (0), last_id (0), last_clause (0) -#ifndef CADICAL_QUIET - , - added (0), deleted (0) -#endif -{ - (void) internal; - - // Initialize random number table for hash function. - // - Random random (42); - for (unsigned n = 0; n < num_nonces; n++) { - uint64_t nonce = random.next (); - if (!(nonce & 1)) - nonce++; - CADICAL_assert (nonce), CADICAL_assert (nonce & 1); - nonces[n] = nonce; - } -#ifndef CADICAL_NDEBUG - binary = b; -#else - (void) b; -#endif - piping = file->piping (); -} - -void IdrupTracer::connect_internal (Internal *i) { - internal = i; - file->connect_internal (internal); - LOG ("IDRUP TRACER connected to internal"); -} - -IdrupTracer::~IdrupTracer () { - LOG ("IDRUP TRACER delete"); - delete file; - for (size_t i = 0; i < size_clauses; i++) - for (IdrupClause *c = clauses[i], *next; c; c = next) - next = c->next, delete_clause (c); - delete[] clauses; -} - -/*------------------------------------------------------------------------*/ - -void IdrupTracer::enlarge_clauses () { - CADICAL_assert (num_clauses == size_clauses); - const uint64_t new_size_clauses = size_clauses ? 2 * size_clauses : 1; - LOG ("IDRUP Tracer enlarging clauses of tracer from %" PRIu64 - " to %" PRIu64, - (uint64_t) size_clauses, (uint64_t) new_size_clauses); - IdrupClause **new_clauses; - new_clauses = new IdrupClause *[new_size_clauses]; - clear_n (new_clauses, new_size_clauses); - for (uint64_t i = 0; i < size_clauses; i++) { - for (IdrupClause *c = clauses[i], *next; c; c = next) { - next = c->next; - const uint64_t h = reduce_hash (c->hash, new_size_clauses); - c->next = new_clauses[h]; - new_clauses[h] = c; - } - } - delete[] clauses; - clauses = new_clauses; - size_clauses = new_size_clauses; -} - -IdrupClause *IdrupTracer::new_clause () { - const size_t size = imported_clause.size (); - CADICAL_assert (size <= UINT_MAX); - const int off = size ? -1 : 0; - const size_t bytes = sizeof (IdrupClause) + (size - off) * sizeof (int); - IdrupClause *res = (IdrupClause *) new char[bytes]; - res->next = 0; - res->hash = last_hash; - res->id = last_id; - res->size = size; - int *literals = res->literals, *p = literals; - for (const auto &lit : imported_clause) { - *p++ = lit; - } - last_clause = res; - num_clauses++; - return res; -} - -void IdrupTracer::delete_clause (IdrupClause *c) { - CADICAL_assert (c); - num_clauses--; - delete[] (char *) c; -} - -uint64_t IdrupTracer::reduce_hash (uint64_t hash, uint64_t size) { - CADICAL_assert (size > 0); - unsigned shift = 32; - uint64_t res = hash; - while ((((uint64_t) 1) << shift) > size) { - res ^= res >> shift; - shift >>= 1; - } - res &= size - 1; - CADICAL_assert (res < size); - return res; -} - -uint64_t IdrupTracer::compute_hash (const int64_t id) { - CADICAL_assert (id > 0); - unsigned j = id % num_nonces; - uint64_t tmp = nonces[j] * (uint64_t) id; - return last_hash = tmp; -} - -bool IdrupTracer::find_and_delete (const int64_t id) { - if (!num_clauses) - return false; - IdrupClause **res = 0, *c; - const uint64_t hash = compute_hash (id); - const uint64_t h = reduce_hash (hash, size_clauses); - for (res = clauses + h; (c = *res); res = &c->next) { - if (c->hash == hash && c->id == id) { - break; - } - if (!c->next) - return false; - } - if (!c) - return false; - CADICAL_assert (c && res); - *res = c->next; - int *begin = c->literals; - for (size_t i = 0; i < c->size; i++) { - imported_clause.push_back (begin[i]); - } - delete_clause (c); - return true; -} - -void IdrupTracer::insert () { - if (num_clauses == size_clauses) - enlarge_clauses (); - const uint64_t h = reduce_hash (compute_hash (last_id), size_clauses); - IdrupClause *c = new_clause (); - c->next = clauses[h]; - clauses[h] = c; -} - -/*------------------------------------------------------------------------*/ - -inline void IdrupTracer::flush_if_piping () { - if (piping) - file->flush (); -} - -inline void IdrupTracer::put_binary_zero () { - CADICAL_assert (binary); - CADICAL_assert (file); - file->put ((unsigned char) 0); -} - -inline void IdrupTracer::put_binary_lit (int lit) { - CADICAL_assert (binary); - CADICAL_assert (file); - CADICAL_assert (lit != INT_MIN); - unsigned x = 2 * abs (lit) + (lit < 0); - unsigned char ch; - while (x & ~0x7f) { - ch = (x & 0x7f) | 0x80; - file->put (ch); - x >>= 7; - } - ch = x; - file->put (ch); -} - -inline void IdrupTracer::put_binary_id (int64_t id, bool can_be_negative) { - CADICAL_assert (binary); - CADICAL_assert (file); - uint64_t x = abs (id); - if (can_be_negative) { - x = 2 * x + (id < 0); - } - unsigned char ch; - while (x & ~0x7f) { - ch = (x & 0x7f) | 0x80; - file->put (ch); - x >>= 7; - } - ch = x; - file->put (ch); -} - -/*------------------------------------------------------------------------*/ - -void IdrupTracer::idrup_add_restored_clause (const vector &clause) { - if (binary) - file->put ('r'); - else - file->put ("r "); - for (const auto &external_lit : clause) - if (binary) - put_binary_lit (external_lit); - else - file->put (external_lit), file->put (' '); - if (binary) - put_binary_zero (); - else - file->put ("0\n"); - // flush_if_piping (); -} - -void IdrupTracer::idrup_add_derived_clause (const vector &clause) { - if (binary) - file->put ('l'); - else - file->put ("l "); - for (const auto &external_lit : clause) - if (binary) - put_binary_lit (external_lit); - else - file->put (external_lit), file->put (' '); - if (binary) - put_binary_zero (); - else - file->put ("0\n"); - // flush_if_piping (); -} - -void IdrupTracer::idrup_add_original_clause (const vector &clause) { - if (binary) - file->put ('i'); - else - file->put ("i "); - for (const auto &external_lit : clause) - if (binary) - put_binary_lit (external_lit); - else - file->put (external_lit), file->put (' '); - if (binary) - put_binary_zero (); - else - file->put ("0\n"); - // flush_if_piping (); -} - -void IdrupTracer::idrup_delete_clause (int64_t id, - const vector &clause) { - if (find_and_delete (id)) { - CADICAL_assert (imported_clause.empty ()); - if (binary) - file->put ('w'); - else - file->put ("w "); -#ifndef CADICAL_QUIET - weakened++; -#endif - } else { - if (binary) - file->put ('d'); - else - file->put ("d "); -#ifndef CADICAL_QUIET - deleted++; -#endif - } - for (const auto &external_lit : clause) - if (binary) - put_binary_lit (external_lit); - else - file->put (external_lit), file->put (' '); - if (binary) - put_binary_zero (); - else - file->put ("0\n"); - // flush_if_piping (); -} - -void IdrupTracer::idrup_conclude_and_delete ( - const vector &conclusion) { - uint64_t size = conclusion.size (); - if (size > 1) { - if (binary) { - file->put ('U'); - put_binary_id (size); - } else { - file->put ("U "); - file->put (size), file->put ("\n"); - } - } - for (auto &id : conclusion) { - if (binary) - file->put ('u'); - else - file->put ("u "); - (void) find_and_delete (id); - for (const auto &external_lit : imported_clause) { - // flip sign... - const auto not_elit = -external_lit; - if (binary) - put_binary_lit (not_elit); - else - file->put (not_elit), file->put (' '); - } - if (binary) - put_binary_zero (); - else - file->put ("0\n"); - imported_clause.clear (); - } - flush_if_piping (); -} - -void IdrupTracer::idrup_report_status (int status) { - if (binary) - file->put ('s'); - else - file->put ("s "); - if (status == SATISFIABLE) - file->put ("SATISFIABLE"); - else if (status == UNSATISFIABLE) - file->put ("UNSATISFIABLE"); - else - file->put ("UNKNOWN"); - if (!binary) - file->put ("\n"); - flush_if_piping (); -} - -void IdrupTracer::idrup_conclude_sat (const vector &model) { - if (binary) - file->put ('m'); - else - file->put ("m "); - for (auto &lit : model) { - if (binary) - put_binary_lit (lit); - else - file->put (lit), file->put (' '); - } - if (binary) - put_binary_zero (); - else - file->put ("0\n"); - flush_if_piping (); -} - -void IdrupTracer::idrup_conclude_unknown (const vector &trail) { - if (binary) - file->put ('e'); - else - file->put ("e "); - for (auto &lit : trail) { - if (binary) - put_binary_lit (lit); - else - file->put (lit), file->put (' '); - } - if (binary) - put_binary_zero (); - else - file->put ("0\n"); - flush_if_piping (); -} - -void IdrupTracer::idrup_solve_query () { - if (binary) - file->put ('q'); - else - file->put ("q "); - for (auto &lit : assumptions) { - if (binary) - put_binary_lit (lit); - else - file->put (lit), file->put (' '); - } - if (binary) - put_binary_zero (); - else - file->put ("0\n"); - flush_if_piping (); -} - -/*------------------------------------------------------------------------*/ - -void IdrupTracer::add_derived_clause (int64_t, bool, - const vector &clause, - const vector &) { - if (file->closed ()) - return; - CADICAL_assert (imported_clause.empty ()); - LOG (clause, "IDRUP TRACER tracing addition of derived clause"); - idrup_add_derived_clause (clause); -#ifndef CADICAL_QUIET - added++; -#endif -} - -void IdrupTracer::add_assumption_clause (int64_t id, - const vector &clause, - const vector &) { - if (file->closed ()) - return; - CADICAL_assert (imported_clause.empty ()); - LOG (clause, "IDRUP TRACER tracing addition of assumption clause"); - for (auto &lit : clause) - imported_clause.push_back (lit); - last_id = id; - insert (); - imported_clause.clear (); -} - -void IdrupTracer::delete_clause (int64_t id, bool, - const vector &clause) { - if (file->closed ()) - return; - CADICAL_assert (imported_clause.empty ()); - LOG ("IDRUP TRACER tracing deletion of clause[%" PRId64 "]", id); - idrup_delete_clause (id, clause); -} - -void IdrupTracer::weaken_minus (int64_t id, const vector &) { - if (file->closed ()) - return; - CADICAL_assert (imported_clause.empty ()); - LOG ("IDRUP TRACER tracing weaken minus of clause[%" PRId64 "]", id); - last_id = id; - insert (); -#ifndef CADICAL_QUIET - weakened++; -#endif -} - -void IdrupTracer::conclude_unsat (ConclusionType, - const vector &conclusion) { - if (file->closed ()) - return; - CADICAL_assert (imported_clause.empty ()); - LOG (conclusion, "IDRUP TRACER tracing conclusion of clause(s)"); - idrup_conclude_and_delete (conclusion); -} - -void IdrupTracer::add_original_clause (int64_t id, bool, - const vector &clause, - bool restored) { - if (file->closed ()) - return; - if (!restored) { - LOG (clause, "IDRUP TRACER tracing addition of original clause"); -#ifndef CADICAL_QUIET - original++; -#endif - return idrup_add_original_clause (clause); - } - CADICAL_assert (restored); - if (find_and_delete (id)) { - LOG (clause, - "IDRUP TRACER the clause was not yet weakened, so no restore"); - return; - } - LOG (clause, "IDRUP TRACER tracing addition of restored clause"); - idrup_add_restored_clause (clause); -#ifndef CADICAL_QUIET - restore++; -#endif -} - -void IdrupTracer::report_status (int status, int64_t) { - if (file->closed ()) - return; - LOG ("IDRUP TRACER tracing report of status %d", status); - idrup_report_status (status); -} - -void IdrupTracer::conclude_sat (const vector &model) { - if (file->closed ()) - return; - LOG (model, "IDRUP TRACER tracing conclusion of model"); - idrup_conclude_sat (model); -} - -void IdrupTracer::conclude_unknown (const vector &trail) { - if (file->closed ()) - return; - LOG (trail, "IDRUP TRACER tracing conclusion of unknown state"); - idrup_conclude_unknown (trail); -} - -void IdrupTracer::solve_query () { - if (file->closed ()) - return; - LOG (assumptions, "IDRUP TRACER tracing solve query with assumptions"); - idrup_solve_query (); -#ifndef CADICAL_QUIET - solved++; -#endif -} - -void IdrupTracer::add_assumption (int lit) { - LOG ("IDRUP TRACER tracing addition of assumption %d", lit); - assumptions.push_back (lit); -} - -void IdrupTracer::reset_assumptions () { - LOG (assumptions, "IDRUP TRACER tracing reset of assumptions"); - assumptions.clear (); -} - -/*------------------------------------------------------------------------*/ - -bool IdrupTracer::closed () { return file->closed (); } - -#ifndef CADICAL_QUIET - -void IdrupTracer::print_statistics () { - // TODO complete this. - uint64_t bytes = file->bytes (); - uint64_t total = added + deleted + weakened + restore + original; - MSG ("LIDRUP %" PRId64 " original clauses %.2f%%", original, - percent (original, total)); - MSG ("LIDRUP %" PRId64 " learned clauses %.2f%%", added, - percent (added, total)); - MSG ("LIDRUP %" PRId64 " deleted clauses %.2f%%", deleted, - percent (deleted, total)); - MSG ("LIDRUP %" PRId64 " weakened clauses %.2f%%", weakened, - percent (weakened, total)); - MSG ("LIDRUP %" PRId64 " restored clauses %.2f%%", restore, - percent (restore, total)); - MSG ("LIDRUP %" PRId64 " queries %.2f", solved, relative (solved, total)); - MSG ("IDRUP %" PRId64 " bytes (%.2f MB)", bytes, - bytes / (double) (1 << 20)); -} - -#endif - -void IdrupTracer::close (bool print) { - CADICAL_assert (!closed ()); - file->close (); -#ifndef CADICAL_QUIET - if (print) { - MSG ("IDRUP proof file '%s' closed", file->name ()); - print_statistics (); - } -#else - (void) print; -#endif -} - -void IdrupTracer::flush (bool print) { - CADICAL_assert (!closed ()); - file->flush (); -#ifndef CADICAL_QUIET - if (print) { - MSG ("IDRUP proof file '%s' flushed", file->name ()); - print_statistics (); - } -#else - (void) print; -#endif -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_instantiate.cpp b/src/sat/cadical/cadical_instantiate.cpp deleted file mode 100644 index 2c34015b2..000000000 --- a/src/sat/cadical/cadical_instantiate.cpp +++ /dev/null @@ -1,371 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -/*------------------------------------------------------------------------*/ - -// This provides an implementation of variable instantiation, a technique -// for removing literals with few occurrence (see also 'instantiate.hpp'). - -/*------------------------------------------------------------------------*/ - -// Triggered at the end of a variable elimination round ('elim_round'). - -void Internal::collect_instantiation_candidates ( - Instantiator &instantiator) { - CADICAL_assert (occurring ()); - for (auto idx : vars) { - if (frozen (idx)) - continue; - if (!active (idx)) - continue; - if (flags (idx).elim) - continue; // BVE attempt pending - for (int sign = -1; sign <= 1; sign += 2) { - const int lit = sign * idx; - if (noccs (lit) > opts.instantiateocclim) - continue; - Occs &os = occs (lit); - for (const auto &c : os) { - if (c->garbage) - continue; - if (opts.instantiateonce && c->instantiated) - continue; - if (c->size < opts.instantiateclslim) - continue; - bool satisfied = false; - int unassigned = 0; - for (const auto &other : *c) { - const signed char tmp = val (other); - if (tmp > 0) - satisfied = true; - if (!tmp) - unassigned++; - } - if (satisfied) - continue; - if (unassigned < 3) - continue; // avoid learning units - size_t negoccs = occs (-lit).size (); - LOG (c, - "instantiation candidate literal %d " - "with %zu negative occurrences in", - lit, negoccs); - instantiator.candidate (lit, c, c->size, negoccs); - } - } - } -} - -/*------------------------------------------------------------------------*/ - -// Specialized propagation and assignment routines for instantiation. - -inline void Internal::inst_assign (int lit) { - LOG ("instantiate assign %d", lit); - CADICAL_assert (!val (lit)); - CADICAL_assert ((int) num_assigned < max_var); - num_assigned++; - set_val (lit, 1); - trail.push_back (lit); -} - -// Conflict analysis is only needed to do valid resolution proofs. -// We remember propagated clauses in order of assignment (in inst_chain) -// which allows us to do a variant of conflict analysis if the instantiation -// attempt succeeds. -// -bool Internal::inst_propagate () { // Adapted from 'propagate'. - START (propagate); - int64_t before = propagated; - bool ok = true; - while (ok && propagated != trail.size ()) { - const int lit = -trail[propagated++]; - LOG ("instantiate propagating %d", -lit); - Watches &ws = watches (lit); - const const_watch_iterator eow = ws.end (); - const_watch_iterator i = ws.begin (); - watch_iterator j = ws.begin (); - while (i != eow) { - const Watch w = *j++ = *i++; - const signed char b = val (w.blit); - if (b > 0) - continue; - if (w.binary ()) { - if (b < 0) { - ok = false; - LOG (w.clause, "conflict"); - if (lrat) { - inst_chain.push_back (w.clause); - } - break; - } else { - if (lrat) { - inst_chain.push_back (w.clause); - } - inst_assign (w.blit); - } - } else { - literal_iterator lits = w.clause->begin (); - const int other = lits[0] ^ lits[1] ^ lit; - lits[0] = other, lits[1] = lit; - const signed char u = val (other); - if (u > 0) - j[-1].blit = other; - else { - const int size = w.clause->size; - const const_literal_iterator end = lits + size; - const literal_iterator middle = lits + w.clause->pos; - literal_iterator k = middle; - signed char v = -1; - int r = 0; - while (k != end && (v = val (r = *k)) < 0) - k++; - if (v < 0) { - k = lits + 2; - CADICAL_assert (w.clause->pos <= size); - while (k != middle && (v = val (r = *k)) < 0) - k++; - } - w.clause->pos = k - lits; - CADICAL_assert (lits + 2 <= k), CADICAL_assert (k <= w.clause->end ()); - if (v > 0) { - j[-1].blit = r; - } else if (!v) { - LOG (w.clause, "unwatch %d in", r); - lits[1] = r; - *k = lit; - watch_literal (r, lit, w.clause); - j--; - } else if (!u) { - CADICAL_assert (v < 0); - if (lrat) { - inst_chain.push_back (w.clause); - } - inst_assign (other); - } else { - CADICAL_assert (u < 0); - CADICAL_assert (v < 0); - if (lrat) { - inst_chain.push_back (w.clause); - } - LOG (w.clause, "conflict"); - ok = false; - break; - } - } - } - } - if (j != i) { - while (i != eow) - *j++ = *i++; - ws.resize (j - ws.begin ()); - } - } - int64_t delta = propagated - before; - stats.propagations.instantiate += delta; - STOP (propagate); - return ok; -} - -/*------------------------------------------------------------------------*/ - -// This is the instantiation attempt. - -bool Internal::instantiate_candidate (int lit, Clause *c) { - stats.instried++; - if (c->garbage) - return false; - CADICAL_assert (!level); - bool found = false, satisfied = false, inactive = false; - int unassigned = 0; - for (const auto &other : *c) { - if (other == lit) - found = true; - const signed char tmp = val (other); - if (tmp > 0) { - satisfied = true; - break; - } - if (!tmp && !active (other)) { - inactive = true; - break; - } - if (!tmp) - unassigned++; - } - if (!found) - return false; - if (inactive) - return false; - if (satisfied) - return false; - if (unassigned < 3) - return false; - size_t before = trail.size (); - CADICAL_assert (propagated == before); - CADICAL_assert (active (lit)); - CADICAL_assert (inst_chain.empty ()); - LOG (c, "trying to instantiate %d in", lit); - CADICAL_assert (!c->garbage); - c->instantiated = true; - CADICAL_assert (lrat_chain.empty ()); - level++; - inst_assign (lit); // Assume 'lit' to true. - for (const auto &other : *c) { - if (other == lit) - continue; - const signed char tmp = val (other); - if (tmp) { - CADICAL_assert (tmp < 0); - continue; - } - inst_assign (-other); // Assume other to false. - } - bool ok = inst_propagate (); // Propagate. - CADICAL_assert (lrat_chain.empty ()); // chain will be built here - if (ok) { - inst_chain.clear (); - } else if (lrat) { // analyze conflict for lrat - CADICAL_assert (inst_chain.size ()); - Clause *reason = inst_chain.back (); - inst_chain.pop_back (); - lrat_chain.push_back (reason->id); - for (const auto &other : *reason) { - Flags &f = flags (other); - CADICAL_assert (!f.seen); - f.seen = true; - analyzed.push_back (other); - } - } - while (trail.size () > before) { // Backtrack. - const int other = trail.back (); - LOG ("instantiate unassign %d", other); - trail.pop_back (); - CADICAL_assert (val (other) > 0); - num_assigned--; - set_val (other, 0); - // this is a variant of conflict analysis which is only needed for lrat - if (!ok && inst_chain.size () && lrat) { - Flags &f = flags (other); - if (f.seen) { - Clause *reason = inst_chain.back (); - lrat_chain.push_back (reason->id); - for (const auto &other : *reason) { - Flags &f = flags (other); - if (f.seen) - continue; - f.seen = true; - analyzed.push_back (other); - } - f.seen = false; - } - inst_chain.pop_back (); - } - } - CADICAL_assert (inst_chain.empty ()); - // post processing step for lrat - if (!ok && lrat) { - if (flags (lit).seen) - lrat_chain.push_back (c->id); - for (const auto &other : *c) { - Flags &f = flags (other); - f.seen = false; - } - for (int other : analyzed) { - Flags &f = flags (other); - if (!f.seen) { - f.seen = true; - continue; - } - int64_t id = unit_id (-other); - lrat_chain.push_back (id); - } - clear_analyzed_literals (); - reverse (lrat_chain.begin (), lrat_chain.end ()); - } - CADICAL_assert (analyzed.empty ()); - propagated = before; - CADICAL_assert (level == 1); - level = 0; - if (ok) { - CADICAL_assert (lrat_chain.empty ()); - LOG ("instantiation failed"); - return false; - } - unwatch_clause (c); - LOG (lrat_chain, "instantiate proof chain"); - strengthen_clause (c, lit); - watch_clause (c); - lrat_chain.clear (); - CADICAL_assert (c->size > 1); - LOG ("instantiation succeeded"); - stats.instantiated++; - return true; -} - -/*------------------------------------------------------------------------*/ - -// Try to instantiate all candidates collected before through the -// 'collect_instantiation_candidates' routine. - -void Internal::instantiate (Instantiator &instantiator) { - CADICAL_assert (opts.instantiate); - START (instantiate); - stats.instrounds++; -#ifndef CADICAL_QUIET - const int64_t candidates = instantiator.candidates.size (); - int64_t tried = 0; -#endif - int64_t instantiated = 0; - init_watches (); - connect_watches (); - if (propagated < trail.size ()) { - if (!propagate ()) { - LOG ("propagation after connecting watches failed"); - learn_empty_clause (); - CADICAL_assert (unsat); - } - } - PHASE ("instantiate", stats.instrounds, - "attempting to instantiate %" PRId64 - " candidate literal clause pairs", - candidates); - while (!unsat && !terminated_asynchronously () && - !instantiator.candidates.empty ()) { - Instantiator::Candidate cand = instantiator.candidates.back (); - instantiator.candidates.pop_back (); -#ifndef CADICAL_QUIET - tried++; -#endif - if (!active (cand.lit)) - continue; - LOG (cand.clause, - "trying to instantiate %d with " - "%zd negative occurrences in", - cand.lit, cand.negoccs); - if (!instantiate_candidate (cand.lit, cand.clause)) - continue; - instantiated++; - VERBOSE (2, - "instantiation %" PRId64 " (%.1f%%) succeeded " - "(%.1f%%) with %zd negative occurrences in size %d clause", - tried, percent (tried, candidates), - percent (instantiated, tried), cand.negoccs, cand.size); - } - PHASE ("instantiate", stats.instrounds, - "instantiated %" PRId64 " candidate successfully " - "out of %" PRId64 " tried %.1f%%", - instantiated, tried, percent (instantiated, tried)); - report ('I', !instantiated); - reset_watches (); - STOP (instantiate); -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_internal.cpp b/src/sat/cadical/cadical_internal.cpp deleted file mode 100644 index abe18c59c..000000000 --- a/src/sat/cadical/cadical_internal.cpp +++ /dev/null @@ -1,1196 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -/*------------------------------------------------------------------------*/ -static Clause external_reason_clause; - -Internal::Internal () - : mode (SEARCH), unsat (false), iterating (false), - localsearching (false), lookingahead (false), preprocessing (false), - protected_reasons (false), force_saved_phase (false), - searching_lucky_phases (false), stable (false), reported (false), - external_prop (false), did_external_prop (false), - external_prop_is_lazy (true), forced_backt_allowed (false), - - private_steps (false), rephased (0), vsize (0), max_var (0), - clause_id (0), original_id (0), reserved_ids (0), conflict_id (0), - saved_decisions (0), concluded (false), lrat (false), frat (false), - level (0), vals (0), score_inc (1.0), scores (this), conflict (0), - ignore (0), external_reason (&external_reason_clause), - newest_clause (0), force_no_backtrack (false), - from_propagator (false), ext_clause_forgettable (false), - tainted_literal (0), notified (0), probe_reason (0), propagated (0), - propagated2 (0), propergated (0), best_assigned (0), - target_assigned (0), no_conflict_until (0), unsat_constraint (false), - marked_failed (true), sweep_incomplete (false), citten (0), - num_assigned (0), proof (0), opts (this), -#ifndef CADICAL_QUIET - profiles (this), force_phase_messages (false), -#endif - arena (this), prefix ("c "), internal (this), external (0), - termination_forced (false), vars (this->max_var), - lits (this->max_var) { - control.push_back (Level (0, 0)); - - // The 'dummy_binary' is used in 'try_to_subsume_clause' to fake a real - // clause, which then can be used to subsume or strengthen the given - // clause in one routine for both binary and non binary clauses. This - // fake binary clause is always kept non-redundant (and not-moved etc.) - // due to the following 'memset'. Only literals will be changed. - - // In a previous version we used local automatic allocated 'Clause' on the - // stack, which became incompatible with several compilers (see the - // discussion on flexible array member in 'Clause.cpp'). - - size_t bytes = Clause::bytes (2); - dummy_binary = (Clause *) new char[bytes]; - memset (dummy_binary, 0, bytes); - dummy_binary->size = 2; -} - -Internal::~Internal () { - // If a memory exception ocurred a profile might still be active. -#ifndef CADICAL_QUIET -#define PROFILE(NAME, LEVEL) \ - if (PROFILE_ACTIVE (NAME)) \ - STOP (NAME); - PROFILES -#undef PROFILE -#endif - delete[] (char *) dummy_binary; - for (const auto &c : clauses) - delete_clause (c); - if (proof) - delete proof; - for (auto &tracer : tracers) - delete tracer; - for (auto &filetracer : file_tracers) - delete filetracer; - for (auto &stattracer : stat_tracers) - delete stattracer; - if (vals) { - vals -= vsize; - delete[] vals; - } -} - -/*------------------------------------------------------------------------*/ - -// Values in 'vals' can be accessed in the range '[-max_var,max_var]' that -// is directly by a literal. This is crucial for performance. By shifting -// the start of 'vals' appropriately, we achieve that negative offsets from -// the start of 'vals' can be used. We also need to set both values at -// 'lit' and '-lit' during assignments. In MiniSAT integer literals are -// encoded, using the least significant bit as negation. This avoids taking -// the 'abs ()' (as in our solution) and thus also avoids a branch in the -// hot-spot of the solver (clause traversal in propagation). That solution -// requires another (branch less) negation of the values though and -// debugging is harder since literals occur only encoded in clauses. -// The main draw-back of our solution is that we have to shift the memory -// and access it through negative indices, which looks less clean (but still -// as far I can tell is properly defined C / C++). You might get a warning -// by static analyzers though. Clang with '--analyze' thought that this -// idiom would generate a memory leak thus we use the following dummy. - -static signed char *ignore_clang_analyze_memory_leak_warning; - -void Internal::enlarge_vals (size_t new_vsize) { - signed char *new_vals; - const size_t bytes = 2u * new_vsize; - new_vals = new signed char[bytes]; // g++-4.8 does not like ... { 0 }; - memset (new_vals, 0, bytes); - ignore_clang_analyze_memory_leak_warning = new_vals; - new_vals += new_vsize; - - if (vals) { - memcpy (new_vals - max_var, vals - max_var, 2u * max_var + 1u); - vals -= vsize; - delete[] vals; - } else - CADICAL_assert (!vsize); - vals = new_vals; -} - -/*------------------------------------------------------------------------*/ - -void Internal::enlarge (int new_max_var) { - // New variables can be created that can invoke enlarge anytime (via calls - // during ipasir-up call-backs), thus assuming (!level) is not correct - size_t new_vsize = vsize ? 2 * vsize : 1 + (size_t) new_max_var; - while (new_vsize <= (size_t) new_max_var) - new_vsize *= 2; - LOG ("enlarge internal size from %zd to new size %zd", vsize, new_vsize); - // Ordered in the size of allocated memory (larger block first). - if (lrat || frat) - enlarge_zero (unit_clauses_idx, 2 * new_vsize); - enlarge_only (wtab, 2 * new_vsize); - enlarge_only (vtab, new_vsize); - enlarge_zero (parents, new_vsize); - enlarge_only (links, new_vsize); - enlarge_zero (btab, new_vsize); - enlarge_zero (gtab, new_vsize); - enlarge_zero (stab, new_vsize); - enlarge_init (ptab, 2 * new_vsize, -1); - enlarge_only (ftab, new_vsize); - enlarge_vals (new_vsize); - vsize = new_vsize; - if (external) - enlarge_zero (relevanttab, new_vsize); - const signed char val = opts.phase ? 1 : -1; - enlarge_init (phases.saved, new_vsize, val); - enlarge_zero (phases.forced, new_vsize); - enlarge_zero (phases.target, new_vsize); - enlarge_zero (phases.best, new_vsize); - enlarge_zero (phases.prev, new_vsize); - enlarge_zero (phases.min, new_vsize); - enlarge_zero (marks, new_vsize); -} - -void Internal::init_vars (int new_max_var) { - if (new_max_var <= max_var) - return; - // New variables can be created that can invoke enlarge anytime (via calls - // during ipasir-up call-backs), thus assuming (!level) is not correct - LOG ("initializing %d internal variables from %d to %d", - new_max_var - max_var, max_var + 1, new_max_var); - if ((size_t) new_max_var >= vsize) - enlarge (new_max_var); -#ifndef CADICAL_NDEBUG - for (int64_t i = -new_max_var; i < -max_var; i++) - CADICAL_assert (!vals[i]); - for (unsigned i = max_var + 1; i <= (unsigned) new_max_var; i++) - CADICAL_assert (!vals[i]), CADICAL_assert (!btab[i]), CADICAL_assert (!gtab[i]); - for (uint64_t i = 2 * ((uint64_t) max_var + 1); - i <= 2 * (uint64_t) new_max_var + 1; i++) - CADICAL_assert (ptab[i] == -1); -#endif - CADICAL_assert (!btab[0]); - int old_max_var = max_var; - max_var = new_max_var; - init_queue (old_max_var, new_max_var); - init_scores (old_max_var, new_max_var); - int initialized = new_max_var - old_max_var; - stats.vars += initialized; - stats.unused += initialized; - stats.inactive += initialized; - LOG ("finished initializing %d internal variables", initialized); -} - -void Internal::add_original_lit (int lit) { - CADICAL_assert (abs (lit) <= max_var); - if (lit) { - original.push_back (lit); - } else { - const int64_t id = - original_id < reserved_ids ? ++original_id : ++clause_id; - if (proof) { - // Use the external form of the clause for printing in proof - // Externalize(internalized literal) != external literal - CADICAL_assert (!original.size () || !external->eclause.empty ()); - proof->add_external_original_clause (id, false, external->eclause); - } - if (internal->opts.check && - (internal->opts.checkwitness || internal->opts.checkfailed)) { - bool forgettable = from_propagator && ext_clause_forgettable; - if (forgettable && opts.check) { - CADICAL_assert (!original.size () || !external->eclause.empty ()); - - // First integer is the presence-flag (even if the clause is empty) - external->forgettable_original[id] = {1}; - - for (auto const &elit : external->eclause) - external->forgettable_original[id].push_back (elit); - - LOG (external->eclause, - "clause added to external forgettable map:"); - } - } - - add_new_original_clause (id); - original.clear (); - } -} - -void Internal::finish_added_clause_with_id (int64_t id, bool restore) { - if (proof) { - // Use the external form of the clause for printing in proof - // Externalize(internalized literal) != external literal - CADICAL_assert (!original.size () || !external->eclause.empty ()); - proof->add_external_original_clause (id, false, external->eclause, - restore); - } - add_new_original_clause (id); - original.clear (); -} - -/*------------------------------------------------------------------------*/ - -void Internal::reserve_ids (int number) { - // return; - LOG ("reserving %d ids", number); - CADICAL_assert (number >= 0); - CADICAL_assert (!clause_id && !reserved_ids && !original_id); - clause_id = reserved_ids = number; - if (proof) - proof->begin_proof (reserved_ids); -} - -/*------------------------------------------------------------------------*/ - -#ifdef PROFILE_MODE - -// Separating these makes it easier to profile stable and unstable search. - -bool Internal::propagate_wrapper () { - if (stable) - return propagate_stable (); - else - return propagate_unstable (); -} - -void Internal::analyze_wrapper () { - if (stable) - analyze_stable (); - else - analyze_unstable (); -} - -int Internal::decide_wrapper () { - if (stable) - return decide_stable (); - else - return decide_unstable (); -} - -#endif - -/*------------------------------------------------------------------------*/ - -// This is the main CDCL loop with interleaved inprocessing. - -int Internal::cdcl_loop_with_inprocessing () { - - int res = 0; - - START (search); - - if (stable) { - START (stable); - report ('['); - } else { - START (unstable); - report ('{'); - } - - while (!res) { - if (unsat) - res = 20; - else if (unsat_constraint) - res = 20; - else if (!propagate_wrapper ()) - analyze_wrapper (); // propagate and analyze - else if (iterating) - iterate (); // report learned unit - else if (!external_propagate () || unsat) { // external propagation - if (unsat) - continue; - else - analyze (); - } else if (satisfied ()) { // found model - if (!external_check_solution () || unsat) { - if (unsat) - continue; - else - analyze (); - } else if (satisfied ()) - res = 10; - } else if (search_limits_hit ()) - break; // decision or conflict limit - else if (terminated_asynchronously ()) // externally terminated - break; - else if (restarting ()) - restart (); // restart by backtracking - else if (rephasing ()) - rephase (); // reset variable phases - else if (reducing ()) - reduce (); // collect useless clauses - else if (inprobing ()) - inprobe (); // schedule of inprocessing - else if (ineliminating ()) - elim (); // variable elimination - else if (compacting ()) - compact (); // collect variables - else if (conditioning ()) - condition (); // globally blocked clauses - else - res = decide (); // next decision - } - - if (stable) { - STOP (stable); - report (']'); - } else { - STOP (unstable); - report ('}'); - } - - STOP (search); - - return res; -} - -int Internal::propagate_assumptions () { - if (proof) - proof->solve_query (); - if (opts.ilb) { - if (opts.ilbassumptions) - sort_and_reuse_assumptions (); - stats.ilbtriggers++; - stats.ilbsuccess += (level > 0); - stats.levelsreused += level; - if (level) { - CADICAL_assert (control.size () > 1); - stats.literalsreused += num_assigned - control[1].trail; - } - } - init_search_limits (); - init_report_limits (); - - int res = already_solved (); // root-level propagation is done here - - int last_assumption_level = assumptions.size (); - if (constraint.size ()) - last_assumption_level++; - - if (!res) { - restore_clauses (); - while (!res) { - if (unsat) - res = 20; - else if (unsat_constraint) - res = 20; - else if (!propagate ()) { - // let analyze run to get failed assumptions - analyze (); - } else if (!external_propagate () || unsat) { // external propagation - if (unsat) - continue; - else - analyze (); - } else if (satisfied ()) { // found model - if (!external_check_solution () || unsat) { - if (unsat) - continue; - else - analyze (); - } else if (satisfied ()) - res = 10; - } else if (search_limits_hit ()) - break; // decision or conflict limit - else if (terminated_asynchronously ()) // externally terminated - break; - else { - if (level >= last_assumption_level) - break; - res = decide (); - } - } - } - - if (unsat || unsat_constraint) - res = 20; - - if (!res && satisfied ()) - res = 10; - - finalize (res); - reset_solving (); - report_solving (res); - - return res; -} - -void Internal::implied (std::vector &entrailed) { - int last_assumption_level = assumptions.size (); - if (constraint.size ()) - last_assumption_level++; - - size_t trail_limit = trail.size(); - if (level > last_assumption_level) - trail_limit = control[last_assumption_level + 1].trail; - - for (size_t i = 0; i < trail_limit; i++) - entrailed.push_back (trail[i]); -} - -/*------------------------------------------------------------------------*/ - -// Most of the limits are only initialized in the first 'solve' call and -// increased as in a stand-alone non-incremental SAT call except for those -// explicitly marked as being reset below. - -void Internal::init_report_limits () { - reported = false; - lim.report = 0; - lim.recompute_tier = 5000; -} - -void Internal::init_preprocessing_limits () { - - const bool incremental = lim.initialized; - if (incremental) - LOG ("reinitializing preprocessing limits incrementally"); - else - LOG ("initializing preprocessing limits and increments"); - - const char *mode = 0; - - /*----------------------------------------------------------------------*/ - - if (incremental) - mode = "keeping"; - else { - last.elim.marked = -1; - lim.elim = stats.conflicts + scale (opts.elimint); - mode = "initial"; - } - (void) mode; - LOG ("%s elim limit %" PRId64 " after %" PRId64 " conflicts", mode, - lim.elim, lim.elim - stats.conflicts); - - // Initialize and reset elimination bounds in any case. - - lim.elimbound = opts.elimboundmin; - LOG ("elimination bound %" PRId64 "", lim.elimbound); - - /*----------------------------------------------------------------------*/ - - if (!incremental) { - - last.ternary.marked = -1; // TODO this should not be necessary... - - lim.compact = stats.conflicts + opts.compactint; - LOG ("initial compact limit %" PRId64 " increment %" PRId64 "", - lim.compact, lim.compact - stats.conflicts); - } - - /*----------------------------------------------------------------------*/ - - if (incremental) - mode = "keeping"; - else { - double delta = log10 (stats.added.irredundant); - delta = delta * delta; - lim.inprobe = stats.conflicts + opts.inprobeint * delta; - mode = "initial"; - } - (void) mode; - LOG ("%s probe limit %" PRId64 " after %" PRId64 " conflicts", mode, - lim.inprobe, lim.inprobe - stats.conflicts); - - /*----------------------------------------------------------------------*/ - - if (incremental) - mode = "keeping"; - else { - lim.condition = stats.conflicts + opts.conditionint; - mode = "initial"; - } - LOG ("%s condition limit %" PRId64 " increment %" PRId64, mode, - lim.condition, lim.condition - stats.conflicts); - - /*----------------------------------------------------------------------*/ - - // Initial preprocessing rounds. - - if (inc.preprocessing <= 0) { - lim.preprocessing = 0; - LOG ("no preprocessing"); - } else { - lim.preprocessing = inc.preprocessing; - LOG ("limiting to %" PRId64 " preprocessing rounds", lim.preprocessing); - } -} - -void Internal::init_search_limits () { - - const bool incremental = lim.initialized; - if (incremental) - LOG ("reinitializing search limits incrementally"); - else - LOG ("initializing search limits and increments"); - - const char *mode = 0; - - /*----------------------------------------------------------------------*/ - - if (incremental) - mode = "keeping"; - else { - last.reduce.conflicts = -1; - lim.reduce = stats.conflicts + opts.reduceinit; - mode = "initial"; - } - (void) mode; - LOG ("%s reduce limit %" PRId64 " after %" PRId64 " conflicts", mode, - lim.reduce, lim.reduce - stats.conflicts); - - /*----------------------------------------------------------------------*/ - - if (incremental) - mode = "keeping"; - else { - lim.flush = opts.flushint; - inc.flush = opts.flushint; - mode = "initial"; - } - (void) mode; - LOG ("%s flush limit %" PRId64 " interval %" PRId64 "", mode, lim.flush, - inc.flush); - - /*----------------------------------------------------------------------*/ - - // Initialize or reset 'rephase' limits in any case. - - lim.rephase = stats.conflicts + opts.rephaseint; - lim.rephased[0] = lim.rephased[1] = 0; - LOG ("new rephase limit %" PRId64 " after %" PRId64 " conflicts", - lim.rephase, lim.rephase - stats.conflicts); - - /*----------------------------------------------------------------------*/ - - // Initialize or reset 'restart' limits in any case. - - lim.restart = stats.conflicts + opts.restartint; - LOG ("new restart limit %" PRId64 " increment %" PRId64 "", lim.restart, - lim.restart - stats.conflicts); - - /*----------------------------------------------------------------------*/ - - if (!incremental) { - stable = opts.stabilize && opts.stabilizeonly; - if (stable) - LOG ("starting in always forced stable phase"); - else - LOG ("starting in default non-stable phase"); - init_averages (); - } else if (opts.stabilize && opts.stabilizeonly) { - LOG ("keeping always forced stable phase"); - CADICAL_assert (stable); - } else if (stable) { - LOG ("switching back to default non-stable phase"); - stable = false; - swap_averages (); - } else - LOG ("keeping non-stable phase"); - - if (!incremental) { - inc.stabilize = 0; - lim.stabilize = stats.conflicts + opts.stabilizeinit; - LOG ("initial stabilize limit %" PRId64 " after %d conflicts", - lim.stabilize, (int) opts.stabilizeinit); - } - - if (opts.stabilize && opts.reluctant) { - LOG ("new restart reluctant doubling sequence period %d", - opts.reluctant); - reluctant.enable (opts.reluctant, opts.reluctantmax); - } else - reluctant.disable (); - - /*----------------------------------------------------------------------*/ - - // Conflict and decision limits. - - if (inc.conflicts < 0) { - lim.conflicts = -1; - LOG ("no limit on conflicts"); - } else { - lim.conflicts = stats.conflicts + inc.conflicts; - LOG ("conflict limit after %" PRId64 " conflicts at %" PRId64 - " conflicts", - inc.conflicts, lim.conflicts); - } - - if (inc.decisions < 0) { - lim.decisions = -1; - LOG ("no limit on decisions"); - } else { - lim.decisions = stats.decisions + inc.decisions; - LOG ("conflict limit after %" PRId64 " decisions at %" PRId64 - " decisions", - inc.decisions, lim.decisions); - } - - /*----------------------------------------------------------------------*/ - - // Initial preprocessing rounds. - - if (inc.localsearch <= 0) { - lim.localsearch = 0; - LOG ("no local search"); - } else { - lim.localsearch = inc.localsearch; - LOG ("limiting to %" PRId64 " local search rounds", lim.localsearch); - } - - /*----------------------------------------------------------------------*/ - - lim.initialized = true; -} - -/*------------------------------------------------------------------------*/ - -bool Internal::preprocess_round (int round) { - (void) round; - if (unsat) - return false; - if (!max_var) - return false; - START (preprocess); - struct { - int64_t vars, clauses; - } before, after; - before.vars = active (); - before.clauses = stats.current.irredundant; - stats.preprocessings++; - CADICAL_assert (!preprocessing); - preprocessing = true; - PHASE ("preprocessing", stats.preprocessings, - "starting round %d with %" PRId64 " variables and %" PRId64 - " clauses", - round, before.vars, before.clauses); - int old_elimbound = lim.elimbound; - if (opts.inprobing) - inprobe (false); - if (opts.elim) - elim (false); - if (opts.condition) - condition (false); - - after.vars = active (); - after.clauses = stats.current.irredundant; - CADICAL_assert (preprocessing); - preprocessing = false; - PHASE ("preprocessing", stats.preprocessings, - "finished round %d with %" PRId64 " variables and %" PRId64 - " clauses", - round, after.vars, after.clauses); - STOP (preprocess); - report ('P'); - if (unsat) - return false; - if (after.vars < before.vars) - return true; - if (old_elimbound < lim.elimbound) - return true; - return false; -} - -// for now counts as one of the preprocessing rounds TODO: change this? -void Internal::preprocess_quickly () { - if (unsat) - return; - if (!max_var) - return; - if (!opts.preprocesslight) - return; - START (preprocess); - struct { - int64_t vars, clauses; - } before, after; - before.vars = active (); - before.clauses = stats.current.irredundant; - // stats.preprocessings++; - CADICAL_assert (!preprocessing); - preprocessing = true; - PHASE ("preprocessing", stats.preprocessings, - "starting with %" PRId64 " variables and %" PRId64 " clauses", - before.vars, before.clauses); - - if (extract_gates ()) - decompose (); - - if (sweep ()) - decompose (); - - if (opts.factor) - factor (); - - if (opts.fastelim) - elimfast (); - // if (opts.condition) - // condition (false); - after.vars = active (); - after.clauses = stats.current.irredundant; - CADICAL_assert (preprocessing); - preprocessing = false; - PHASE ("preprocessing", stats.preprocessings, - "finished with %" PRId64 " variables and %" PRId64 " clauses", - after.vars, after.clauses); - STOP (preprocess); - report ('P'); -} - -int Internal::preprocess () { - preprocess_quickly (); - for (int i = 0; i < lim.preprocessing; i++) - if (!preprocess_round (i)) - break; - if (unsat) - return 20; - return 0; -} - -/*------------------------------------------------------------------------*/ - -int Internal::try_to_satisfy_formula_by_saved_phases () { - LOG ("satisfying formula by saved phases"); - CADICAL_assert (!level); - CADICAL_assert (!force_saved_phase); - CADICAL_assert (propagated == trail.size ()); - force_saved_phase = true; - if (external_prop) { - CADICAL_assert (!level); - LOG ("external notifications are turned off during preprocessing."); - private_steps = true; - } - int res = 0; - while (!res) { - if (satisfied ()) { - LOG ("formula indeed satisfied by saved phases"); - res = 10; - } else if (decide ()) { - LOG ("inconsistent assumptions with redundant clauses and phases"); - res = 20; - } else if (!propagate ()) { - LOG ("saved phases do not satisfy redundant clauses"); - CADICAL_assert (level > 0); - backtrack (); - conflict = 0; // ignore conflict - CADICAL_assert (!res); - break; - } - } - CADICAL_assert (force_saved_phase); - force_saved_phase = false; - if (external_prop) { - private_steps = false; - LOG ("external notifications are turned back on."); - if (!level) - notify_assignments (); // In case fixed assignments were found. - else { - renotify_trail_after_local_search (); - } - } - return res; -} - -/*------------------------------------------------------------------------*/ - -void Internal::produce_failed_assumptions () { - LOG ("producing failed assumptions"); - CADICAL_assert (!level); - CADICAL_assert (!assumptions.empty ()); - while (!unsat) { - CADICAL_assert (!satisfied ()); - notify_assignments (); - if (decide ()) - break; - while (!unsat && !propagate ()) - analyze (); - } - notify_assignments (); - if (unsat) - LOG ("formula is actually unsatisfiable unconditionally"); - else - LOG ("assumptions indeed failing"); -} - -/*------------------------------------------------------------------------*/ - -int Internal::local_search_round (int round) { - - CADICAL_assert (round > 0); - - if (unsat) - return false; - if (!max_var) - return false; - - START_OUTER_WALK (); - CADICAL_assert (!localsearching); - localsearching = true; - - // Determine propagation limit quadratically scaled with rounds. - // - int64_t limit = opts.walkmineff; - limit *= round; - if (LONG_MAX / round > limit) - limit *= round; - else - limit = LONG_MAX; - - int res = walk_round (limit, true); - - CADICAL_assert (localsearching); - localsearching = false; - STOP_OUTER_WALK (); - - report ('L'); - - return res; -} - -int Internal::local_search () { - - if (unsat) - return 0; - if (!max_var) - return 0; - if (!opts.walk) - return 0; - if (constraint.size ()) - return 0; - - int res = 0; - - for (int i = 1; !res && i <= lim.localsearch; i++) - res = local_search_round (i); - - if (res == 10) { - LOG ("local search determined formula to be satisfiable"); - CADICAL_assert (!stats.walk.minimum); - res = try_to_satisfy_formula_by_saved_phases (); - } else if (res == 20) { - LOG ("local search determined assumptions to be inconsistent"); - CADICAL_assert (!assumptions.empty ()); - produce_failed_assumptions (); - } - - return res; -} - -/*------------------------------------------------------------------------*/ - -// if preprocess_only is false and opts.ilb is true we do not preprocess -// such that we do not have to backtrack to level 0. -// -int Internal::solve (bool preprocess_only) { - CADICAL_assert (clause.empty ()); - START (solve); - if (proof) - proof->solve_query (); - if (opts.ilb) { - if (opts.ilbassumptions) - sort_and_reuse_assumptions (); - stats.ilbtriggers++; - stats.ilbsuccess += (level > 0); - stats.levelsreused += level; - if (level) { - CADICAL_assert (control.size () > 1); - stats.literalsreused += num_assigned - control[1].trail; - } - if (external->propagator) - renotify_trail_after_ilb (); - } - if (preprocess_only) - LOG ("internal solving in preprocessing only mode"); - else - LOG ("internal solving in full mode"); - init_report_limits (); - int res = already_solved (); - if (!res && preprocess_only && level) - backtrack (); - if (!res) - res = restore_clauses (); - if (!res || (res == 10 && external_prop)) { - init_preprocessing_limits (); - if (!preprocess_only) - init_search_limits (); - } - if (!preprocess_only) { - if (!res && !level) - res = local_search (); - } - if (!res && !level) - res = preprocess (); - if (!preprocess_only) { - if (!res && !level) - res = local_search (); - if (!res && !level) - res = lucky_phases (); - if (!res || (res == 10 && external_prop)) { - if (res == 10 && external_prop && level) - backtrack (); - res = cdcl_loop_with_inprocessing (); - } - } - finalize (res); - reset_solving (); - report_solving (res); - STOP (solve); - return res; -} - -int Internal::already_solved () { - int res = 0; - if (unsat || unsat_constraint) { - LOG ("already inconsistent"); - res = 20; - } else { - if (level && !opts.ilb) - backtrack (); - if (!level && !propagate ()) { - LOG ("root level propagation produces conflict"); - learn_empty_clause (); - res = 20; - } - if (max_var == 0 && res == 0) - res = 10; - } - return res; -} -void Internal::report_solving (int res) { - if (res == 10) - report ('1'); - else if (res == 20) - report ('0'); - else - report ('?'); -} - -void Internal::reset_solving () { - if (termination_forced) { - - // TODO this leads potentially to a data race if the external - // user is calling 'terminate' twice within one 'solve' call. - // A proper solution would be to guard / protect setting the - // 'termination_forced' flag and only allow it during solving and - // ignore it otherwise thus also the second time it is called during a - // 'solve' call. We could move resetting it also the start of - // 'solve'. - // - termination_forced = false; - - LOG ("reset forced termination"); - } -} - -int Internal::restore_clauses () { - int res = 0; - if (opts.restoreall <= 1 && external->tainted.empty ()) { - LOG ("no tainted literals and nothing to restore"); - report ('*'); - } else { - report ('+'); - // remove_garbage_binaries (); - external->restore_clauses (); - internal->report ('r'); - if (!unsat && !level && !propagate ()) { - LOG ("root level propagation after restore produces conflict"); - learn_empty_clause (); - res = 20; - } - } - return res; -} - -int Internal::lookahead () { - CADICAL_assert (clause.empty ()); - START (lookahead); - CADICAL_assert (!lookingahead); - lookingahead = true; - if (external_prop) { - if (level) { - // Combining lookahead with external propagator is limited - // Note that lookahead_probing (); would also force backtrack anyway - backtrack (); - } - LOG ("external notifications are turned off during preprocessing."); - private_steps = true; - } - int tmp = already_solved (); - if (!tmp) - tmp = restore_clauses (); - int res = 0; - if (!tmp) - res = lookahead_probing (); - if (res == INT_MIN) - res = 0; - reset_solving (); - report_solving (tmp); - CADICAL_assert (lookingahead); - lookingahead = false; - STOP (lookahead); - if (external_prop) { - private_steps = false; - LOG ("external notifications are turned back on."); - notify_assignments (); // In case fixed assignments were found. - } - return res; -} - -/*------------------------------------------------------------------------*/ - -void Internal::finalize (int res) { - if (!proof) - return; - LOG ("finalizing"); - // finalize external units - if (frat) { - for (const auto &evar : external->vars) { - CADICAL_assert (evar > 0); - const auto eidx = 2 * evar; - int sign = 1; - int64_t id = external->ext_units[eidx]; - if (!id) { - sign = -1; - id = external->ext_units[eidx + 1]; - } - if (id) { - proof->finalize_external_unit (id, evar * sign); - } - } - // finalize internal units - for (const auto &lit : lits) { - const auto elit = externalize (lit); - if (elit) { - const unsigned eidx = (elit < 0) + 2u * (unsigned) abs (elit); - const int64_t id = external->ext_units[eidx]; - if (id) { - CADICAL_assert (unit_clauses (vlit (lit)) == id); - continue; - } - } - const int64_t id = unit_clauses (vlit (lit)); - if (!id) - continue; - proof->finalize_unit (id, lit); - } - // See the discussion in 'propagate' on why garbage binary clauses stick - // around. - for (const auto &c : clauses) - if (!c->garbage || (c->size == 2 && !c->flushed)) - proof->finalize_clause (c); - - // finalize conflict and proof - if (conflict_id) { - proof->finalize_clause (conflict_id, {}); - } - } - proof->report_status (res, conflict_id); - if (res == 10) - external->conclude_sat (); - else if (res == 20) - conclude_unsat (); - else if (!res) - external->conclude_unknown (); -} - -/*------------------------------------------------------------------------*/ - -void Internal::print_statistics () { - stats.print (this); - for (auto &st : stat_tracers) - st->print_stats (); -} - -/*------------------------------------------------------------------------*/ - -// Only useful for debugging purposes. - -void Internal::dump (Clause *c) { - for (const auto &lit : *c) - printf ("%d ", lit); - printf ("0\n"); -} - -void Internal::dump () { - int64_t m = assumptions.size (); - for (auto idx : vars) - if (fixed (idx)) - m++; - for (const auto &c : clauses) - if (!c->garbage) - m++; - printf ("p cnf %d %" PRId64 "\n", max_var, m); - for (auto idx : vars) { - const int tmp = fixed (idx); - if (tmp) - printf ("%d 0\n", tmp < 0 ? -idx : idx); - } - for (const auto &c : clauses) - if (!c->garbage) - dump (c); - for (const auto &lit : assumptions) - printf ("%d 0\n", lit); - fflush (stdout); -} - -/*------------------------------------------------------------------------*/ - -bool Internal::traverse_constraint (ClauseIterator &it) { - if (constraint.empty () && !unsat_constraint) - return true; - - vector eclause; - if (unsat) - return it.clause (eclause); - - LOG (constraint, "traversing constraint"); - bool satisfied = false; - for (auto ilit : constraint) { - const int tmp = fixed (ilit); - if (tmp > 0) { - satisfied = true; - break; - } - if (tmp < 0) - continue; - const int elit = externalize (ilit); - eclause.push_back (elit); - } - if (!satisfied && !it.clause (eclause)) - return false; - - return true; -} -/*------------------------------------------------------------------------*/ - -bool Internal::traverse_clauses (ClauseIterator &it) { - vector eclause; - if (unsat) - return it.clause (eclause); - for (const auto &c : clauses) { - if (c->garbage) - continue; - if (c->redundant) - continue; - bool satisfied = false; - for (const auto &ilit : *c) { - const int tmp = fixed (ilit); - if (tmp > 0) { - satisfied = true; - break; - } - if (tmp < 0) - continue; - const int elit = externalize (ilit); - eclause.push_back (elit); - } - if (!satisfied && !it.clause (eclause)) - return false; - eclause.clear (); - } - return true; -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_ipasir.cpp b/src/sat/cadical/cadical_ipasir.cpp deleted file mode 100644 index cb88deb4b..000000000 --- a/src/sat/cadical/cadical_ipasir.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include "global.h" - -#include "ipasir.h" -#include "ccadical.h" - -ABC_NAMESPACE_IMPL_START - -const char *ipasir_signature () { return ccadical_signature (); } - -void *ipasir_init () { return ccadical_init (); } - -void ipasir_release (void *solver) { - ccadical_release ((CCaDiCaL *) solver); -} - -void ipasir_add (void *solver, int lit) { - ccadical_add ((CCaDiCaL *) solver, lit); -} - -void ipasir_assume (void *solver, int lit) { - ccadical_assume ((CCaDiCaL *) solver, lit); -} - -int ipasir_solve (void *solver) { - return ccadical_solve ((CCaDiCaL *) solver); -} - -int ipasir_val (void *solver, int lit) { - return ccadical_val ((CCaDiCaL *) solver, lit); -} - -int ipasir_failed (void *solver, int lit) { - return ccadical_failed ((CCaDiCaL *) solver, lit); -} - -void ipasir_set_terminate (void *solver, void *state, - int (*terminate) (void *state)) { - ccadical_set_terminate ((CCaDiCaL *) solver, state, terminate); -} - -void ipasir_set_learn (void *solver, void *state, int max_length, - void (*learn) (void *state, int *clause)) { - ccadical_set_learn ((CCaDiCaL *) solver, state, max_length, learn); -} - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_kitten.c b/src/sat/cadical/cadical_kitten.c deleted file mode 100644 index da3738980..000000000 --- a/src/sat/cadical/cadical_kitten.c +++ /dev/null @@ -1,2609 +0,0 @@ -#include "global.h" - -#include "kitten.h" -#include "random.h" -#include "stack.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -ABC_NAMESPACE_IMPL_START - -typedef signed char value; - -static void die (const char *fmt, ...) { - fputs ("cadical_kitten: error: ", stderr); - va_list ap; - va_start (ap, fmt); - vfprintf (stderr, fmt, ap); - va_end (ap); - fputc ('\n', stderr); - exit (1); -} - -static inline void *cadical_kitten_calloc (size_t n, size_t size) { - void *res = calloc (n, size); - if (n && size && !res) - die ("out of memory allocating '%zu * %zu' bytes", n, size); - return res; -} - -#define CALLOC(T, P, N) \ - do { \ - (P) = (T*)cadical_kitten_calloc (N, sizeof *(P)); \ - } while (0) -#define DEALLOC(P, N) free (P) - -#undef ENLARGE_STACK - -#define ENLARGE_STACK(S) \ - do { \ - CADICAL_assert (FULL_STACK (S)); \ - const size_t SIZE = SIZE_STACK (S); \ - const size_t OLD_CAPACITY = CAPACITY_STACK (S); \ - const size_t NEW_CAPACITY = OLD_CAPACITY ? 2 * OLD_CAPACITY : 1; \ - const size_t BYTES = NEW_CAPACITY * sizeof *(S).begin; \ - (S).begin = (unsigned*)realloc ((S).begin, BYTES); \ - if (!(S).begin) \ - die ("out of memory reallocating '%zu' bytes", BYTES); \ - (S).allocated = (S).begin + NEW_CAPACITY; \ - (S).end = (S).begin + SIZE; \ - } while (0) - -// Beside allocators above also use stand alone statistics counters. - -#define INC(NAME) \ - do { \ - statistics *statistics = &cadical_kitten->statistics; \ - CADICAL_assert (statistics->NAME < UINT64_MAX); \ - statistics->NAME++; \ - } while (0) - -#define ADD(NAME, DELTA) \ - do { \ - statistics *statistics = &cadical_kitten->statistics; \ - CADICAL_assert (statistics->NAME <= UINT64_MAX - (DELTA)); \ - statistics->NAME += (DELTA); \ - } while (0) - -#define KITTEN_TICKS (cadical_kitten->statistics.cadical_kitten_ticks) - -#define INVALID UINT_MAX -#define MAX_VARS ((1u << 31) - 1) - -#define CORE_FLAG (1u) -#define LEARNED_FLAG (2u) - -// clang-format off - -typedef struct kar kar; -typedef struct kink kink; -typedef struct klause klause; -typedef STACK (unsigned) klauses; -typedef unsigneds katches; - -// clang-format on - -struct kar { - unsigned level; - unsigned reason; -}; - -struct kink { - unsigned next; - unsigned prev; - uint64_t stamp; -}; - -struct klause { - unsigned aux; - unsigned size; - unsigned flags; - unsigned lits[1]; -}; - -typedef struct statistics statistics; - -struct statistics { - uint64_t learned; - uint64_t original; - uint64_t cadical_kitten_flip; - uint64_t cadical_kitten_flipped; - uint64_t cadical_kitten_sat; - uint64_t cadical_kitten_solved; - uint64_t cadical_kitten_conflicts; - uint64_t cadical_kitten_decisions; - uint64_t cadical_kitten_propagations; - uint64_t cadical_kitten_ticks; - uint64_t cadical_kitten_unknown; - uint64_t cadical_kitten_unsat; -}; - -typedef struct kimits kimits; - -struct kimits { - uint64_t ticks; -}; - -struct cadical_kitten { - // First zero initialized field in 'clear_cadical_kitten' is 'status'. - // - int status; - -#if defined(LOGGING) - bool logging; -#endif - bool antecedents; - bool learned; - - unsigned level; - unsigned propagated; - unsigned unassigned; - unsigned inconsistent; - unsigned failing; - - uint64_t generator; - - size_t lits; - size_t evars; - - size_t end_original_ref; - - struct { - unsigned first, last; - uint64_t stamp; - unsigned search; - } queue; - - // The 'size' field below is the first not zero reinitialized field - // by 'memset' in 'clear_cadical_kitten' (after 'kissat'). - - size_t size; - size_t esize; - - kar *vars; - kink *links; - value *marks; - value *values; - bool *failed; - unsigned char *phases; - unsigned *import; - katches *watches; - - unsigneds analyzed; - unsigneds assumptions; - unsigneds core; - unsigneds rcore; - unsigneds eclause; - unsigneds export_; - unsigneds klause; - unsigneds klauses; - unsigneds resolved; - unsigneds trail; - unsigneds units; - unsigneds prime[2]; - - kimits limits; - int (*terminator) (void *); - void *terminator_data; - unsigneds clause; - uint64_t initialized; - statistics statistics; -}; - -/*------------------------------------------------------------------------*/ - -static inline bool is_core_klause (klause *c) { - return c->flags & CORE_FLAG; -} - -static inline bool is_learned_klause (klause *c) { - return c->flags & LEARNED_FLAG; -} - -static inline void set_core_klause (klause *c) { c->flags |= CORE_FLAG; } - -static inline void unset_core_klause (klause *c) { c->flags &= ~CORE_FLAG; } - -static inline klause *dereference_klause (cadical_kitten *cadical_kitten, unsigned ref) { - unsigned *res = BEGIN_STACK (cadical_kitten->klauses) + ref; - CADICAL_assert (res < END_STACK (cadical_kitten->klauses)); - return (klause *) res; -} - -static inline unsigned reference_klause (cadical_kitten *cadical_kitten, const klause *c) { - const unsigned *const begin = BEGIN_STACK (cadical_kitten->klauses); - const unsigned *p = (const unsigned *) c; - CADICAL_assert (begin <= p); - CADICAL_assert (p < END_STACK (cadical_kitten->klauses)); - const unsigned res = p - begin; - return res; -} - -/*------------------------------------------------------------------------*/ - -#define KATCHES(KIT) (cadical_kitten->watches[CADICAL_assert ((KIT) < cadical_kitten->lits), (KIT)]) - -#define all_klauses(C) \ - klause *C = begin_klauses (cadical_kitten), *end_##C = end_klauses (cadical_kitten); \ - (C) != end_##C; \ - (C) = next_klause (cadical_kitten, C) - -#define all_original_klauses(C) \ - klause *C = begin_klauses (cadical_kitten), \ - *end_##C = end_original_klauses (cadical_kitten); \ - (C) != end_##C; \ - (C) = next_klause (cadical_kitten, C) - -#define all_learned_klauses(C) \ - klause *C = begin_learned_klauses (cadical_kitten), \ - *end_##C = end_klauses (cadical_kitten); \ - (C) != end_##C; \ - (C) = next_klause (cadical_kitten, C) - -#define all_kits(KIT) \ - size_t KIT = 0, KIT_##END = cadical_kitten->lits; \ - KIT != KIT_##END; \ - KIT++ - -#define BEGIN_KLAUSE(C) (C)->lits - -#define END_KLAUSE(C) (BEGIN_KLAUSE (C) + (C)->size) - -#define all_literals_in_klause(KIT, C) \ - unsigned KIT, *KIT##_PTR = BEGIN_KLAUSE (C), \ - *KIT##_END = END_KLAUSE (C); \ - KIT##_PTR != KIT##_END && ((KIT = *KIT##_PTR), true); \ - ++KIT##_PTR - -#define all_antecedents(REF, C) \ - unsigned REF, *REF##_PTR = antecedents (C), \ - *REF##_END = REF##_PTR + (C)->aux; \ - REF##_PTR != REF##_END && ((REF = *REF##_PTR), true); \ - ++REF##_PTR - -#ifdef LOGGING - -#define logging (cadical_kitten->logging) - -static void log_basic (cadical_kitten *, const char *, ...) - __attribute__ ((format (printf, 2, 3))); - -static void log_basic (cadical_kitten *cadical_kitten, const char *fmt, ...) { - CADICAL_assert (logging); - printf ("c KITTEN %u ", cadical_kitten->level); - va_list ap; - va_start (ap, fmt); - vprintf (fmt, ap); - va_end (ap); - fputc ('\n', stdout); - fflush (stdout); -} - -static void log_reference (cadical_kitten *, unsigned, const char *, ...) - __attribute__ ((format (printf, 3, 4))); - -static void log_reference (cadical_kitten *cadical_kitten, unsigned ref, const char *fmt, - ...) { - klause *c = dereference_klause (cadical_kitten, ref); - CADICAL_assert (logging); - printf ("c KITTEN %u ", cadical_kitten->level); - va_list ap; - va_start (ap, fmt); - vprintf (fmt, ap); - va_end (ap); - if (is_learned_klause (c)) { - fputs (" learned", stdout); - if (c->aux) - printf ("[%u]", c->aux); - } else { - fputs (" original", stdout); - if (c->aux != INVALID) - printf ("[%u]", c->aux); - } - printf (" size %u clause[%u]", c->size, ref); - value *values = cadical_kitten->values; - kar *vars = cadical_kitten->vars; - for (all_literals_in_klause (lit, c)) { - printf (" %u", lit); - const value value = values[lit]; - if (value) - printf ("@%u=%d", vars[lit / 2].level, (int) value); - } - fputc ('\n', stdout); - fflush (stdout); -} - -static void log_literals (cadical_kitten *, unsigned *, unsigned, const char *, ...) - __attribute__ ((format (printf, 4, 5))); - -static void log_literals (cadical_kitten *cadical_kitten, unsigned *lits, unsigned size, - const char *fmt, ...) { - CADICAL_assert (logging); - printf ("c KITTEN %u ", cadical_kitten->level); - va_list ap; - va_start (ap, fmt); - vprintf (fmt, ap); - va_end (ap); - value *values = cadical_kitten->values; - kar *vars = cadical_kitten->vars; - for (unsigned i = 0; i < size; i++) { - const unsigned lit = lits[i]; - printf (" %u", lit); - const value value = values[lit]; - if (value) - printf ("@%u=%d", vars[lit / 2].level, (int) value); - } - fputc ('\n', stdout); - fflush (stdout); -} - -#define LOG(...) \ - do { \ - if (logging) \ - log_basic (cadical_kitten, __VA_ARGS__); \ - } while (0) - -#define ROG(...) \ - do { \ - if (logging) \ - log_reference (cadical_kitten, __VA_ARGS__); \ - } while (0) - -#define LOGLITS(...) \ - do { \ - if (logging) \ - log_literals (cadical_kitten, __VA_ARGS__); \ - } while (0) - -#else - -#define LOG(...) \ - do { \ - } while (0) -#define ROG(...) \ - do { \ - } while (0) -#define LOGLITS(...) \ - do { \ - } while (0) - -#endif - -static void check_queue (cadical_kitten *cadical_kitten) { -#ifdef CHECK_KITTEN - const unsigned vars = cadical_kitten->lits / 2; - unsigned found = 0, prev = INVALID; - kink *links = cadical_kitten->links; - uint64_t stamp = 0; - for (unsigned idx = cadical_kitten->queue.first, next; idx != INVALID; - idx = next) { - kink *link = links + idx; - CADICAL_assert (link->prev == prev); - CADICAL_assert (!found || stamp < link->stamp); - CADICAL_assert (link->stamp < cadical_kitten->queue.stamp); - stamp = link->stamp; - next = link->next; - prev = idx; - found++; - } - CADICAL_assert (found == vars); - unsigned next = INVALID; - found = 0; - for (unsigned idx = cadical_kitten->queue.last, prev; idx != INVALID; - idx = prev) { - kink *link = links + idx; - CADICAL_assert (link->next == next); - prev = link->prev; - next = idx; - found++; - } - CADICAL_assert (found == vars); - value *values = cadical_kitten->values; - bool first = true; - for (unsigned idx = cadical_kitten->queue.search, next; idx != INVALID; - idx = next) { - kink *link = links + idx; - next = link->next; - const unsigned lit = 2 * idx; - CADICAL_assert (first || values[lit]); - first = false; - } -#else - (void) cadical_kitten; -#endif -} - -static void update_search (cadical_kitten *cadical_kitten, unsigned idx) { - if (cadical_kitten->queue.search == idx) - return; - cadical_kitten->queue.search = idx; - LOG ("search updated to %u stamped %" PRIu64, idx, - cadical_kitten->links[idx].stamp); -} - -static void enqueue (cadical_kitten *cadical_kitten, unsigned idx) { - LOG ("enqueue %u", idx); - kink *links = cadical_kitten->links; - kink *l = links + idx; - const unsigned last = cadical_kitten->queue.last; - if (last == INVALID) - cadical_kitten->queue.first = idx; - else - links[last].next = idx; - l->prev = last; - l->next = INVALID; - cadical_kitten->queue.last = idx; - l->stamp = cadical_kitten->queue.stamp++; - LOG ("stamp %" PRIu64, l->stamp); -} - -static void dequeue (cadical_kitten *cadical_kitten, unsigned idx) { - LOG ("dequeue %u", idx); - kink *links = cadical_kitten->links; - kink *l = links + idx; - const unsigned prev = l->prev; - const unsigned next = l->next; - if (prev == INVALID) - cadical_kitten->queue.first = next; - else - links[prev].next = next; - if (next == INVALID) - cadical_kitten->queue.last = prev; - else - links[next].prev = prev; -} - -static void init_queue (cadical_kitten *cadical_kitten, size_t old_vars, size_t new_vars) { - for (size_t idx = old_vars; idx < new_vars; idx++) { - CADICAL_assert (!cadical_kitten->values[2 * idx]); - CADICAL_assert (cadical_kitten->unassigned < UINT_MAX); - cadical_kitten->unassigned++; - enqueue (cadical_kitten, idx); - } - LOG ("initialized decision queue from %zu to %zu", old_vars, new_vars); - update_search (cadical_kitten, cadical_kitten->queue.last); - check_queue (cadical_kitten); -} - -static void initialize_cadical_kitten (cadical_kitten *cadical_kitten) { - cadical_kitten->queue.first = INVALID; - cadical_kitten->queue.last = INVALID; - cadical_kitten->inconsistent = INVALID; - cadical_kitten->failing = INVALID; - cadical_kitten->queue.search = INVALID; - cadical_kitten->terminator = 0; - cadical_kitten->terminator_data = 0; - cadical_kitten->limits.ticks = UINT64_MAX; - cadical_kitten->generator = cadical_kitten->initialized++; -} - -static void clear_cadical_kitten (cadical_kitten *cadical_kitten) { - size_t bytes = (char *) &cadical_kitten->size - (char *) &cadical_kitten->status; - memset (&cadical_kitten->status, 0, bytes); - memset (&cadical_kitten->statistics, 0, sizeof (statistics)); - initialize_cadical_kitten (cadical_kitten); -} - -#define RESIZE1(T, P) \ - do { \ - void *OLD_PTR = (P); \ - CALLOC (T, (P), new_size / 2); \ - const size_t BYTES = old_vars * sizeof *(P); \ - memcpy ((P), OLD_PTR, BYTES); \ - void *NEW_PTR = (P); \ - (P) = (T*)OLD_PTR; \ - DEALLOC ((P), old_size / 2); \ - (P) = (T*)NEW_PTR; \ - } while (0) - -#define RESIZE2(T, P) \ - do { \ - void *OLD_PTR = (P); \ - CALLOC (T, (P), new_size); \ - const size_t BYTES = old_lits * sizeof *(P); \ - memcpy ((P), OLD_PTR, BYTES); \ - void *NEW_PTR = (P); \ - (P) = (T*)OLD_PTR; \ - DEALLOC ((P), old_size); \ - (P) = (T*)NEW_PTR; \ - } while (0) - -static void enlarge_internal (cadical_kitten *cadical_kitten, size_t lit) { - const size_t new_lits = (lit | 1) + 1; - const size_t old_lits = cadical_kitten->lits; - CADICAL_assert (old_lits <= lit); - CADICAL_assert (old_lits < new_lits); - CADICAL_assert ((lit ^ 1) < new_lits); - CADICAL_assert (lit < new_lits); - const size_t old_size = cadical_kitten->size; - const unsigned new_vars = new_lits / 2; - const unsigned old_vars = old_lits / 2; - if (old_size < new_lits) { - size_t new_size = old_size ? 2 * old_size : 2; - while (new_size <= lit) - new_size *= 2; - LOG ("internal literals resized to %zu from %zu (requested %zu)", - new_size, old_size, new_lits); - - RESIZE1 (value, cadical_kitten->marks); - RESIZE1 (unsigned char, cadical_kitten->phases); - RESIZE2 (value, cadical_kitten->values); - RESIZE2 (bool, cadical_kitten->failed); - RESIZE1 (kar, cadical_kitten->vars); - RESIZE1 (kink, cadical_kitten->links); - RESIZE2 (katches, cadical_kitten->watches); - - cadical_kitten->size = new_size; - } - cadical_kitten->lits = new_lits; - init_queue (cadical_kitten, old_vars, new_vars); - LOG ("internal literals activated until %zu literals", new_lits); - return; -} - -static const char *status_to_string (int status) { - switch (status) { - case 10: - return "formula satisfied"; - case 11: - return "formula satisfied and prime implicant computed"; - case 20: - return "formula inconsistent"; - case 21: - return "formula inconsistent and core computed"; - default: - CADICAL_assert (!status); - return "formula unsolved"; - } -} - -static void invalid_api_usage (const char *fun, const char *fmt, ...) { - fprintf (stderr, "cadical_kitten: fatal error: invalid API usage in '%s': ", fun); - va_list ap; - va_start (ap, fmt); - vfprintf (stderr, fmt, ap); - va_end (ap); - fputc ('\n', stderr); - fflush (stderr); - abort (); -} - -#define INVALID_API_USAGE(...) invalid_api_usage (__func__, __VA_ARGS__) - -#define REQUIRE_INITIALIZED() \ - do { \ - if (!cadical_kitten) \ - INVALID_API_USAGE ("solver argument zero"); \ - } while (0) - -#define REQUIRE_STATUS(EXPECTED) \ - do { \ - REQUIRE_INITIALIZED (); \ - if (cadical_kitten->status != (EXPECTED)) \ - INVALID_API_USAGE ("invalid status '%s' (expected '%s')", \ - status_to_string (cadical_kitten->status), \ - status_to_string (EXPECTED)); \ - } while (0) - -#define UPDATE_STATUS(STATUS) \ - do { \ - if (cadical_kitten->status != (STATUS)) \ - LOG ("updating status from '%s' to '%s'", \ - status_to_string (cadical_kitten->status), status_to_string (STATUS)); \ - else \ - LOG ("keeping status at '%s'", status_to_string (STATUS)); \ - cadical_kitten->status = (STATUS); \ - } while (0) - -cadical_kitten *cadical_kitten_init (void) { - cadical_kitten *cadical_kitten; - CALLOC (struct cadical_kitten, cadical_kitten, 1); - initialize_cadical_kitten (cadical_kitten); - return cadical_kitten; -} - -#ifdef LOGGING -void cadical_kitten_set_logging (cadical_kitten *cadical_kitten) { logging = true; } -#endif - -void cadical_kitten_track_antecedents (cadical_kitten *cadical_kitten) { - REQUIRE_STATUS (0); - - if (cadical_kitten->learned) - INVALID_API_USAGE ("can not start tracking antecedents after learning"); - - LOG ("enabling antecedents tracking"); - cadical_kitten->antecedents = true; -} - -void cadical_kitten_randomize_phases (cadical_kitten *cadical_kitten) { - REQUIRE_INITIALIZED (); - - LOG ("randomizing phases"); - - unsigned char *phases = cadical_kitten->phases; - const unsigned vars = cadical_kitten->size / 2; - - uint64_t random = kissat_next_random64 (&cadical_kitten->generator); - - unsigned i = 0; - const unsigned rest = vars & ~63u; - - while (i != rest) { - uint64_t *p = (uint64_t *) (phases + i); - p[0] = (random >> 0) & 0x0101010101010101; - p[1] = (random >> 1) & 0x0101010101010101; - p[2] = (random >> 2) & 0x0101010101010101; - p[3] = (random >> 3) & 0x0101010101010101; - p[4] = (random >> 4) & 0x0101010101010101; - p[5] = (random >> 5) & 0x0101010101010101; - p[6] = (random >> 6) & 0x0101010101010101; - p[7] = (random >> 7) & 0x0101010101010101; - random = kissat_next_random64 (&cadical_kitten->generator); - i += 64; - } - - unsigned shift = 0; - while (i != vars) - phases[i++] = (random >> shift++) & 1; -} - -void cadical_kitten_flip_phases (cadical_kitten *cadical_kitten) { - REQUIRE_INITIALIZED (); - - LOG ("flipping phases"); - - unsigned char *phases = cadical_kitten->phases; - const unsigned vars = cadical_kitten->size / 2; - - unsigned i = 0; - const unsigned rest = vars & ~7u; - - while (i != rest) { - uint64_t *p = (uint64_t *) (phases + i); - *p ^= 0x0101010101010101; - i += 8; - } - - while (i != vars) - phases[i++] ^= 1; -} - -void cadical_kitten_no_ticks_limit (cadical_kitten *cadical_kitten) { - REQUIRE_INITIALIZED (); - LOG ("forcing no ticks limit"); - cadical_kitten->limits.ticks = UINT64_MAX; -} - -uint64_t cadical_kitten_current_ticks (cadical_kitten *cadical_kitten) { - REQUIRE_INITIALIZED (); - const uint64_t current = KITTEN_TICKS; - return current; -} - -void cadical_kitten_set_ticks_limit (cadical_kitten *cadical_kitten, uint64_t delta) { - REQUIRE_INITIALIZED (); - const uint64_t current = KITTEN_TICKS; - uint64_t limit; - if (UINT64_MAX - delta <= current) { - LOG ("forcing unlimited ticks limit"); - limit = UINT64_MAX; - } else { - limit = current + delta; - LOG ("new limit of %" PRIu64 " ticks after %" PRIu64, limit, delta); - } - - cadical_kitten->limits.ticks = limit; -} - -void cadical_kitten_no_terminator (cadical_kitten *cadical_kitten) { - REQUIRE_INITIALIZED (); - LOG ("removing terminator"); - cadical_kitten->terminator = 0; - cadical_kitten->terminator_data = 0; -} - -void cadical_kitten_set_terminator (cadical_kitten *cadical_kitten, void *data, - int (*terminator) (void *)) { - REQUIRE_INITIALIZED (); - LOG ("setting terminator"); - cadical_kitten->terminator = terminator; - cadical_kitten->terminator_data = data; -} - -static void shuffle_unsigned_array (cadical_kitten *cadical_kitten, size_t size, - unsigned *a) { - for (size_t i = 0; i < size; i++) { - const size_t j = kissat_pick_random (&cadical_kitten->generator, 0, i); - if (j == i) - continue; - const unsigned first = a[i]; - const unsigned second = a[j]; - a[i] = second; - a[j] = first; - } -} - -static void shuffle_unsigned_stack (cadical_kitten *cadical_kitten, unsigneds *stack) { - const size_t size = SIZE_STACK (*stack); - unsigned *a = BEGIN_STACK (*stack); - shuffle_unsigned_array (cadical_kitten, size, a); -} - -static void shuffle_katches (cadical_kitten *cadical_kitten) { - LOG ("shuffling watch lists"); - for (size_t lit = 0; lit < cadical_kitten->lits; lit++) - shuffle_unsigned_stack (cadical_kitten, &KATCHES (lit)); -} - -static void shuffle_queue (cadical_kitten *cadical_kitten) { - LOG ("shuffling variable decision order"); - - const unsigned vars = cadical_kitten->lits / 2; - for (unsigned i = 0; i < vars; i++) { - const unsigned idx = kissat_pick_random (&cadical_kitten->generator, 0, vars); - dequeue (cadical_kitten, idx); - enqueue (cadical_kitten, idx); - } - update_search (cadical_kitten, cadical_kitten->queue.last); -} - -static void shuffle_units (cadical_kitten *cadical_kitten) { - LOG ("shuffling units"); - shuffle_unsigned_stack (cadical_kitten, &cadical_kitten->units); -} - -void cadical_kitten_shuffle_clauses (cadical_kitten *cadical_kitten) { - REQUIRE_STATUS (0); - shuffle_queue (cadical_kitten); - shuffle_katches (cadical_kitten); - shuffle_units (cadical_kitten); -} - -static inline unsigned *antecedents (klause *c) { - CADICAL_assert (is_learned_klause (c)); - return c->lits + c->size; -} - -static inline void watch_klause (cadical_kitten *cadical_kitten, unsigned lit, - unsigned ref) { - ROG (ref, "watching %u in", lit); - katches *watches = &KATCHES (lit); - PUSH_STACK (*watches, ref); -} - -static inline void connect_new_klause (cadical_kitten *cadical_kitten, unsigned ref) { - ROG (ref, "new"); - - klause *c = dereference_klause (cadical_kitten, ref); - - if (!c->size) { - if (cadical_kitten->inconsistent == INVALID) { - ROG (ref, "registering inconsistent empty"); - cadical_kitten->inconsistent = ref; - } else - ROG (ref, "ignoring inconsistent empty"); - } else if (c->size == 1) { - ROG (ref, "watching unit"); - PUSH_STACK (cadical_kitten->units, ref); - } else { - watch_klause (cadical_kitten, c->lits[0], ref); - watch_klause (cadical_kitten, c->lits[1], ref); - } -} - -static unsigned new_reference (cadical_kitten *cadical_kitten) { - size_t ref = SIZE_STACK (cadical_kitten->klauses); - if (ref >= INVALID) { - die ("maximum number of literals exhausted"); - } - const unsigned res = (unsigned) ref; - CADICAL_assert (res != INVALID); - INC (cadical_kitten_ticks); - return res; -} - -static void new_original_klause (cadical_kitten *cadical_kitten, unsigned id) { - unsigned res = new_reference (cadical_kitten); - unsigned size = SIZE_STACK (cadical_kitten->klause); - unsigneds *klauses = &cadical_kitten->klauses; - PUSH_STACK (*klauses, id); - PUSH_STACK (*klauses, size); - PUSH_STACK (*klauses, 0); - for (all_stack (unsigned, lit, cadical_kitten->klause)) - PUSH_STACK (*klauses, lit); - connect_new_klause (cadical_kitten, res); - cadical_kitten->end_original_ref = SIZE_STACK (*klauses); - cadical_kitten->statistics.original++; -} - -static void enlarge_external (cadical_kitten *cadical_kitten, size_t eidx) { - const size_t old_size = cadical_kitten->esize; - const unsigned old_evars = cadical_kitten->evars; - CADICAL_assert (old_evars <= eidx); - const unsigned new_evars = eidx + 1; - if (old_size <= eidx) { - size_t new_size = old_size ? 2 * old_size : 1; - while (new_size <= eidx) - new_size *= 2; - LOG ("external resizing to %zu variables from %zu (requested %u)", - new_size, old_size, new_evars); - unsigned *old_import = cadical_kitten->import; - CALLOC (unsigned, cadical_kitten->import, new_size); - const size_t bytes = old_evars * sizeof *cadical_kitten->import; - memcpy (cadical_kitten->import, old_import, bytes); - DEALLOC (old_import, old_size); - cadical_kitten->esize = new_size; - } - cadical_kitten->evars = new_evars; - LOG ("external variables enlarged to %u", new_evars); -} - -static unsigned import_literal (cadical_kitten *cadical_kitten, unsigned elit) { - const unsigned eidx = elit / 2; - if (eidx >= cadical_kitten->evars) - enlarge_external (cadical_kitten, eidx); - - unsigned iidx = cadical_kitten->import[eidx]; - if (!iidx) { - iidx = SIZE_STACK (cadical_kitten->export_); - PUSH_STACK (cadical_kitten->export_, eidx); - cadical_kitten->import[eidx] = iidx + 1; - } else - iidx--; - unsigned ilit = 2 * iidx + (elit & 1); - LOG ("imported external literal %u as internal literal %u", elit, ilit); - if (ilit >= cadical_kitten->lits) - enlarge_internal (cadical_kitten, ilit); - return ilit; -} - -static unsigned export_literal (cadical_kitten *cadical_kitten, unsigned ilit) { - const unsigned iidx = ilit / 2; - CADICAL_assert (iidx < SIZE_STACK (cadical_kitten->export_)); - const unsigned eidx = PEEK_STACK (cadical_kitten->export_, iidx); - const unsigned elit = 2 * eidx + (ilit & 1); - return elit; -} - -unsigned cadical_new_learned_klause (cadical_kitten *cadical_kitten) { - unsigned res = new_reference (cadical_kitten); - unsigneds *klauses = &cadical_kitten->klauses; - const size_t size = SIZE_STACK (cadical_kitten->klause); - CADICAL_assert (size <= UINT_MAX); - const size_t aux = - cadical_kitten->antecedents ? SIZE_STACK (cadical_kitten->resolved) : 0; - CADICAL_assert (aux <= UINT_MAX); - PUSH_STACK (*klauses, (unsigned) aux); - PUSH_STACK (*klauses, (unsigned) size); - PUSH_STACK (*klauses, LEARNED_FLAG); - for (all_stack (unsigned, lit, cadical_kitten->klause)) - PUSH_STACK (*klauses, lit); - if (aux) - for (all_stack (unsigned, ref, cadical_kitten->resolved)) - PUSH_STACK (*klauses, ref); - connect_new_klause (cadical_kitten, res); - cadical_kitten->learned = true; - cadical_kitten->statistics.learned++; - return res; -} - -void cadical_kitten_clear (cadical_kitten *cadical_kitten) { - LOG ("clear cadical_kitten of size %zu", cadical_kitten->size); - - CADICAL_assert (EMPTY_STACK (cadical_kitten->analyzed)); - CADICAL_assert (EMPTY_STACK (cadical_kitten->eclause)); - CADICAL_assert (EMPTY_STACK (cadical_kitten->resolved)); - - CLEAR_STACK (cadical_kitten->assumptions); - CLEAR_STACK (cadical_kitten->core); - CLEAR_STACK (cadical_kitten->klause); - CLEAR_STACK (cadical_kitten->klauses); - CLEAR_STACK (cadical_kitten->trail); - CLEAR_STACK (cadical_kitten->units); - CLEAR_STACK (cadical_kitten->clause); - CLEAR_STACK (cadical_kitten->prime[0]); - CLEAR_STACK (cadical_kitten->prime[1]); - - for (all_kits (kit)) - CLEAR_STACK (KATCHES (kit)); - - while (!EMPTY_STACK (cadical_kitten->export_)) - cadical_kitten->import[POP_STACK (cadical_kitten->export_)] = 0; - - const size_t lits = cadical_kitten->size; - const unsigned vars = lits / 2; - -#ifndef CADICAL_NDEBUG - for (unsigned i = 0; i < vars; i++) - CADICAL_assert (!cadical_kitten->marks[i]); -#endif - - memset (cadical_kitten->phases, 0, vars); - memset (cadical_kitten->values, 0, lits); - memset (cadical_kitten->failed, 0, lits); - memset (cadical_kitten->vars, 0, vars); - - clear_cadical_kitten (cadical_kitten); -} - -void cadical_kitten_release (cadical_kitten *cadical_kitten) { - RELEASE_STACK (cadical_kitten->analyzed); - RELEASE_STACK (cadical_kitten->assumptions); - RELEASE_STACK (cadical_kitten->core); - RELEASE_STACK (cadical_kitten->eclause); - RELEASE_STACK (cadical_kitten->export_); - RELEASE_STACK (cadical_kitten->klause); - RELEASE_STACK (cadical_kitten->klauses); - RELEASE_STACK (cadical_kitten->resolved); - RELEASE_STACK (cadical_kitten->trail); - RELEASE_STACK (cadical_kitten->units); - RELEASE_STACK (cadical_kitten->clause); - RELEASE_STACK (cadical_kitten->prime[0]); - RELEASE_STACK (cadical_kitten->prime[1]); - - for (size_t lit = 0; lit < cadical_kitten->size; lit++) - RELEASE_STACK (cadical_kitten->watches[lit]); - - const size_t lits = cadical_kitten->size; - const unsigned vars = lits / 2; - DEALLOC (cadical_kitten->marks, vars); - DEALLOC (cadical_kitten->phases, vars); - DEALLOC (cadical_kitten->values, lits); - DEALLOC (cadical_kitten->failed, lits); - DEALLOC (cadical_kitten->vars, vars); - DEALLOC (cadical_kitten->links, vars); - DEALLOC (cadical_kitten->watches, lits); - DEALLOC (cadical_kitten->import, cadical_kitten->esize); - (void) vars; - - free (cadical_kitten); -} - -static inline void move_to_front (cadical_kitten *cadical_kitten, unsigned idx) { - if (idx == cadical_kitten->queue.last) - return; - LOG ("move to front variable %u", idx); - dequeue (cadical_kitten, idx); - enqueue (cadical_kitten, idx); - CADICAL_assert (cadical_kitten->values[2 * idx]); -} - -static inline void assign (cadical_kitten *cadical_kitten, unsigned lit, unsigned reason) { -#ifdef LOGGING - if (reason == INVALID) - LOG ("assign %u as decision", lit); - else - ROG (reason, "assign %u reason", lit); -#endif - value *values = cadical_kitten->values; - const unsigned not_lit = lit ^ 1; - CADICAL_assert (!values[lit]); - CADICAL_assert (!values[not_lit]); - values[lit] = 1; - values[not_lit] = -1; - const unsigned idx = lit / 2; - const unsigned sign = lit & 1; - cadical_kitten->phases[idx] = sign; - PUSH_STACK (cadical_kitten->trail, lit); - kar *v = cadical_kitten->vars + idx; - v->level = cadical_kitten->level; - if (!v->level) { - CADICAL_assert (reason != INVALID); - klause *c = dereference_klause (cadical_kitten, reason); - if (c->size > 1) { - if (cadical_kitten->antecedents) { - PUSH_STACK (cadical_kitten->resolved, reason); - for (all_literals_in_klause (other, c)) - if (other != lit) { - const unsigned other_idx = other / 2; - const unsigned other_ref = cadical_kitten->vars[other_idx].reason; - CADICAL_assert (other_ref != INVALID); - PUSH_STACK (cadical_kitten->resolved, other_ref); - } - } - PUSH_STACK (cadical_kitten->klause, lit); - reason = cadical_new_learned_klause (cadical_kitten); - CLEAR_STACK (cadical_kitten->resolved); - CLEAR_STACK (cadical_kitten->klause); - } - } - v->reason = reason; - CADICAL_assert (cadical_kitten->unassigned); - cadical_kitten->unassigned--; -} - -static inline unsigned propagate_literal (cadical_kitten *cadical_kitten, unsigned lit) { - LOG ("propagating %u", lit); - value *values = cadical_kitten->values; - CADICAL_assert (values[lit] > 0); - const unsigned not_lit = lit ^ 1; - katches *watches = cadical_kitten->watches + not_lit; - unsigned conflict = INVALID; - unsigned *q = BEGIN_STACK (*watches); - const unsigned *const end_watches = END_STACK (*watches); - unsigned const *p = q; - uint64_t ticks = (((char *) end_watches - (char *) q) >> 7) + 1; - while (p != end_watches) { - const unsigned ref = *q++ = *p++; - klause *c = dereference_klause (cadical_kitten, ref); - CADICAL_assert (c->size > 1); - unsigned *lits = c->lits; - const unsigned other = lits[0] ^ lits[1] ^ not_lit; - const value other_value = values[other]; - ticks++; - if (other_value > 0) - continue; - value replacement_value = -1; - unsigned replacement = INVALID; - const unsigned *const end_lits = lits + c->size; - unsigned *r; - for (r = lits + 2; r != end_lits; r++) { - replacement = *r; - replacement_value = values[replacement]; - if (replacement_value >= 0) - break; - } - if (replacement_value >= 0) { - CADICAL_assert (replacement != INVALID); - ROG (ref, "unwatching %u in", not_lit); - lits[0] = other; - lits[1] = replacement; - *r = not_lit; - watch_klause (cadical_kitten, replacement, ref); - q--; - } else if (other_value < 0) { - ROG (ref, "conflict"); - INC (cadical_kitten_conflicts); - conflict = ref; - break; - } else { - CADICAL_assert (!other_value); - assign (cadical_kitten, other, ref); - } - } - while (p != end_watches) - *q++ = *p++; - SET_END_OF_STACK (*watches, q); - ADD (cadical_kitten_ticks, ticks); - return conflict; -} - -static inline unsigned propagate (cadical_kitten *cadical_kitten) { - CADICAL_assert (cadical_kitten->inconsistent == INVALID); - unsigned propagated = 0; - unsigned conflict = INVALID; - while (conflict == INVALID && - cadical_kitten->propagated < SIZE_STACK (cadical_kitten->trail)) { - if (cadical_kitten->terminator && - cadical_kitten->terminator (cadical_kitten->terminator_data)) { - break; - } - const unsigned lit = PEEK_STACK (cadical_kitten->trail, cadical_kitten->propagated); - conflict = propagate_literal (cadical_kitten, lit); - cadical_kitten->propagated++; - propagated++; - } - ADD (cadical_kitten_propagations, propagated); - return conflict; -} - -static void bump (cadical_kitten *cadical_kitten) { - value *marks = cadical_kitten->marks; - for (all_stack (unsigned, idx, cadical_kitten->analyzed)) { - marks[idx] = 0; - move_to_front (cadical_kitten, idx); - } - check_queue (cadical_kitten); -} - -static inline void unassign (cadical_kitten *cadical_kitten, value *values, unsigned lit) { - const unsigned not_lit = lit ^ 1; - CADICAL_assert (values[lit]); - CADICAL_assert (values[not_lit]); - const unsigned idx = lit / 2; -#ifdef LOGGING - kar *var = cadical_kitten->vars + idx; - cadical_kitten->level = var->level; - LOG ("unassign %u", lit); -#endif - values[lit] = values[not_lit] = 0; - CADICAL_assert (cadical_kitten->unassigned < cadical_kitten->lits / 2); - cadical_kitten->unassigned++; - kink *links = cadical_kitten->links; - kink *link = links + idx; - if (link->stamp > links[cadical_kitten->queue.search].stamp) - update_search (cadical_kitten, idx); -} - -static void backtrack (cadical_kitten *cadical_kitten, unsigned jump) { - check_queue (cadical_kitten); - CADICAL_assert (jump < cadical_kitten->level); - LOG ("back%s to level %u", - (cadical_kitten->level == jump + 1 ? "tracking" : "jumping"), jump); - kar *vars = cadical_kitten->vars; - value *values = cadical_kitten->values; - unsigneds *trail = &cadical_kitten->trail; - while (!EMPTY_STACK (*trail)) { - const unsigned lit = TOP_STACK (*trail); - const unsigned idx = lit / 2; - const unsigned level = vars[idx].level; - if (level == jump) - break; - (void) POP_STACK (*trail); - unassign (cadical_kitten, values, lit); - } - cadical_kitten->propagated = SIZE_STACK (*trail); - cadical_kitten->level = jump; - check_queue (cadical_kitten); -} - -void cadical_completely_backtrack_to_root_level (cadical_kitten *cadical_kitten) { - check_queue (cadical_kitten); - LOG ("completely backtracking to level 0"); - value *values = cadical_kitten->values; - unsigneds *trail = &cadical_kitten->trail; - unsigneds *units = &cadical_kitten->units; -#ifndef CADICAL_NDEBUG - kar *vars = cadical_kitten->vars; -#endif - for (all_stack (unsigned, lit, *trail)) { - CADICAL_assert (vars[lit / 2].level); - unassign (cadical_kitten, values, lit); - } - CLEAR_STACK (*trail); - for (all_stack (unsigned, ref, *units)) { - klause *c = dereference_klause (cadical_kitten, ref); - CADICAL_assert (c->size == 1); - const unsigned unit = c->lits[0]; - const value value = values[unit]; - if (value <= 0) - continue; - unassign (cadical_kitten, values, unit); - } - cadical_kitten->propagated = 0; - cadical_kitten->level = 0; - check_queue (cadical_kitten); -} - -static void analyze (cadical_kitten *cadical_kitten, unsigned conflict) { - CADICAL_assert (cadical_kitten->level); - CADICAL_assert (cadical_kitten->inconsistent == INVALID); - CADICAL_assert (EMPTY_STACK (cadical_kitten->analyzed)); - CADICAL_assert (EMPTY_STACK (cadical_kitten->resolved)); - CADICAL_assert (EMPTY_STACK (cadical_kitten->klause)); - PUSH_STACK (cadical_kitten->klause, INVALID); - unsigned reason = conflict; - value *marks = cadical_kitten->marks; - const kar *const vars = cadical_kitten->vars; - const unsigned level = cadical_kitten->level; - unsigned const *p = END_STACK (cadical_kitten->trail); - unsigned open = 0, jump = 0, size = 1, uip; - for (;;) { - CADICAL_assert (reason != INVALID); - klause *c = dereference_klause (cadical_kitten, reason); - CADICAL_assert (c); - ROG (reason, "analyzing"); - PUSH_STACK (cadical_kitten->resolved, reason); - for (all_literals_in_klause (lit, c)) { - const unsigned idx = lit / 2; - if (marks[idx]) - continue; - CADICAL_assert (cadical_kitten->values[lit] < 0); - LOG ("analyzed %u", lit); - marks[idx] = true; - PUSH_STACK (cadical_kitten->analyzed, idx); - const kar *const v = vars + idx; - const unsigned tmp = v->level; - if (tmp < level) { - if (tmp > jump) { - jump = tmp; - if (size > 1) { - const unsigned other = PEEK_STACK (cadical_kitten->klause, 1); - POKE_STACK (cadical_kitten->klause, 1, lit); - lit = other; - } - } - PUSH_STACK (cadical_kitten->klause, lit); - size++; - } else - open++; - } - unsigned idx; - do { - CADICAL_assert (BEGIN_STACK (cadical_kitten->trail) < p); - uip = *--p; - } while (!marks[idx = uip / 2]); - CADICAL_assert (open); - if (!--open) - break; - reason = vars[idx].reason; - } - const unsigned not_uip = uip ^ 1; - LOG ("first UIP %u jump level %u size %u", not_uip, jump, size); - POKE_STACK (cadical_kitten->klause, 0, not_uip); - bump (cadical_kitten); - CLEAR_STACK (cadical_kitten->analyzed); - const unsigned learned_ref = cadical_new_learned_klause (cadical_kitten); - CLEAR_STACK (cadical_kitten->resolved); - CLEAR_STACK (cadical_kitten->klause); - backtrack (cadical_kitten, jump); - assign (cadical_kitten, not_uip, learned_ref); -} - -static void failing (cadical_kitten *cadical_kitten) { - CADICAL_assert (cadical_kitten->inconsistent == INVALID); - CADICAL_assert (!EMPTY_STACK (cadical_kitten->assumptions)); - CADICAL_assert (EMPTY_STACK (cadical_kitten->analyzed)); - CADICAL_assert (EMPTY_STACK (cadical_kitten->resolved)); - CADICAL_assert (EMPTY_STACK (cadical_kitten->klause)); - LOG ("analyzing failing assumptions"); - const value *const values = cadical_kitten->values; - const kar *const vars = cadical_kitten->vars; - unsigned failed_clashing = INVALID; - unsigned first_failed = INVALID; - unsigned failed_unit = INVALID; - for (all_stack (unsigned, lit, cadical_kitten->assumptions)) { - if (values[lit] >= 0) - continue; - if (first_failed == INVALID) - first_failed = lit; - const unsigned failed_idx = lit / 2; - const kar *const failed_var = vars + failed_idx; - if (!failed_var->level) { - failed_unit = lit; - break; - } - if (failed_clashing == INVALID && failed_var->reason == INVALID) - failed_clashing = lit; - } - unsigned failed; - if (failed_unit != INVALID) - failed = failed_unit; - else if (failed_clashing != INVALID) - failed = failed_clashing; - else - failed = first_failed; - CADICAL_assert (failed != INVALID); - const unsigned failed_idx = failed / 2; - const kar *const failed_var = vars + failed_idx; - const unsigned failed_reason = failed_var->reason; - LOG ("first failed assumption %u", failed); - cadical_kitten->failed[failed] = true; - - if (failed_unit != INVALID) { - CADICAL_assert (dereference_klause (cadical_kitten, failed_reason)->size == 1); - LOG ("root-level falsified assumption %u", failed); - cadical_kitten->failing = failed_reason; - ROG (cadical_kitten->failing, "failing reason"); - return; - } - - const unsigned not_failed = failed ^ 1; - if (failed_clashing != INVALID) { - LOG ("clashing with negated assumption %u", not_failed); - cadical_kitten->failed[not_failed] = true; - CADICAL_assert (cadical_kitten->failing == INVALID); - return; - } - - value *marks = cadical_kitten->marks; - CADICAL_assert (!marks[failed_idx]); - marks[failed_idx] = true; - PUSH_STACK (cadical_kitten->analyzed, failed_idx); - PUSH_STACK (cadical_kitten->klause, not_failed); - - unsigneds work; - INIT_STACK (work); - - LOGLITS (BEGIN_STACK (cadical_kitten->trail), SIZE_STACK (cadical_kitten->trail), - "trail"); - - CADICAL_assert (SIZE_STACK (cadical_kitten->trail)); - unsigned const *p = END_STACK (cadical_kitten->trail); - unsigned open = 1; - for (;;) { - if (!open) - break; - open--; - unsigned idx, uip; - do { - CADICAL_assert (BEGIN_STACK (cadical_kitten->trail) < p); - uip = *--p; - } while (!marks[idx = uip / 2]); - - const kar *var = vars + idx; - const unsigned reason = var->reason; - if (reason == INVALID) { - unsigned lit = 2 * idx; - if (values[lit] < 0) - lit ^= 1; - LOG ("failed assumption %u", lit); - CADICAL_assert (!cadical_kitten->failed[lit]); - cadical_kitten->failed[lit] = true; - const unsigned not_lit = lit ^ 1; - PUSH_STACK (cadical_kitten->klause, not_lit); - } else { - ROG (reason, "analyzing"); - PUSH_STACK (cadical_kitten->resolved, reason); - klause *c = dereference_klause (cadical_kitten, reason); - for (all_literals_in_klause (other, c)) { - const unsigned other_idx = other / 2; - if (marks[other_idx]) - continue; - CADICAL_assert (other_idx != idx); - marks[other_idx] = true; - CADICAL_assert (values[other]); - if (vars[other_idx].level) - open++; - else - PUSH_STACK (work, other_idx); - PUSH_STACK (cadical_kitten->analyzed, other_idx); - - LOG ("analyzing final literal %u", other ^ 1); - } - } - } - for (size_t next = 0; next < SIZE_STACK (work); next++) { - const unsigned idx = PEEK_STACK (work, next); - const kar *var = vars + idx; - const unsigned reason = var->reason; - if (reason == INVALID) { - unsigned lit = 2 * idx; - if (values[lit] < 0) - lit ^= 1; - LOG ("failed assumption %u", lit); - CADICAL_assert (!cadical_kitten->failed[lit]); - cadical_kitten->failed[lit] = true; - const unsigned not_lit = lit ^ 1; - PUSH_STACK (cadical_kitten->klause, not_lit); - } else { - ROG (reason, "analyzing unit"); - PUSH_STACK (cadical_kitten->resolved, reason); - } - } - - // this is bfs not dfs so it does not work for lrat :/ - /* - for (size_t next = 0; next < SIZE_STACK (cadical_kitten->analyzed); next++) { - const unsigned idx = PEEK_STACK (cadical_kitten->analyzed, next); - CADICAL_assert (marks[idx]); - const kar *var = vars + idx; - const unsigned reason = var->reason; - if (reason == INVALID) { - unsigned lit = 2 * idx; - if (values[lit] < 0) - lit ^= 1; - LOG ("failed assumption %u", lit); - CADICAL_assert (!cadical_kitten->failed[lit]); - cadical_kitten->failed[lit] = true; - const unsigned not_lit = lit ^ 1; - PUSH_STACK (cadical_kitten->klause, not_lit); - } else { - ROG (reason, "analyzing"); - PUSH_STACK (cadical_kitten->resolved, reason); - klause *c = dereference_klause (cadical_kitten, reason); - for (all_literals_in_klause (other, c)) { - const unsigned other_idx = other / 2; - if (other_idx == idx) - continue; - if (marks[other_idx]) - continue; - marks[other_idx] = true; - PUSH_STACK (cadical_kitten->analyzed, other_idx); - LOG ("analyzing final literal %u", other ^ 1); - } - } - } - */ - - for (all_stack (unsigned, idx, cadical_kitten->analyzed)) - CADICAL_assert (marks[idx]), marks[idx] = 0; - CLEAR_STACK (cadical_kitten->analyzed); - - RELEASE_STACK (work); - - const size_t resolved = SIZE_STACK (cadical_kitten->resolved); - CADICAL_assert (resolved); - - if (resolved == 1) { - cadical_kitten->failing = PEEK_STACK (cadical_kitten->resolved, 0); - ROG (cadical_kitten->failing, "reusing as core"); - } else { - cadical_kitten->failing = cadical_new_learned_klause (cadical_kitten); - ROG (cadical_kitten->failing, "new core"); - } - - CLEAR_STACK (cadical_kitten->resolved); - CLEAR_STACK (cadical_kitten->klause); -} - -static void flush_trail (cadical_kitten *cadical_kitten) { - unsigneds *trail = &cadical_kitten->trail; - LOG ("flushing %zu root-level literals from trail", SIZE_STACK (*trail)); - CADICAL_assert (!cadical_kitten->level); - cadical_kitten->propagated = 0; - CLEAR_STACK (*trail); -} - -static int decide (cadical_kitten *cadical_kitten) { - if (!cadical_kitten->level && !EMPTY_STACK (cadical_kitten->trail)) - flush_trail (cadical_kitten); - - const value *const values = cadical_kitten->values; - unsigned decision = INVALID; - const size_t assumptions = SIZE_STACK (cadical_kitten->assumptions); - while (cadical_kitten->level < assumptions) { - unsigned assumption = PEEK_STACK (cadical_kitten->assumptions, cadical_kitten->level); - value value = values[assumption]; - if (value < 0) { - LOG ("found failing assumption %u", assumption); - failing (cadical_kitten); - return 20; - } else if (value > 0) { - - cadical_kitten->level++; - LOG ("pseudo decision level %u for already satisfied assumption %u", - cadical_kitten->level, assumption); - } else { - decision = assumption; - LOG ("using assumption %u as decision", decision); - break; - } - } - - if (!cadical_kitten->unassigned) - return 10; - - if (KITTEN_TICKS >= cadical_kitten->limits.ticks) { - LOG ("ticks limit %" PRIu64 " hit after %" PRIu64 " ticks", - cadical_kitten->limits.ticks, KITTEN_TICKS); - return -1; - } - - if (cadical_kitten->terminator && cadical_kitten->terminator (cadical_kitten->terminator_data)) { - LOG ("terminator requested termination"); - return -1; - } - - if (decision == INVALID) { - unsigned idx = cadical_kitten->queue.search; - const kink *const links = cadical_kitten->links; - for (;;) { - CADICAL_assert (idx != INVALID); - if (!values[2 * idx]) - break; - idx = links[idx].prev; - } - update_search (cadical_kitten, idx); - const unsigned phase = cadical_kitten->phases[idx]; - decision = 2 * idx + phase; - LOG ("decision %u variable %u phase %u", decision, idx, phase); - } - INC (cadical_kitten_decisions); - cadical_kitten->level++; - assign (cadical_kitten, decision, INVALID); - return 0; -} - -static void inconsistent (cadical_kitten *cadical_kitten, unsigned ref) { - CADICAL_assert (ref != INVALID); - CADICAL_assert (cadical_kitten->inconsistent == INVALID); - - if (!cadical_kitten->antecedents) { - cadical_kitten->inconsistent = ref; - ROG (ref, "registering inconsistent virtually empty"); - return; - } - - unsigneds *analyzed = &cadical_kitten->analyzed; - unsigneds *resolved = &cadical_kitten->resolved; - - CADICAL_assert (EMPTY_STACK (*analyzed)); - CADICAL_assert (EMPTY_STACK (*resolved)); - - value *marks = cadical_kitten->marks; - const kar *const vars = cadical_kitten->vars; - unsigned next = 0; - - for (;;) { - CADICAL_assert (ref != INVALID); - klause *c = dereference_klause (cadical_kitten, ref); - CADICAL_assert (c); - ROG (ref, "analyzing inconsistent"); - PUSH_STACK (*resolved, ref); - for (all_literals_in_klause (lit, c)) { - const unsigned idx = lit / 2; - CADICAL_assert (!vars[idx].level); - if (marks[idx]) - continue; - CADICAL_assert (cadical_kitten->values[lit] < 0); - LOG ("analyzed %u", lit); - marks[idx] = true; - PUSH_STACK (cadical_kitten->analyzed, idx); - } - if (next == SIZE_STACK (cadical_kitten->analyzed)) - break; - const unsigned idx = PEEK_STACK (cadical_kitten->analyzed, next); - next++; - const kar *const v = vars + idx; - CADICAL_assert (!v->level); - ref = v->reason; - } - CADICAL_assert (EMPTY_STACK (cadical_kitten->klause)); - ref = cadical_new_learned_klause (cadical_kitten); - ROG (ref, "registering final inconsistent empty"); - cadical_kitten->inconsistent = ref; - - for (all_stack (unsigned, idx, *analyzed)) - marks[idx] = 0; - - CLEAR_STACK (*analyzed); - CLEAR_STACK (*resolved); -} - -static int propagate_units (cadical_kitten *cadical_kitten) { - if (cadical_kitten->inconsistent != INVALID) - return 20; - - if (EMPTY_STACK (cadical_kitten->units)) { - LOG ("no root level unit clauses"); - return 0; - } - - LOG ("propagating %zu root level unit clauses", - SIZE_STACK (cadical_kitten->units)); - - const value *const values = cadical_kitten->values; - - for (size_t next = 0; next < SIZE_STACK (cadical_kitten->units); next++) { - const unsigned ref = PEEK_STACK (cadical_kitten->units, next); - CADICAL_assert (ref != INVALID); - klause *c = dereference_klause (cadical_kitten, ref); - CADICAL_assert (c->size == 1); - ROG (ref, "propagating unit"); - const unsigned unit = c->lits[0]; - const value value = values[unit]; - if (value > 0) - continue; - if (value < 0) { - inconsistent (cadical_kitten, ref); - return 20; - } - assign (cadical_kitten, unit, ref); - } - const unsigned conflict = propagate (cadical_kitten); - if (conflict == INVALID) - return 0; - inconsistent (cadical_kitten, conflict); - return 20; -} - -/*------------------------------------------------------------------------*/ - -static klause *begin_klauses (cadical_kitten *cadical_kitten) { - return (klause *) BEGIN_STACK (cadical_kitten->klauses); -} - -static klause *end_original_klauses (cadical_kitten *cadical_kitten) { - return (klause *) (BEGIN_STACK (cadical_kitten->klauses) + - cadical_kitten->end_original_ref); -} - -static klause *end_klauses (cadical_kitten *cadical_kitten) { - return (klause *) END_STACK (cadical_kitten->klauses); -} - -static klause *next_klause (cadical_kitten *cadical_kitten, klause *c) { - CADICAL_assert (begin_klauses (cadical_kitten) <= c); - CADICAL_assert (c < end_klauses (cadical_kitten)); - unsigned *res = c->lits + c->size; - if (cadical_kitten->antecedents && is_learned_klause (c)) - res += c->aux; - return (klause *) res; -} - -/*------------------------------------------------------------------------*/ - -static void reset_core (cadical_kitten *cadical_kitten) { - LOG ("resetting core clauses"); - size_t reset = 0; - for (all_klauses (c)) - if (is_core_klause (c)) - unset_core_klause (c), reset++; - LOG ("reset %zu core clauses", reset); - CLEAR_STACK (cadical_kitten->core); -} - -static void reset_assumptions (cadical_kitten *cadical_kitten) { - LOG ("reset %zu assumptions", SIZE_STACK (cadical_kitten->assumptions)); - while (!EMPTY_STACK (cadical_kitten->assumptions)) { - const unsigned assumption = POP_STACK (cadical_kitten->assumptions); - cadical_kitten->failed[assumption] = false; - } -#ifndef CADICAL_NDEBUG - for (size_t i = 0; i < cadical_kitten->size; i++) - CADICAL_assert (!cadical_kitten->failed[i]); -#endif - CLEAR_STACK (cadical_kitten->assumptions); - if (cadical_kitten->failing != INVALID) { - ROG (cadical_kitten->failing, "reset failed assumption reason"); - cadical_kitten->failing = INVALID; - } -} - -static void reset_incremental (cadical_kitten *cadical_kitten) { - // if (cadical_kitten->level) - cadical_completely_backtrack_to_root_level (cadical_kitten); - if (!EMPTY_STACK (cadical_kitten->assumptions)) - reset_assumptions (cadical_kitten); - else - CADICAL_assert (cadical_kitten->failing == INVALID); - if (cadical_kitten->status == 21) - reset_core (cadical_kitten); - UPDATE_STATUS (0); -} - -/*------------------------------------------------------------------------*/ - -static bool flip_literal (cadical_kitten *cadical_kitten, unsigned lit) { - INC (cadical_kitten_flip); - signed char *values = cadical_kitten->values; - if (values[lit] < 0) - lit ^= 1; - LOG ("trying to flip value of satisfied literal %u", lit); - CADICAL_assert (values[lit] > 0); - katches *watches = cadical_kitten->watches + lit; - unsigned *q = BEGIN_STACK (*watches); - const unsigned *const end_watches = END_STACK (*watches); - unsigned const *p = q; - uint64_t ticks = (((char *) end_watches - (char *) q) >> 7) + 1; - bool res = true; - while (p != end_watches) { - const unsigned ref = *q++ = *p++; - klause *c = dereference_klause (cadical_kitten, ref); - unsigned *lits = c->lits; - const unsigned other = lits[0] ^ lits[1] ^ lit; - const value other_value = values[other]; - ticks++; - if (other_value > 0) - continue; - value replacement_value = -1; - unsigned replacement = INVALID; - const unsigned *const end_lits = lits + c->size; - unsigned *r; - for (r = lits + 2; r != end_lits; r++) { - replacement = *r; - CADICAL_assert (replacement != lit); - replacement_value = values[replacement]; - CADICAL_assert (replacement_value); - if (replacement_value > 0) - break; - } - if (replacement_value > 0) { - CADICAL_assert (replacement != INVALID); - ROG (ref, "unwatching %u in", lit); - lits[0] = other; - lits[1] = replacement; - *r = lit; - watch_klause (cadical_kitten, replacement, ref); - q--; - } else { - CADICAL_assert (replacement_value < 0); - ROG (ref, "single satisfied"); - res = false; - break; - } - } - while (p != end_watches) - *q++ = *p++; - SET_END_OF_STACK (*watches, q); - ADD (cadical_kitten_ticks, ticks); - if (res) { - LOG ("flipping value of %u", lit); - values[lit] = -1; - const unsigned not_lit = lit ^ 1; - values[not_lit] = 1; - INC (cadical_kitten_flipped); - } else - LOG ("failed to flip value of %u", lit); - return res; -} - -/*------------------------------------------------------------------------*/ - -// this cadical specific clause addition avoids copying clauses multiple -// times just to convert literals to unsigned representation. -// -static unsigned int2u (int lit) { - CADICAL_assert (lit != 0); - int idx = abs (lit) - 1; - return (lit < 0) + 2u * (unsigned) idx; -} - -void cadical_kitten_assume (cadical_kitten *cadical_kitten, unsigned elit) { - REQUIRE_INITIALIZED (); - if (cadical_kitten->status) - reset_incremental (cadical_kitten); - const unsigned ilit = import_literal (cadical_kitten, elit); - LOG ("registering assumption %u", ilit); - PUSH_STACK (cadical_kitten->assumptions, ilit); -} - -void cadical_kitten_assume_signed (cadical_kitten *cadical_kitten, int elit) { - unsigned kelit = int2u (elit); - cadical_kitten_assume (cadical_kitten, kelit); -} - -void cadical_kitten_clause_with_id_and_exception (cadical_kitten *cadical_kitten, unsigned id, - size_t size, - const unsigned *elits, - unsigned except) { - REQUIRE_INITIALIZED (); - if (cadical_kitten->status) - reset_incremental (cadical_kitten); - CADICAL_assert (EMPTY_STACK (cadical_kitten->klause)); - const unsigned *const end = elits + size; - for (const unsigned *p = elits; p != end; p++) { - const unsigned elit = *p; - if (elit == except) - continue; - const unsigned ilit = import_literal (cadical_kitten, elit); - CADICAL_assert (ilit < cadical_kitten->lits); - const unsigned iidx = ilit / 2; - if (cadical_kitten->marks[iidx]) - INVALID_API_USAGE ("variable '%u' of literal '%u' occurs twice", - elit / 2, elit); - cadical_kitten->marks[iidx] = true; - PUSH_STACK (cadical_kitten->klause, ilit); - } - for (unsigned *p = cadical_kitten->klause.begin; p != cadical_kitten->klause.end; p++) - cadical_kitten->marks[*p / 2] = false; - new_original_klause (cadical_kitten, id); - CLEAR_STACK (cadical_kitten->klause); -} - -void citten_clause_with_id_and_exception (cadical_kitten *cadical_kitten, unsigned id, - size_t size, const int *elits, - unsigned except) { - REQUIRE_INITIALIZED (); - if (cadical_kitten->status) - reset_incremental (cadical_kitten); - CADICAL_assert (EMPTY_STACK (cadical_kitten->klause)); - const int *const end = elits + size; - for (const int *p = elits; p != end; p++) { - const unsigned elit = int2u (*p); // this is the conversion - if (elit == except) - continue; - const unsigned ilit = import_literal (cadical_kitten, elit); - CADICAL_assert (ilit < cadical_kitten->lits); - const unsigned iidx = ilit / 2; - if (cadical_kitten->marks[iidx]) - INVALID_API_USAGE ("variable '%u' of literal '%u' occurs twice", - elit / 2, elit); - cadical_kitten->marks[iidx] = true; - PUSH_STACK (cadical_kitten->klause, ilit); - } - for (unsigned *p = cadical_kitten->klause.begin; p != cadical_kitten->klause.end; p++) - cadical_kitten->marks[*p / 2] = false; - new_original_klause (cadical_kitten, id); - CLEAR_STACK (cadical_kitten->klause); -} - -void citten_clause_with_id_and_equivalence (cadical_kitten *cadical_kitten, unsigned id, - size_t size, const int *elits, - unsigned lit, unsigned other) { - REQUIRE_INITIALIZED (); - if (cadical_kitten->status) - reset_incremental (cadical_kitten); - CADICAL_assert (EMPTY_STACK (cadical_kitten->klause)); - bool sat = false; - const int *const end = elits + size; - for (const int *p = elits; p != end; p++) { - const unsigned elit = int2u (*p); // this is the conversion - if (elit == (lit ^ 1u) || elit == (other ^ 1u)) - continue; - if (elit == lit || elit == other) { - sat = true; - break; - } - const unsigned ilit = import_literal (cadical_kitten, elit); - CADICAL_assert (ilit < cadical_kitten->lits); - const unsigned iidx = ilit / 2; - if (cadical_kitten->marks[iidx]) - INVALID_API_USAGE ("variable '%u' of literal '%u' occurs twice", - elit / 2, elit); - cadical_kitten->marks[iidx] = true; - PUSH_STACK (cadical_kitten->klause, ilit); - } - for (unsigned *p = cadical_kitten->klause.begin; p != cadical_kitten->klause.end; p++) - cadical_kitten->marks[*p / 2] = false; - if (!sat) - new_original_klause (cadical_kitten, id); - CLEAR_STACK (cadical_kitten->klause); -} - -void cadical_kitten_clause (cadical_kitten *cadical_kitten, size_t size, unsigned *elits) { - cadical_kitten_clause_with_id_and_exception (cadical_kitten, INVALID, size, elits, - INVALID); -} - -void citten_clause_with_id (cadical_kitten *cadical_kitten, unsigned id, size_t size, - int *elits) { - citten_clause_with_id_and_exception (cadical_kitten, id, size, elits, INVALID); -} - -void cadical_kitten_unit (cadical_kitten *cadical_kitten, unsigned lit) { - cadical_kitten_clause (cadical_kitten, 1, &lit); -} - -void cadical_kitten_binary (cadical_kitten *cadical_kitten, unsigned a, unsigned b) { - unsigned clause[2] = {a, b}; - cadical_kitten_clause (cadical_kitten, 2, clause); -} - -int cadical_kitten_solve (cadical_kitten *cadical_kitten) { - REQUIRE_INITIALIZED (); - if (cadical_kitten->status) - reset_incremental (cadical_kitten); - else // if (cadical_kitten->level) - cadical_completely_backtrack_to_root_level (cadical_kitten); - - LOG ("starting solving under %zu assumptions", - SIZE_STACK (cadical_kitten->assumptions)); - - INC (cadical_kitten_solved); - - int res = propagate_units (cadical_kitten); - while (!res) { - const unsigned conflict = propagate (cadical_kitten); - if (cadical_kitten->terminator && - cadical_kitten->terminator (cadical_kitten->terminator_data)) { - LOG ("terminator requested termination"); - res = -1; - break; - } - if (conflict != INVALID) { - if (cadical_kitten->level) - analyze (cadical_kitten, conflict); - else { - inconsistent (cadical_kitten, conflict); - res = 20; - } - } else - res = decide (cadical_kitten); - } - - if (res < 0) - res = 0; - - if (!res && !EMPTY_STACK (cadical_kitten->assumptions)) - reset_assumptions (cadical_kitten); - - UPDATE_STATUS (res); - - if (res == 10) - INC (cadical_kitten_sat); - else if (res == 20) - INC (cadical_kitten_unsat); - else - INC (cadical_kitten_unknown); - - LOG ("finished solving with result %d", res); - - return res; -} - -int cadical_kitten_status (cadical_kitten *cadical_kitten) { return cadical_kitten->status; } - -unsigned cadical_kitten_compute_clausal_core (cadical_kitten *cadical_kitten, - uint64_t *learned_ptr) { - REQUIRE_STATUS (20); - - if (!cadical_kitten->antecedents) - INVALID_API_USAGE ("antecedents not tracked"); - - LOG ("computing clausal core"); - - unsigneds *resolved = &cadical_kitten->resolved; - CADICAL_assert (EMPTY_STACK (*resolved)); - - unsigned original = 0; - uint64_t learned = 0; - - unsigned reason_ref = cadical_kitten->inconsistent; - - if (reason_ref == INVALID) { - CADICAL_assert (!EMPTY_STACK (cadical_kitten->assumptions)); - reason_ref = cadical_kitten->failing; - if (reason_ref == INVALID) { - LOG ("assumptions mutually inconsistent"); - //goto DONE; - if (learned_ptr) - *learned_ptr = learned; - - LOG ("clausal core of %u original clauses", original); - LOG ("clausal core of %" PRIu64 " learned clauses", learned); - cadical_kitten->statistics.original = original; - cadical_kitten->statistics.learned = 0; - UPDATE_STATUS (21); - - return original; - } - } - - PUSH_STACK (*resolved, reason_ref); - unsigneds *core = &cadical_kitten->core; - CADICAL_assert (EMPTY_STACK (*core)); - - while (!EMPTY_STACK (*resolved)) { - const unsigned c_ref = POP_STACK (*resolved); - if (c_ref == INVALID) { - const unsigned d_ref = POP_STACK (*resolved); - ROG (d_ref, "core[%zu]", SIZE_STACK (*core)); - PUSH_STACK (*core, d_ref); - klause *d = dereference_klause (cadical_kitten, d_ref); - CADICAL_assert (!is_core_klause (d)); - set_core_klause (d); - if (is_learned_klause (d)) - learned++; - else - original++; - } else { - klause *c = dereference_klause (cadical_kitten, c_ref); - if (is_core_klause (c)) - continue; - PUSH_STACK (*resolved, c_ref); - PUSH_STACK (*resolved, INVALID); - ROG (c_ref, "analyzing antecedent core"); - if (!is_learned_klause (c)) - continue; - for (all_antecedents (d_ref, c)) { - klause *d = dereference_klause (cadical_kitten, d_ref); - if (!is_core_klause (d)) - PUSH_STACK (*resolved, d_ref); - } - } - } - - //DONE: - - if (learned_ptr) - *learned_ptr = learned; - - LOG ("clausal core of %u original clauses", original); - LOG ("clausal core of %" PRIu64 " learned clauses", learned); - cadical_kitten->statistics.original = original; - cadical_kitten->statistics.learned = 0; - UPDATE_STATUS (21); - - return original; -} - -void cadical_kitten_traverse_core_ids (cadical_kitten *cadical_kitten, void *state, - void (*traverse) (void *, unsigned)) { - REQUIRE_STATUS (21); - - LOG ("traversing core of original clauses"); - - unsigned traversed = 0; - - for (all_original_klauses (c)) { - // only happens for 'true' incremental calls, i.e. if add happens after - // solve - if (is_learned_klause (c)) - continue; - if (!is_core_klause (c)) - continue; - ROG (reference_klause (cadical_kitten, c), "traversing"); - traverse (state, c->aux); - traversed++; - } - - LOG ("traversed %u original core clauses", traversed); - (void) traversed; - - CADICAL_assert (cadical_kitten->status == 21); -} - -void cadical_kitten_traverse_core_clauses (cadical_kitten *cadical_kitten, void *state, - void (*traverse) (void *, bool, size_t, - const unsigned *)) { - REQUIRE_STATUS (21); - - LOG ("traversing clausal core"); - - unsigned traversed = 0; - - for (all_stack (unsigned, c_ref, cadical_kitten->core)) { - klause *c = dereference_klause (cadical_kitten, c_ref); - CADICAL_assert (is_core_klause (c)); - const bool learned = is_learned_klause (c); - unsigneds *eclause = &cadical_kitten->eclause; - CADICAL_assert (EMPTY_STACK (*eclause)); - for (all_literals_in_klause (ilit, c)) { - const unsigned elit = export_literal (cadical_kitten, ilit); - PUSH_STACK (*eclause, elit); - } - const size_t size = SIZE_STACK (*eclause); - const unsigned *elits = eclause->begin; - ROG (reference_klause (cadical_kitten, c), "traversing"); - traverse (state, learned, size, elits); - CLEAR_STACK (*eclause); - traversed++; - } - - LOG ("traversed %u core clauses", traversed); - (void) traversed; - - CADICAL_assert (cadical_kitten->status == 21); -} - -void cadical_kitten_traverse_core_clauses_with_id ( - cadical_kitten *cadical_kitten, void *state, - void (*traverse) (void *state, unsigned, bool learned, size_t, - const unsigned *)) { - REQUIRE_STATUS (21); - - LOG ("traversing clausal core"); - - unsigned traversed = 0; - - for (all_stack (unsigned, c_ref, cadical_kitten->core)) { - klause *c = dereference_klause (cadical_kitten, c_ref); - CADICAL_assert (is_core_klause (c)); - const bool learned = is_learned_klause (c); - unsigneds *eclause = &cadical_kitten->eclause; - CADICAL_assert (EMPTY_STACK (*eclause)); - for (all_literals_in_klause (ilit, c)) { - const unsigned elit = export_literal (cadical_kitten, ilit); - PUSH_STACK (*eclause, elit); - } - const size_t size = SIZE_STACK (*eclause); - const unsigned *elits = eclause->begin; - ROG (reference_klause (cadical_kitten, c), "traversing"); - unsigned ctag = learned ? 0 : c->aux; - traverse (state, ctag, learned, size, elits); - CLEAR_STACK (*eclause); - traversed++; - } - - LOG ("traversed %u core clauses", traversed); - (void) traversed; - - CADICAL_assert (cadical_kitten->status == 21); -} - -void cadical_kitten_trace_core (cadical_kitten *cadical_kitten, void *state, - void (*trace) (void *, unsigned, unsigned, bool, - size_t, const unsigned *, size_t, - const unsigned *)) { - REQUIRE_STATUS (21); - - LOG ("tracing clausal core"); - - unsigned traced = 0; - - for (all_stack (unsigned, c_ref, cadical_kitten->core)) { - klause *c = dereference_klause (cadical_kitten, c_ref); - CADICAL_assert (is_core_klause (c)); - const bool learned = is_learned_klause (c); - unsigneds *eclause = &cadical_kitten->eclause; - CADICAL_assert (EMPTY_STACK (*eclause)); - for (all_literals_in_klause (ilit, c)) { - const unsigned elit = export_literal (cadical_kitten, ilit); - PUSH_STACK (*eclause, elit); - } - const size_t size = SIZE_STACK (*eclause); - const unsigned *elits = eclause->begin; - - unsigneds *resolved = &cadical_kitten->resolved; - CADICAL_assert (EMPTY_STACK (*resolved)); - if (learned) { - for (all_antecedents (ref, c)) { - PUSH_STACK (*resolved, ref); - } - } - const size_t rsize = SIZE_STACK (*resolved); - const unsigned *rids = resolved->begin; - - unsigned cid = reference_klause (cadical_kitten, c); - unsigned ctag = learned ? 0 : c->aux; - ROG (cid, "tracing"); - trace (state, cid, ctag, learned, size, elits, rsize, rids); - CLEAR_STACK (*eclause); - CLEAR_STACK (*resolved); - traced++; - } - - LOG ("traced %u core clauses", traced); - (void) traced; - - CADICAL_assert (cadical_kitten->status == 21); -} - -void cadical_kitten_shrink_to_clausal_core (cadical_kitten *cadical_kitten) { - REQUIRE_STATUS (21); - - LOG ("shrinking formula to core of original clauses"); - - CLEAR_STACK (cadical_kitten->trail); - - cadical_kitten->unassigned = cadical_kitten->lits / 2; - cadical_kitten->propagated = 0; - cadical_kitten->level = 0; - - update_search (cadical_kitten, cadical_kitten->queue.last); - - memset (cadical_kitten->values, 0, cadical_kitten->lits); - - for (all_kits (lit)) - CLEAR_STACK (KATCHES (lit)); - - CADICAL_assert (cadical_kitten->inconsistent != INVALID); - klause *inconsistent = dereference_klause (cadical_kitten, cadical_kitten->inconsistent); - if (is_learned_klause (inconsistent) || inconsistent->size) { - ROG (cadical_kitten->inconsistent, "resetting inconsistent"); - cadical_kitten->inconsistent = INVALID; - } else - ROG (cadical_kitten->inconsistent, "keeping inconsistent"); - - CLEAR_STACK (cadical_kitten->units); - - klause *begin = begin_klauses (cadical_kitten), *q = begin; - klause const *const end = end_original_klauses (cadical_kitten); -#ifdef LOGGING - unsigned original = 0; -#endif - for (klause *c = begin, *next; c != end; c = next) { - next = next_klause (cadical_kitten, c); - // CADICAL_assert (!is_learned_klause (c)); not necessarily true - if (is_learned_klause (c)) - continue; - if (!is_core_klause (c)) - continue; - unset_core_klause (c); - const unsigned dst = (unsigned *) q - (unsigned *) begin; - const unsigned size = c->size; - if (!size) { - if (cadical_kitten->inconsistent != INVALID) - cadical_kitten->inconsistent = dst; - } else if (size == 1) { - PUSH_STACK (cadical_kitten->units, dst); - ROG (dst, "keeping"); - } else { - watch_klause (cadical_kitten, c->lits[0], dst); - watch_klause (cadical_kitten, c->lits[1], dst); - } - if (c == q) - q = next; - else { - const size_t bytes = (char *) next - (char *) c; - memmove (q, c, bytes); - q = (klause *) ((char *) q + bytes); - } -#ifdef LOGGING - original++; -#endif - } - SET_END_OF_STACK (cadical_kitten->klauses, (unsigned *) q); - cadical_kitten->end_original_ref = SIZE_STACK (cadical_kitten->klauses); - LOG ("end of original clauses at %zu", cadical_kitten->end_original_ref); - LOG ("%u original clauses left", original); - - CLEAR_STACK (cadical_kitten->core); - - UPDATE_STATUS (0); -} - -signed char cadical_kitten_signed_value (cadical_kitten *cadical_kitten, int selit) { - REQUIRE_STATUS (10); - const unsigned elit = int2u (selit); - const unsigned eidx = elit / 2; - if (eidx >= cadical_kitten->evars) - return 0; - unsigned iidx = cadical_kitten->import[eidx]; - if (!iidx) - return 0; - const unsigned ilit = 2 * (iidx - 1) + (elit & 1); - return cadical_kitten->values[ilit]; -} - -signed char cadical_kitten_value (cadical_kitten *cadical_kitten, unsigned elit) { - REQUIRE_STATUS (10); - const unsigned eidx = elit / 2; - if (eidx >= cadical_kitten->evars) - return 0; - unsigned iidx = cadical_kitten->import[eidx]; - if (!iidx) - return 0; - const unsigned ilit = 2 * (iidx - 1) + (elit & 1); - return cadical_kitten->values[ilit]; -} - -signed char cadical_kitten_fixed (cadical_kitten *cadical_kitten, unsigned elit) { - const unsigned eidx = elit / 2; - if (eidx >= cadical_kitten->evars) - return 0; - unsigned iidx = cadical_kitten->import[eidx]; - if (!iidx) - return 0; - iidx--; - const unsigned ilit = 2 * iidx + (elit & 1); - signed char res = cadical_kitten->values[ilit]; - if (!res) - return 0; - kar *v = cadical_kitten->vars + iidx; - if (v->level) - return 0; - return res; -} - -signed char cadical_kitten_fixed_signed (cadical_kitten *cadical_kitten, int elit) { - unsigned kelit = int2u (elit); - return cadical_kitten_fixed (cadical_kitten, kelit); -} - -bool cadical_kitten_flip_literal (cadical_kitten *cadical_kitten, unsigned elit) { - REQUIRE_STATUS (10); - const unsigned eidx = elit / 2; - if (eidx >= cadical_kitten->evars) - return false; - unsigned iidx = cadical_kitten->import[eidx]; - if (!iidx) - return false; - const unsigned ilit = 2 * (iidx - 1) + (elit & 1); - if (cadical_kitten_fixed (cadical_kitten, elit)) - return false; - return flip_literal (cadical_kitten, ilit); -} - -bool cadical_kitten_flip_signed_literal (cadical_kitten *cadical_kitten, int elit) { - REQUIRE_STATUS (10); - unsigned kelit = int2u (elit); - return cadical_kitten_flip_literal (cadical_kitten, kelit); -} - -bool cadical_kitten_failed (cadical_kitten *cadical_kitten, unsigned elit) { - REQUIRE_STATUS (20); - const unsigned eidx = elit / 2; - if (eidx >= cadical_kitten->evars) - return false; - unsigned iidx = cadical_kitten->import[eidx]; - if (!iidx) - return false; - const unsigned ilit = 2 * (iidx - 1) + (elit & 1); - return cadical_kitten->failed[ilit]; -} - -// checks both watches for clauses with only one literal positively -// assigned. if such a clause is found, return false. Otherwise fix watch -// invariant and return true -static bool prime_propagate (cadical_kitten *cadical_kitten, const unsigned idx, - void *state, const bool ignoring, - bool (*ignore) (void *, unsigned)) { - unsigned lit = 2 * idx; - unsigned conflict = INVALID; - value *values = cadical_kitten->values; - for (int i = 0; i < 2; i++) { - if (conflict != INVALID) - break; - lit = lit ^ i; - const unsigned not_lit = lit ^ 1; - katches *watches = cadical_kitten->watches + not_lit; - unsigned *q = BEGIN_STACK (*watches); - const unsigned *const end_watches = END_STACK (*watches); - unsigned const *p = q; - uint64_t ticks = (((char *) end_watches - (char *) q) >> 7) + 1; - while (p != end_watches) { - const unsigned ref = *q++ = *p++; - klause *c = dereference_klause (cadical_kitten, ref); - if (is_learned_klause (c) || ignore (state, c->aux) == ignoring) - continue; - CADICAL_assert (c->size > 1); - unsigned *lits = c->lits; - const unsigned other = lits[0] ^ lits[1] ^ not_lit; - const value other_value = values[other]; - ticks++; - if (other_value > 0) - continue; - value replacement_value = -1; - unsigned replacement = INVALID; - const unsigned *const end_lits = lits + c->size; - unsigned *r; - for (r = lits + 2; r != end_lits; r++) { - replacement = *r; - replacement_value = values[replacement]; - if (replacement_value > 0) - break; - } - if (replacement_value > 0) { - CADICAL_assert (replacement != INVALID); - ROG (ref, "unwatching %u in", not_lit); - lits[0] = other; - lits[1] = replacement; - *r = not_lit; - watch_klause (cadical_kitten, replacement, ref); - q--; - } else { - ROG (ref, "idx %u forced prime by", idx); - conflict = ref; - break; - } - } - while (p != end_watches) - *q++ = *p++; - SET_END_OF_STACK (*watches, q); - ADD (cadical_kitten_ticks, ticks); - } - return conflict == INVALID; -} - -void cadical_kitten_add_prime_implicant (cadical_kitten *cadical_kitten, void *state, int side, - void (*add_implicant) (void *, int, size_t, - const unsigned *)) { - REQUIRE_STATUS (11); - // might be possible in some edge cases - unsigneds *prime = &cadical_kitten->prime[side]; - unsigneds *prime2 = &cadical_kitten->prime[!side]; - CADICAL_assert (!EMPTY_STACK (*prime) || !EMPTY_STACK (*prime2)); - CLEAR_STACK (*prime2); - - for (all_stack (unsigned, lit, *prime)) { - const unsigned not_lit = lit ^ 1; - const unsigned elit = export_literal (cadical_kitten, not_lit); - PUSH_STACK (*prime2, elit); - } - - // adds a clause which will reset cadical_kitten status and backtrack - add_implicant (state, side, SIZE_STACK (*prime2), BEGIN_STACK (*prime2)); - CLEAR_STACK (*prime); - CLEAR_STACK (*prime2); -} - -// computes two prime implicants, only considering clauses based on ignore -// return -1 if no prime implicant has been computed, otherwise returns -// index of shorter implicant. -// TODO does not work if flip has been called beforehand -int cadical_kitten_compute_prime_implicant (cadical_kitten *cadical_kitten, void *state, - bool (*ignore) (void *, unsigned)) { - REQUIRE_STATUS (10); - - value *values = cadical_kitten->values; - kar *vars = cadical_kitten->vars; - unsigneds unassigned; - INIT_STACK (unassigned); - bool limit_hit = 0; - CADICAL_assert (EMPTY_STACK (cadical_kitten->prime[0]) && EMPTY_STACK (cadical_kitten->prime[1])); - for (int i = 0; i < 2; i++) { - const bool ignoring = i; - for (all_stack (unsigned, lit, cadical_kitten->trail)) { - if (KITTEN_TICKS >= cadical_kitten->limits.ticks) { - LOG ("ticks limit %" PRIu64 " hit after %" PRIu64 " ticks", - cadical_kitten->limits.ticks, KITTEN_TICKS); - limit_hit = 1; - break; - } - CADICAL_assert (values[lit] > 0); - const unsigned idx = lit / 2; - const unsigned ref = vars[idx].reason; - CADICAL_assert (vars[idx].level); - klause *c = 0; - if (ref != INVALID) - c = dereference_klause (cadical_kitten, ref); - if (ref == INVALID || is_learned_klause (c) || - ignore (state, c->aux) == ignoring) { - LOG ("non-prime candidate var %d", idx); - if (prime_propagate (cadical_kitten, idx, state, ignoring, ignore)) { - values[lit] = 0; - values[lit ^ 1] = 0; - PUSH_STACK (unassigned, lit); - } else - CADICAL_assert (values[lit] > 0); - } - } - unsigneds *prime = &cadical_kitten->prime[i]; - // push on prime implicant stack. - for (all_kits (lit)) { - if (values[lit] > 0) - PUSH_STACK (*prime, lit); - } - // reassign all literals on - for (all_stack (unsigned, lit, unassigned)) { - CADICAL_assert (!values[lit]); - values[lit] = 1; - values[lit ^ 1] = -1; - } - CLEAR_STACK (unassigned); - } - RELEASE_STACK (unassigned); - - if (limit_hit) { - CLEAR_STACK (cadical_kitten->prime[0]); - CLEAR_STACK (cadical_kitten->prime[1]); - return -1; - } - // the only case when one of the prime implicants is allowed to be empty - // is if ignore returns always true or always false. - CADICAL_assert (!EMPTY_STACK (cadical_kitten->prime[0]) || - !EMPTY_STACK (cadical_kitten->prime[1])); - UPDATE_STATUS (11); - - int res = SIZE_STACK (cadical_kitten->prime[0]) > SIZE_STACK (cadical_kitten->prime[1]); - return res; -} - -static bool contains_blit (cadical_kitten *cadical_kitten, klause *c, const unsigned blit) { - for (all_literals_in_klause (lit, c)) { - if (lit == blit) - return true; - } - return false; -} - -static bool prime_propagate_blit (cadical_kitten *cadical_kitten, const unsigned idx, - const unsigned blit) { - unsigned lit = 2 * idx; - unsigned conflict = INVALID; - value *values = cadical_kitten->values; - LOG ("prime propagating idx %u for blit %u", idx, blit); - for (int i = 0; i < 2; i++) { - if (conflict != INVALID) - break; - lit = lit ^ i; - if (lit == blit) - continue; - const unsigned not_lit = lit ^ 1; - katches *watches = cadical_kitten->watches + not_lit; - unsigned *q = BEGIN_STACK (*watches); - const unsigned *const end_watches = END_STACK (*watches); - unsigned const *p = q; - uint64_t ticks = (((char *) end_watches - (char *) q) >> 7) + 1; - while (p != end_watches) { - const unsigned ref = *q++ = *p++; - klause *c = dereference_klause (cadical_kitten, ref); - if (is_learned_klause (c)) - continue; - ROG (ref, "checking with blit %u", blit); - CADICAL_assert (c->size > 1); - unsigned *lits = c->lits; - const unsigned other = lits[0] ^ lits[1] ^ not_lit; - const value other_value = values[other]; - ticks++; - bool use = other == blit || not_lit == blit; - if (other_value > 0) - continue; - value replacement_value = -1; - unsigned replacement = INVALID; - const unsigned *const end_lits = lits + c->size; - unsigned *r; - for (r = lits + 2; r != end_lits; r++) { - replacement = *r; - replacement_value = values[replacement]; - use = use || replacement == blit; - if (replacement_value > 0) - break; - } - if (replacement_value > 0) { - CADICAL_assert (replacement != INVALID); - ROG (ref, "unwatching %u in", not_lit); - lits[0] = other; - lits[1] = replacement; - *r = not_lit; - watch_klause (cadical_kitten, replacement, ref); - q--; - } else if (!use) { - continue; - } else { - ROG (ref, "idx %u forced prime by", idx); - conflict = ref; - break; - } - } - while (p != end_watches) - *q++ = *p++; - SET_END_OF_STACK (*watches, q); - ADD (cadical_kitten_ticks, ticks); - } - return conflict == INVALID; -} - -static int compute_prime_implicant_for (cadical_kitten *cadical_kitten, unsigned blit) { - value *values = cadical_kitten->values; - kar *vars = cadical_kitten->vars; - unsigneds unassigned; - INIT_STACK (unassigned); - bool limit_hit = false; - CADICAL_assert (EMPTY_STACK (cadical_kitten->prime[0]) && EMPTY_STACK (cadical_kitten->prime[1])); - for (int i = 0; i < 2; i++) { - const unsigned block = blit ^ i; - const bool ignoring = i; - if (prime_propagate_blit (cadical_kitten, block / 2, block)) { - value tmp = values[blit]; - CADICAL_assert (tmp); - values[blit] = 0; - values[blit ^ 1] = 0; - PUSH_STACK (unassigned, tmp > 0 ? blit : blit ^ 1); - PUSH_STACK (cadical_kitten->prime[i], block); // will be negated! - } else - CADICAL_assert (false); - for (all_stack (unsigned, lit, cadical_kitten->trail)) { - if (KITTEN_TICKS >= cadical_kitten->limits.ticks) { - LOG ("ticks limit %" PRIu64 " hit after %" PRIu64 " ticks", - cadical_kitten->limits.ticks, KITTEN_TICKS); - limit_hit = true; - break; - } - if (!values[lit]) - continue; - CADICAL_assert (values[lit]); // not true when flipping is involved - const unsigned idx = lit / 2; - const unsigned ref = vars[idx].reason; - CADICAL_assert (vars[idx].level); - LOG ("non-prime candidate var %d", idx); - if (prime_propagate_blit (cadical_kitten, idx, block)) { - value tmp = values[lit]; - CADICAL_assert (tmp); - values[lit] = 0; - values[lit ^ 1] = 0; - PUSH_STACK (unassigned, tmp > 0 ? lit : lit ^ 1); - } - } - unsigneds *prime = &cadical_kitten->prime[i]; - // push on prime implicant stack. - for (all_kits (lit)) { - if (values[lit] > 0) - PUSH_STACK (*prime, lit); - } - // reassign all literals on - for (all_stack (unsigned, lit, unassigned)) { - CADICAL_assert (!values[lit]); - values[lit] = 1; - values[lit ^ 1] = -1; - } - CLEAR_STACK (unassigned); - } - RELEASE_STACK (unassigned); - - if (limit_hit) { - CLEAR_STACK (cadical_kitten->prime[0]); - CLEAR_STACK (cadical_kitten->prime[1]); - return -1; - } - // the only case when one of the prime implicants is allowed to be empty - // is if ignore returns always true or always false. - CADICAL_assert (!EMPTY_STACK (cadical_kitten->prime[0]) || - !EMPTY_STACK (cadical_kitten->prime[1])); - LOGLITS (BEGIN_STACK (cadical_kitten->prime[0]), SIZE_STACK (cadical_kitten->prime[0]), - "first implicant %u", blit); - LOGLITS (BEGIN_STACK (cadical_kitten->prime[1]), SIZE_STACK (cadical_kitten->prime[1]), - "second implicant %u", blit ^ 1); - UPDATE_STATUS (11); - - int res = SIZE_STACK (cadical_kitten->prime[0]) > SIZE_STACK (cadical_kitten->prime[1]); - return res; -} - -int cadical_kitten_flip_and_implicant_for_signed_literal (cadical_kitten *cadical_kitten, - int elit) { - REQUIRE_STATUS (10); - unsigned kelit = int2u (elit); - if (!cadical_kitten_flip_literal (cadical_kitten, kelit)) { - return -2; - } - const unsigned eidx = kelit / 2; - unsigned iidx = cadical_kitten->import[eidx]; - CADICAL_assert (iidx); - const unsigned ilit = 2 * (iidx - 1) + (kelit & 1); - return compute_prime_implicant_for (cadical_kitten, ilit); -} - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_lidruptracer.cpp b/src/sat/cadical/cadical_lidruptracer.cpp deleted file mode 100644 index db07e36e6..000000000 --- a/src/sat/cadical/cadical_lidruptracer.cpp +++ /dev/null @@ -1,662 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -/*------------------------------------------------------------------------*/ - -LidrupTracer::LidrupTracer (Internal *i, File *f, bool b) - : internal (i), file (f), binary (b), num_clauses (0), size_clauses (0), - clauses (0), last_hash (0), last_id (0), last_clause (0) -#ifndef CADICAL_QUIET - , - added (0), deleted (0) -#endif -{ - (void) internal; - - // Initialize random number table for hash function. - // - Random random (42); - for (unsigned n = 0; n < num_nonces; n++) { - uint64_t nonce = random.next (); - if (!(nonce & 1)) - nonce++; - CADICAL_assert (nonce), CADICAL_assert (nonce & 1); - nonces[n] = nonce; - } -#ifndef CADICAL_NDEBUG - binary = b; -#else - (void) b; -#endif - piping = file->piping (); -} - -void LidrupTracer::connect_internal (Internal *i) { - internal = i; - file->connect_internal (internal); - LOG ("LIDRUP TRACER connected to internal"); -} - -LidrupTracer::~LidrupTracer () { - LOG ("LIDRUP TRACER delete"); - delete file; - for (size_t i = 0; i < size_clauses; i++) - for (LidrupClause *c = clauses[i], *next; c; c = next) - next = c->next, delete_clause (c); - delete[] clauses; -} - -/*------------------------------------------------------------------------*/ - -void LidrupTracer::enlarge_clauses () { - CADICAL_assert (num_clauses == size_clauses); - const uint64_t new_size_clauses = size_clauses ? 2 * size_clauses : 1; - LOG ("LIDRUP Tracer enlarging clauses of tracer from %" PRIu64 - " to %" PRIu64, - (uint64_t) size_clauses, (uint64_t) new_size_clauses); - LidrupClause **new_clauses; - new_clauses = new LidrupClause *[new_size_clauses]; - clear_n (new_clauses, new_size_clauses); - for (uint64_t i = 0; i < size_clauses; i++) { - for (LidrupClause *c = clauses[i], *next; c; c = next) { - next = c->next; - const uint64_t h = reduce_hash (c->hash, new_size_clauses); - c->next = new_clauses[h]; - new_clauses[h] = c; - } - } - delete[] clauses; - clauses = new_clauses; - size_clauses = new_size_clauses; -} - -LidrupClause *LidrupTracer::new_clause () { - LidrupClause *res = new LidrupClause; - res->next = 0; - res->hash = last_hash; - res->id = last_id; - for (const auto &id : imported_chain) { - res->chain.push_back (id); - } - for (const auto &lit : imported_clause) { - res->literals.push_back (lit); - } - last_clause = res; - num_clauses++; - return res; -} - -void LidrupTracer::delete_clause (LidrupClause *c) { - CADICAL_assert (c); - num_clauses--; - delete c; -} - -uint64_t LidrupTracer::reduce_hash (uint64_t hash, uint64_t size) { - CADICAL_assert (size > 0); - unsigned shift = 32; - uint64_t res = hash; - while ((((uint64_t) 1) << shift) > size) { - res ^= res >> shift; - shift >>= 1; - } - res &= size - 1; - CADICAL_assert (res < size); - return res; -} - -uint64_t LidrupTracer::compute_hash (const int64_t id) { - CADICAL_assert (id > 0); - unsigned j = id % num_nonces; - uint64_t tmp = nonces[j] * (uint64_t) id; - return last_hash = tmp; -} - -bool LidrupTracer::find_and_delete (const int64_t id) { - if (!num_clauses) - return false; - LidrupClause **res = 0, *c; - const uint64_t hash = compute_hash (id); - const uint64_t h = reduce_hash (hash, size_clauses); - for (res = clauses + h; (c = *res); res = &c->next) { - if (c->hash == hash && c->id == id) { - break; - } - if (!c->next) - return false; - } - if (!c) - return false; - CADICAL_assert (c && res); - *res = c->next; - for (auto &lit : c->literals) { - imported_clause.push_back (lit); - } - for (auto &cid : c->chain) { - imported_chain.push_back (cid); - } - delete_clause (c); - return true; -} - -void LidrupTracer::insert () { - if (num_clauses == size_clauses) - enlarge_clauses (); - const uint64_t h = reduce_hash (compute_hash (last_id), size_clauses); - LidrupClause *c = new_clause (); - c->next = clauses[h]; - clauses[h] = c; -} - -/*------------------------------------------------------------------------*/ - -inline void LidrupTracer::flush_if_piping () { - if (piping) - file->flush (); -} - -inline void LidrupTracer::put_binary_zero () { - CADICAL_assert (binary); - CADICAL_assert (file); - file->put ((unsigned char) 0); -} - -inline void LidrupTracer::put_binary_lit (int lit) { - CADICAL_assert (binary); - CADICAL_assert (file); - CADICAL_assert (lit != INT_MIN); - unsigned x = 2 * abs (lit) + (lit < 0); - unsigned char ch; - while (x & ~0x7f) { - ch = (x & 0x7f) | 0x80; - file->put (ch); - x >>= 7; - } - ch = x; - file->put (ch); -} - -inline void LidrupTracer::put_binary_id (int64_t id, bool can_be_negative) { - CADICAL_assert (binary); - CADICAL_assert (file); - uint64_t x = abs (id); - if (can_be_negative) { - x = 2 * x + (id < 0); - } - unsigned char ch; - while (x & ~0x7f) { - ch = (x & 0x7f) | 0x80; - file->put (ch); - x >>= 7; - } - ch = x; - file->put (ch); -} - -/*------------------------------------------------------------------------*/ - -void LidrupTracer::lidrup_add_restored_clause (int64_t id) { - if (!batch_weaken.empty () || !batch_delete.empty ()) - lidrup_batch_weaken_restore_and_delete (); - batch_restore.push_back (id); -} - -void LidrupTracer::lidrup_add_derived_clause ( - int64_t id, const vector &clause, const vector &chain) { - lidrup_batch_weaken_restore_and_delete (); - if (binary) { - file->put ('l'); - put_binary_id (id); - } else { - file->put ("l "); - file->put (id); - file->put (' '); - } - for (const auto &external_lit : clause) - if (binary) - put_binary_lit (external_lit); - else - file->put (external_lit), file->put (' '); - if (binary) - put_binary_zero (); - else - file->put ("0 "); - for (const auto &cid : chain) - if (binary) - put_binary_id (cid); - else - file->put (cid), file->put (' '); - if (binary) - put_binary_zero (); - else - file->put ("0\n"); -} - -void LidrupTracer::lidrup_add_original_clause (int64_t id, - const vector &clause) { - lidrup_batch_weaken_restore_and_delete (); - if (binary) { - file->put ('i'); - put_binary_id (id); - } else { - file->put ("i "); - file->put (id); - file->put (' '); - } - for (const auto &external_lit : clause) - if (binary) - put_binary_lit (external_lit); - else - file->put (external_lit), file->put (' '); - if (binary) - put_binary_zero (); - else - file->put ("0\n"); -} - -void LidrupTracer::lidrup_batch_weaken_restore_and_delete () { - CADICAL_assert (batch_weaken.empty () || batch_delete.empty ()); - if (!batch_weaken.empty ()) { - if (binary) { - file->put ('w'); - } else { - file->put ("w "); - } - for (const auto &id : batch_weaken) { - if (binary) - put_binary_id (id); - else - file->put (id), file->put (' '); - } - batch_weaken.clear (); - if (binary) - put_binary_zero (); - else - file->put ("0\n"); -#ifndef CADICAL_QUIET - batched++; -#endif - } - if (!batch_delete.empty ()) { - if (binary) { - file->put ('d'); - } else { - file->put ("d "); - } - for (const auto &id : batch_delete) { - if (binary) - put_binary_id (id); - else - file->put (id), file->put (' '); - } - batch_delete.clear (); - if (binary) - put_binary_zero (); - else - file->put ("0\n"); -#ifndef CADICAL_QUIET - batched++; -#endif - } - if (!batch_restore.empty ()) { - if (binary) { - file->put ('r'); - } else { - file->put ("r "); - } - for (const auto &id : batch_restore) { - if (binary) - put_binary_id (id); - else - file->put (id), file->put (' '); - } - batch_restore.clear (); - if (binary) - put_binary_zero (); - else - file->put ("0\n"); -#ifndef CADICAL_QUIET - batched++; -#endif - } -} - -void LidrupTracer::lidrup_conclude_and_delete ( - const vector &conclusion) { - lidrup_batch_weaken_restore_and_delete (); - int64_t size = conclusion.size (); - if (size > 1) { - if (binary) { - file->put ('U'); - put_binary_id (size); - } else { - file->put ("U "); - file->put (size), file->put ("\n"); - } - } - for (auto &id : conclusion) { - if (binary) - file->put ('u'); - else - file->put ("u "); - if (!find_and_delete (id)) { - CADICAL_assert (imported_clause.empty ()); - CADICAL_assert (conclusion.size () == 1); - if (binary) { - put_binary_zero (); - put_binary_id (id); - put_binary_zero (); - } else { - file->put ("0 "); - file->put (id); - file->put (" 0\n"); - } - } else { - for (const auto &external_lit : imported_clause) { - // flip sign... - const auto not_elit = -external_lit; - if (binary) - put_binary_lit (not_elit); - else - file->put (not_elit), file->put (' '); - } - if (binary) - put_binary_zero (); - else - file->put ("0 "); - for (const auto &cid : imported_chain) { - if (binary) - put_binary_id (cid); - else - file->put (cid), file->put (' '); - } - if (binary) - put_binary_zero (); - else - file->put ("0\n"); - imported_clause.clear (); - imported_chain.clear (); - } - } - flush_if_piping (); -} - -void LidrupTracer::lidrup_report_status (int status) { - lidrup_batch_weaken_restore_and_delete (); - if (binary) - file->put ('s'); - else - file->put ("s "); - if (status == SATISFIABLE) - file->put ("SATISFIABLE"); - else if (status == UNSATISFIABLE) - file->put ("UNSATISFIABLE"); - else - file->put ("UNKNOWN"); - if (!binary) - file->put ("\n"); - flush_if_piping (); -} - -void LidrupTracer::lidrup_conclude_sat (const vector &model) { - lidrup_batch_weaken_restore_and_delete (); - if (binary) - file->put ('m'); - else - file->put ("m "); - for (auto &lit : model) { - if (binary) - put_binary_lit (lit); - else - file->put (lit), file->put (' '); - } - if (binary) - put_binary_zero (); - else - file->put ("0\n"); - flush_if_piping (); -} - -void LidrupTracer::lidrup_conclude_unknown (const vector &trail) { - lidrup_batch_weaken_restore_and_delete (); - if (binary) - file->put ('e'); - else - file->put ("e "); - for (auto &lit : trail) { - if (binary) - put_binary_lit (lit); - else - file->put (lit), file->put (' '); - } - if (binary) - put_binary_zero (); - else - file->put ("0\n"); - flush_if_piping (); -} - -void LidrupTracer::lidrup_solve_query () { - lidrup_batch_weaken_restore_and_delete (); - if (binary) - file->put ('q'); - else - file->put ("q "); - for (auto &lit : assumptions) { - if (binary) - put_binary_lit (lit); - else - file->put (lit), file->put (' '); - } - if (binary) - put_binary_zero (); - else - file->put ("0\n"); - flush_if_piping (); -} - -/*------------------------------------------------------------------------*/ - -void LidrupTracer::add_derived_clause (int64_t id, bool, - const vector &clause, - const vector &chain) { - if (file->closed ()) - return; - CADICAL_assert (imported_clause.empty ()); - LOG (clause, "LIDRUP TRACER tracing addition of derived clause"); - lidrup_add_derived_clause (id, clause, chain); -#ifndef CADICAL_QUIET - added++; -#endif -} - -void LidrupTracer::add_assumption_clause (int64_t id, - const vector &clause, - const vector &chain) { - if (file->closed ()) - return; - CADICAL_assert (imported_clause.empty ()); - LOG (clause, - "LIDRUP TRACER tracing addition of assumption clause[%" PRId64 "]", - id); - for (auto &lit : clause) - imported_clause.push_back (lit); - for (auto &cid : chain) - imported_chain.push_back (cid); - last_id = id; - insert (); - imported_clause.clear (); - imported_chain.clear (); -} - -void LidrupTracer::delete_clause (int64_t id, bool, const vector &) { - if (file->closed ()) - return; - CADICAL_assert (imported_clause.empty ()); - LOG ("LIDRUP TRACER tracing deletion of clause[%" PRId64 "]", id); - if (find_and_delete (id)) { - CADICAL_assert (imported_clause.empty ()); - if (!batch_delete.empty () || !batch_restore.empty ()) - lidrup_batch_weaken_restore_and_delete (); - batch_weaken.push_back (id); -#ifndef CADICAL_QUIET - weakened++; -#endif - } else { - if (!batch_weaken.empty () || !batch_restore.empty ()) - lidrup_batch_weaken_restore_and_delete (); - batch_delete.push_back (id); -#ifndef CADICAL_QUIET - deleted++; -#endif - } -} - -void LidrupTracer::weaken_minus (int64_t id, const vector &) { - if (file->closed ()) - return; - CADICAL_assert (imported_clause.empty ()); - LOG ("LIDRUP TRACER tracing weaken minus of clause[%" PRId64 "]", id); - last_id = id; - insert (); -} - -void LidrupTracer::conclude_unsat (ConclusionType, - const vector &conclusion) { - if (file->closed ()) - return; - CADICAL_assert (imported_clause.empty ()); - LOG (conclusion, "LIDRUP TRACER tracing conclusion of clause(s)"); - lidrup_conclude_and_delete (conclusion); -} - -void LidrupTracer::add_original_clause (int64_t id, bool, - const vector &clause, - bool restored) { - if (file->closed ()) - return; - if (!restored) { - LOG (clause, "LIDRUP TRACER tracing addition of original clause"); -#ifndef CADICAL_QUIET - original++; -#endif - return lidrup_add_original_clause (id, clause); - } - CADICAL_assert (restored); - if (find_and_delete (id)) { - LOG (clause, - "LIDRUP TRACER the clause was not yet weakened, so no restore"); - return; - } - LOG (clause, "LIDRUP TRACER tracing addition of restored clause"); - lidrup_add_restored_clause (id); -#ifndef CADICAL_QUIET - restore++; -#endif -} - -void LidrupTracer::report_status (int status, int64_t) { - if (file->closed ()) - return; - LOG ("LIDRUP TRACER tracing report of status %d", status); - lidrup_report_status (status); -} - -void LidrupTracer::conclude_sat (const vector &model) { - if (file->closed ()) - return; - LOG (model, "LIDRUP TRACER tracing conclusion of model"); - lidrup_conclude_sat (model); -} - -void LidrupTracer::conclude_unknown (const vector &entrailed) { - if (file->closed ()) - return; - LOG (entrailed, "LIDRUP TRACER tracing conclusion of UNK"); - lidrup_conclude_unknown (entrailed); -} - -void LidrupTracer::solve_query () { - if (file->closed ()) - return; - LOG (assumptions, "LIDRUP TRACER tracing solve query with assumptions"); - lidrup_solve_query (); -#ifndef CADICAL_QUIET - solved++; -#endif -} - -void LidrupTracer::add_assumption (int lit) { - LOG ("LIDRUP TRACER tracing addition of assumption %d", lit); - assumptions.push_back (lit); -} - -void LidrupTracer::reset_assumptions () { - LOG (assumptions, "LIDRUP TRACER tracing reset of assumptions"); - assumptions.clear (); -} - -/*------------------------------------------------------------------------*/ - -bool LidrupTracer::closed () { return file->closed (); } - -#ifndef CADICAL_QUIET - -void LidrupTracer::print_statistics () { - // TODO complete this. - uint64_t bytes = file->bytes (); - uint64_t total = added + deleted + weakened + restore + original; - MSG ("LIDRUP %" PRId64 " original clauses %.2f%%", original, - percent (original, total)); - MSG ("LIDRUP %" PRId64 " learned clauses %.2f%%", added, - percent (added, total)); - MSG ("LIDRUP %" PRId64 " deleted clauses %.2f%%", deleted, - percent (deleted, total)); - MSG ("LIDRUP %" PRId64 " weakened clauses %.2f%%", weakened, - percent (weakened, total)); - MSG ("LIDRUP %" PRId64 " restored clauses %.2f%%", restore, - percent (restore, total)); - MSG ("LIDRUP %" PRId64 " batches of deletions, weaken and restores %.2f", - batched, relative (batched, deleted + restore + weakened)); - MSG ("LIDRUP %" PRId64 " queries %.2f", solved, relative (solved, total)); - MSG ("LIDRUP %" PRId64 " bytes (%.2f MB)", bytes, - bytes / (double) (1 << 20)); -} - -#endif - -void LidrupTracer::close (bool print) { - CADICAL_assert (!closed ()); - file->close (); -#ifndef CADICAL_QUIET - if (print) { - MSG ("LIDRUP proof file '%s' closed", file->name ()); - print_statistics (); - } -#else - (void) print; -#endif -} - -void LidrupTracer::flush (bool print) { - CADICAL_assert (!closed ()); - lidrup_batch_weaken_restore_and_delete (); - file->flush (); -#ifndef CADICAL_QUIET - if (print) { - MSG ("LIDRUP proof file '%s' flushed", file->name ()); - print_statistics (); - } -#else - (void) print; -#endif -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_limit.cpp b/src/sat/cadical/cadical_limit.cpp deleted file mode 100644 index 69417a473..000000000 --- a/src/sat/cadical/cadical_limit.cpp +++ /dev/null @@ -1,135 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -Limit::Limit () { memset (this, 0, sizeof *this); } - -/*------------------------------------------------------------------------*/ - -double Internal::scale (double v) const { - const double ratio = clause_variable_ratio (); - const double factor = (ratio <= 2) ? 1.0 : log (ratio) / log (2); - double res = factor * v; - if (res < 1) - res = 1; - return res; -} - -/*------------------------------------------------------------------------*/ - -Last::Last () { memset (this, 0, sizeof *this); } - -/*------------------------------------------------------------------------*/ - -Inc::Inc () { - memset (this, 0, sizeof *this); - decisions = conflicts = -1; // unlimited -} - -void Internal::limit_terminate (int l) { - if (l <= 0 && !lim.terminate.forced) { - LOG ("keeping unbounded terminate limit"); - } else if (l <= 0) { - LOG ("reset terminate limit to be unbounded"); - lim.terminate.forced = 0; - } else { - lim.terminate.forced = l; - LOG ("new terminate limit of %d calls", l); - } -} - -void Internal::limit_conflicts (int l) { - if (l < 0 && inc.conflicts < 0) { - LOG ("keeping unbounded conflict limit"); - } else if (l < 0) { - LOG ("reset conflict limit to be unbounded"); - inc.conflicts = -1; - } else { - inc.conflicts = l; - LOG ("new conflict limit of %d conflicts", l); - } -} - -void Internal::limit_decisions (int l) { - if (l < 0 && inc.decisions < 0) { - LOG ("keeping unbounded decision limit"); - } else if (l < 0) { - LOG ("reset decision limit to be unbounded"); - inc.decisions = -1; - } else { - inc.decisions = l; - LOG ("new decision limit of %d decisions", l); - } -} - -void Internal::limit_preprocessing (int l) { - if (l < 0) { - LOG ("ignoring invalid preprocessing limit %d", l); - } else if (!l) { - LOG ("reset preprocessing limit to no preprocessing"); - inc.preprocessing = 0; - } else { - inc.preprocessing = l; - LOG ("new preprocessing limit of %d preprocessing rounds", l); - } -} - -void Internal::limit_local_search (int l) { - if (l < 0) { - LOG ("ignoring invalid local search limit %d", l); - } else if (!l) { - LOG ("reset local search limit to no local search"); - inc.localsearch = 0; - } else { - inc.localsearch = l; - LOG ("new local search limit of %d local search rounds", l); - } -} - -bool Internal::is_valid_limit (const char *name) { - if (!strcmp (name, "terminate")) - return true; - if (!strcmp (name, "conflicts")) - return true; - if (!strcmp (name, "decisions")) - return true; - if (!strcmp (name, "preprocessing")) - return true; - if (!strcmp (name, "localsearch")) - return true; - return false; -} - -bool Internal::limit (const char *name, int l) { - bool res = true; - if (!strcmp (name, "terminate")) - limit_terminate (l); - else if (!strcmp (name, "conflicts")) - limit_conflicts (l); - else if (!strcmp (name, "decisions")) - limit_decisions (l); - else if (!strcmp (name, "preprocessing")) - limit_preprocessing (l); - else if (!strcmp (name, "localsearch")) - limit_local_search (l); - else - res = false; - return res; -} - -void Internal::reset_limits () { - LOG ("reset limits"); - limit_terminate (0); - limit_conflicts (-1); - limit_decisions (-1); - limit_preprocessing (0); - limit_local_search (0); -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_logging.cpp b/src/sat/cadical/cadical_logging.cpp deleted file mode 100644 index 589bf097e..000000000 --- a/src/sat/cadical/cadical_logging.cpp +++ /dev/null @@ -1,221 +0,0 @@ -#include "global.h" - -#ifdef LOGGING - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -void Logger::print_log_prefix (Internal *internal) { - internal->print_prefix (); - tout.magenta (); - fputs ("LOG ", stdout); - tout.magenta (true); - printf ("%d ", internal->level); - tout.normal (); -} - -void Logger::log_empty_line (Internal *internal) { - internal->print_prefix (); - tout.magenta (); - const int len = internal->prefix.size (), max = 78 - len; - for (int i = 0; i < max; i++) - fputc ('-', stdout); - fputc ('\n', stdout); - tout.normal (); - fflush (stdout); -} - -void Logger::log (Internal *internal, const char *fmt, ...) { - print_log_prefix (internal); - tout.magenta (); - va_list ap; - va_start (ap, fmt); - vprintf (fmt, ap); - va_end (ap); - fputc ('\n', stdout); - tout.normal (); - fflush (stdout); -} - -// It is hard to factor out the common part between the two clause loggers, -// since they are also used in slightly different contexts. Our attempt to -// do so were not more readable than the current version. See the header -// for an explanation of the difference between the following two functions. - -void Logger::log (Internal *internal, const Clause *c, const char *fmt, - ...) { - print_log_prefix (internal); - tout.magenta (); - va_list ap; - va_start (ap, fmt); - vprintf (fmt, ap); - va_end (ap); - if (c) { - if (c->redundant) - printf (" glue %d redundant", c->glue); - else - printf (" irredundant"); - printf (" size %d clause[%" PRId64 "]", c->size, c->id); - if (c->moved) - printf (" ... (moved)"); - else { - if (internal->opts.logsort) { - vector s; - for (const auto &lit : *c) - s.push_back (lit); - sort (s.begin (), s.end (), clause_lit_less_than ()); - for (const auto &lit : s) - printf (" %d", lit); - } else { - for (const auto &lit : *c) { - printf (" %s", loglit (internal, lit).c_str ()); - } - } - } - } else if (internal->level) - printf (" decision"); - else - printf (" unit"); - fputc ('\n', stdout); - tout.normal (); - fflush (stdout); -} - -void Logger::log (Internal *internal, const Gate *g, const char *fmt, ...) { - print_log_prefix (internal); - tout.magenta (); - va_list ap; - va_start (ap, fmt); - vprintf (fmt, ap); - va_end (ap); - if (g) { - printf ("%s%s%s gate[%" PRIu64 "] (arity: %ld) %s := %s", - g->degenerated_and_pos ? " deg+" : "", - g->degenerated_and_neg ? " deg-" : "", - g->garbage ? " garbage" : "", g->id, g->arity (), - loglit (internal, g->lhs).c_str (), - string_of_gate (g->tag).c_str ()); - for (const auto &lit : g->rhs) { - printf (" %s", loglit (internal, lit).c_str ()); - } - } else - printf (" null gate"); - fputc ('\n', stdout); - tout.normal (); - fflush (stdout); -} - -// Same as above, but for the global clause 'c' (which is not a reason). - -void Logger::log (Internal *internal, const vector &c, const char *fmt, - ...) { - print_log_prefix (internal); - tout.magenta (); - va_list ap; - va_start (ap, fmt); - vprintf (fmt, ap); - va_end (ap); - if (internal->opts.logsort) { - vector s; - for (const auto &lit : c) - s.push_back (lit); - sort (s.begin (), s.end (), clause_lit_less_than ()); - for (const auto &lit : s) - printf (" %d", lit); - } else { - for (const auto &lit : c) - printf (" %d", lit); - } - fputc ('\n', stdout); - tout.normal (); - fflush (stdout); -} - -// Now for 'restore_clause' to avoid copying (without logging). - -void Logger::log (Internal *internal, - const vector::const_iterator &begin, - const vector::const_iterator &end, const char *fmt, - ...) { - print_log_prefix (internal); - tout.magenta (); - va_list ap; - va_start (ap, fmt); - vprintf (fmt, ap); - va_end (ap); - if (internal->opts.logsort) { - vector s; - for (auto p = begin; p != end; p++) - s.push_back (*p); - sort (s.begin (), s.end (), clause_lit_less_than ()); - for (const auto &lit : s) - printf (" %d", lit); - } else { - for (auto p = begin; p != end; p++) - printf (" %d", *p); - } - fputc ('\n', stdout); - tout.normal (); - fflush (stdout); -} - -// for LRAT proof chains - -void Logger::log (Internal *internal, const vector &c, - const char *fmt, ...) { - print_log_prefix (internal); - tout.magenta (); - va_list ap; - va_start (ap, fmt); - vprintf (fmt, ap); - va_end (ap); - for (const auto &id : c) - printf (" %" PRId64, id); - fputc ('\n', stdout); - tout.normal (); - fflush (stdout); -} - -// for LRAT proof clauses - -void Logger::log (Internal *internal, const int *literals, - const unsigned size, const char *fmt, ...) { - print_log_prefix (internal); - tout.magenta (); - va_list ap; - va_start (ap, fmt); - vprintf (fmt, ap); - va_end (ap); - for (unsigned i = 0; i < size; i++) { - const int lit = literals[i]; - printf (" %d", lit); - } - fputc ('\n', stdout); - tout.normal (); - fflush (stdout); -} - -string Logger::loglit (Internal *internal, int lit) { - std::string v = std::to_string (lit); - if (lit && -internal->max_var <= lit && internal->max_var >= lit) { - const int va = internal->val (lit); - if (va) { - v = v + "@" + std::to_string (internal->var (lit).level); - if (!internal->var (lit).reason) - v = v + "+"; - } - if (va > 0) - v += "=1"; - else if (va < 0) - v += "=-1"; - } - return v; -} -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END - -#endif diff --git a/src/sat/cadical/cadical_lookahead.cpp b/src/sat/cadical/cadical_lookahead.cpp deleted file mode 100644 index de84858cc..000000000 --- a/src/sat/cadical/cadical_lookahead.cpp +++ /dev/null @@ -1,526 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -struct literal_occ { - int lit; - int count; - bool operator< (const literal_occ &locc) const { - return (count > locc.count) || (count == locc.count && lit < locc.lit); - } - literal_occ operator++ () { - ++count; - return *this; - } -}; - -std::vector Internal::lookahead_populate_locc () { - std::vector loccs ((std::size_t) max_var + 1); - for (std::size_t lit = 0; lit < loccs.size (); ++lit) { - loccs[lit].lit = lit; - } - for (const auto &c : clauses) - if (!c->redundant) - for (const auto &lit : *c) - if (active (lit)) - ++loccs[std::abs (lit)]; - std::sort (begin (loccs), end (loccs)); - std::vector locc_map; - locc_map.reserve (max_var); - for (const auto &locc : loccs) - locc_map.push_back (locc.lit); - return locc_map; -} - -int Internal::lookahead_locc (const std::vector &loccs) { - for (auto lit : loccs) - if (active (abs (lit)) && !assumed (lit) && !assumed (-lit) && - !val (lit)) - return lit; - return 0; -} - -// This calculates the literal that appears the most often reusing the -// available datastructures and iterating over the clause set. This is too -// slow to be called iteratively. A faster (but inexact) version is -// lookahead_populate_loc and lookahead_loc. -int Internal::most_occurring_literal () { - init_noccs (); - for (const auto &c : clauses) - if (!c->redundant) - for (const auto &lit : *c) - if (active (lit)) - noccs (lit)++; - int64_t max_noccs = 0; - int res = 0; - - if (unsat) - return INT_MIN; - - propagate (); - for (int idx = 1; idx <= max_var; idx++) { - if (!active (idx) || assumed (idx) || assumed (-idx) || val (idx)) - continue; - for (int sign = -1; sign <= 1; sign += 2) { - const int lit = sign * idx; - if (!active (lit)) - continue; - int64_t tmp = noccs (lit); - if (tmp <= max_noccs) - continue; - max_noccs = tmp; - res = lit; - } - } - MSG ("maximum occurrence %" PRId64 " of literal %d", max_noccs, res); - reset_noccs (); - return res; -} - -// We probe on literals first, which occur more often negated and thus we -// sort the 'probes' stack in such a way that literals which occur negated -// less frequently come first. Probes are taken from the back of the stack. - -struct probe_negated_noccs_rank { - Internal *internal; - probe_negated_noccs_rank (Internal *i) : internal (i) {} - typedef size_t Type; - Type operator() (int a) const { return internal->noccs (-a); } -}; - -// Follow the ideas in 'generate_probes' but flush non root probes and -// reorder remaining probes. - -void Internal::lookahead_flush_probes () { - - CADICAL_assert (!probes.empty ()); - - init_noccs (); - for (const auto &c : clauses) { - int a, b; - if (!is_binary_clause (c, a, b)) - continue; - noccs (a)++; - noccs (b)++; - } - - const auto eop = probes.end (); - auto j = probes.begin (); - for (auto i = j; i != eop; i++) { - int lit = *i; - if (!active (lit)) - continue; - const bool have_pos_bin_occs = noccs (lit) > 0; - const bool have_neg_bin_occs = noccs (-lit) > 0; - if (have_pos_bin_occs == have_neg_bin_occs) - continue; - if (have_pos_bin_occs) - lit = -lit; - CADICAL_assert (!noccs (lit)), CADICAL_assert (noccs (-lit) > 0); - if (propfixed (lit) >= stats.all.fixed) - continue; - MSG ("keeping probe %d negated occs %" PRId64 "", lit, noccs (-lit)); - *j++ = lit; - } - size_t remain = j - probes.begin (); -#ifndef CADICAL_QUIET - size_t flushed = probes.size () - remain; -#endif - probes.resize (remain); - - rsort (probes.begin (), probes.end (), probe_negated_noccs_rank (this)); - - reset_noccs (); - shrink_vector (probes); - - PHASE ("probe-round", stats.probingrounds, - "flushed %zd literals %.0f%% remaining %zd", flushed, - percent (flushed, remain + flushed), remain); -} - -void Internal::lookahead_generate_probes () { - - CADICAL_assert (probes.empty ()); - - // First determine all the literals which occur in binary clauses. It is - // way faster to go over the clauses once, instead of walking the watch - // lists for each literal. - // - init_noccs (); - for (const auto &c : clauses) { - int a, b; - if (!is_binary_clause (c, a, b)) - continue; - noccs (a)++; - noccs (b)++; - } - - for (int idx = 1; idx <= max_var; idx++) { - - // Then focus on roots of the binary implication graph, which are - // literals occurring negatively in a binary clause, but not positively. - // If neither 'idx' nor '-idx' is a root it makes less sense to probe - // this variable. - - // This argument requires that equivalent literal substitution through - // 'decompose' is performed, because otherwise there might be 'cyclic - // roots' which are not tried, i.e., -1 2 0, 1 -2 0, 1 2 3 0, 1 2 -3 0. - - const bool have_pos_bin_occs = noccs (idx) > 0; - const bool have_neg_bin_occs = noccs (-idx) > 0; - - // if (have_pos_bin_occs == have_neg_bin_occs) continue; - - if (have_pos_bin_occs) { - int probe = -idx; - - // See the discussion where 'propfixed' is used below. - // - if (propfixed (probe) >= stats.all.fixed) - continue; - - MSG ("scheduling probe %d negated occs %" PRId64 "", probe, - noccs (-probe)); - probes.push_back (probe); - } - - if (have_neg_bin_occs) { - int probe = idx; - - // See the discussion where 'propfixed' is used below. - // - if (propfixed (probe) >= stats.all.fixed) - continue; - - MSG ("scheduling probe %d negated occs %" PRId64 "", probe, - noccs (-probe)); - probes.push_back (probe); - } - } - - rsort (probes.begin (), probes.end (), probe_negated_noccs_rank (this)); - - reset_noccs (); - shrink_vector (probes); - - PHASE ("probe-round", stats.probingrounds, - "scheduled %zd literals %.0f%%", probes.size (), - percent (probes.size (), 2 * max_var)); -} - -int Internal::lookahead_next_probe () { - - int generated = 0; - - for (;;) { - - if (probes.empty ()) { - if (generated++) - return 0; - lookahead_generate_probes (); - } - - while (!probes.empty ()) { - - int probe = probes.back (); - probes.pop_back (); - - // Eliminated or assigned. - // - if (!active (probe) || assumed (probe) || assumed (-probe)) - continue; - - // There is now new unit since the last time we propagated this probe, - // thus we propagated it before without obtaining a conflict and - // nothing changed since then. Thus there is no need to propagate it - // again. This observation was independently made by Partik Simons - // et.al. in the context of implementing 'smodels' (see for instance - // Alg. 4 in his JAIR article from 2002) and it has also been - // contributed to the thesis work of Yacine Boufkhad. - // - if (propfixed (probe) >= stats.all.fixed) - continue; - - return probe; - } - } -} - -bool non_tautological_cube (std::vector cube) { - std::sort (begin (cube), end (cube), clause_lit_less_than ()); - - for (size_t i = 0, j = 1; j < cube.size (); ++i, ++j) - if (cube[i] == cube[j]) - return false; - else if (cube[i] == -cube[j]) - return false; - else if (cube[i] == 0) - return false; - - return true; -} - -bool Internal::terminating_asked () { - - if (external->terminator && external->terminator->terminate ()) { - MSG ("connected terminator forces termination"); - return true; - } - - if (termination_forced) { - MSG ("termination forced"); - return true; - } - return false; -} - -// We run probing on all literals with some differences: -// -// * no limit on the number of propagations. We rely on terminating to -// stop() -// * we run only one round -// -// The run can be expensive, so we actually first run the cheaper -// occurrence version and only then run lookahead. -// -int Internal::lookahead_probing () { - - if (!active ()) - return 0; - - MSG ("lookahead-probe-round %" PRId64 - " without propagations limit and %zu assumptions", - stats.probingrounds, assumptions.size ()); - - termination_forced = false; - -#ifndef CADICAL_QUIET - int old_failed = stats.failed; - int64_t old_probed = stats.probed; -#endif - int64_t old_hbrs = stats.hbrs; - - if (unsat) - return INT_MIN; - if (level) - backtrack (); - if (!propagate ()) { - MSG ("empty clause before probing"); - learn_empty_clause (); - return INT_MIN; - } - - if (terminating_asked ()) - return most_occurring_literal (); - - decompose (); - - if (ternary ()) // If we derived a binary clause - decompose (); // then start another round of ELS. - - // Remove duplicated binary clauses and perform in essence hyper unary - // resolution, i.e., derive the unit '2' from '1 2' and '-1 2'. - // - mark_duplicated_binary_clauses_as_garbage (); - - lim.conflicts = -1; - - if (!probes.empty ()) - lookahead_flush_probes (); - - // We reset 'propfixed' since there was at least another conflict thus - // a new learned clause, which might produce new propagations (and hyper - // binary resolvents). During 'generate_probes' we keep the old value. - // - for (int idx = 1; idx <= max_var; idx++) - propfixed (idx) = propfixed (-idx) = -1; - - CADICAL_assert (unsat || propagated == trail.size ()); - propagated = propagated2 = trail.size (); - - int probe; - int res = most_occurring_literal (); - int max_hbrs = -1; - - set_mode (PROBE); - - MSG ("unsat = %d, terminating_asked () = %d ", unsat, - terminating_asked ()); - init_probehbr_lrat (); - while (!unsat && !terminating_asked () && - (probe = lookahead_next_probe ())) { - stats.probed++; - int hbrs; - - probe_assign_decision (probe); - if (probe_propagate ()) - hbrs = trail.size (), backtrack (); - else - hbrs = 0, failed_literal (probe); - clean_probehbr_lrat (); - if (max_hbrs < hbrs || - (max_hbrs == hbrs && - internal->bumped (probe) > internal->bumped (res))) { - res = probe; - max_hbrs = hbrs; - } - } - - reset_mode (PROBE); - - if (unsat) { - MSG ("probing derived empty clause"); - res = INT_MIN; - } else if (propagated < trail.size ()) { - MSG ("probing produced %zd units", - (size_t) (trail.size () - propagated)); - if (!propagate ()) { - MSG ("propagating units after probing results in empty clause"); - learn_empty_clause (); - res = INT_MIN; - } else - sort_watches (); - } - -#ifndef CADICAL_QUIET - int failed = stats.failed - old_failed; - int64_t probed = stats.probed - old_probed; -#endif - int64_t hbrs = stats.hbrs - old_hbrs; - - MSG ("lookahead-probe-round %" PRId64 " probed %" PRId64 - " and found %d failed literals", - stats.probingrounds, probed, failed); - - if (hbrs) - PHASE ("lookahead-probe-round", stats.probingrounds, - "found %" PRId64 " hyper binary resolvents", hbrs); - - MSG ("lookahead literal %d with %d\n", res, max_hbrs); - - return res; -} - -CubesWithStatus Internal::generate_cubes (int depth, int min_depth) { - if (!active () || depth == 0) { - CubesWithStatus cubes; - cubes.status = 0; - cubes.cubes.push_back (std::vector ()); - return cubes; - } - - lookingahead = true; - START (lookahead); - MSG ("Generating cubes of depth %i", depth); - - // presimplify required due to assumptions - - termination_forced = false; - int res = already_solved (); - if (res == 0) - res = restore_clauses (); - if (unsat) - res = 10; - if (res != 0) - res = solve (true); - if (res != 0) { - MSG ("Solved during preprocessing"); - CubesWithStatus cubes; - cubes.status = res; - lookingahead = false; - STOP (lookahead); - return cubes; - } - - reset_limits (); - MSG ("generate cubes with %zu assumptions\n", assumptions.size ()); - - CADICAL_assert (ntab.empty ()); - std::vector current_assumptions{assumptions}; - std::vector> cubes{{assumptions}}; - auto loccs{lookahead_populate_locc ()}; - LOG ("loccs populated\n"); - CADICAL_assert (ntab.empty ()); - - for (int i = 0; i < depth; ++i) { - LOG ("Probing at depth %i, currently %zu have been generated", i, - cubes.size ()); - std::vector> cubes2{std::move (cubes)}; - cubes.clear (); - - for (size_t j = 0; j < cubes2.size (); ++j) { - CADICAL_assert (ntab.empty ()); - CADICAL_assert (!unsat); - reset_assumptions (); - for (auto lit : cubes2[j]) - assume (lit); - restore_clauses (); - propagate (); - // preprocess_round(0); //uncomment maybe - - if (unsat) { - LOG ("current cube is unsat; skipping"); - unsat = false; - continue; - } - - int res = terminating_asked () ? lookahead_locc (loccs) - : lookahead_probing (); - if (unsat) { - LOG ("current cube is unsat; skipping"); - unsat = false; - continue; - } - - if (res == 0) { - LOG ("no lit to split %i", res); - cubes.push_back (cubes2[j]); - continue; - } - - CADICAL_assert (res != 0); - LOG ("splitting on lit %i", res); - std::vector cube1{cubes2[j]}; - cube1.push_back (res); - std::vector cube2{std::move (cubes2[j])}; - cube2.push_back (-res); - cubes.push_back (cube1); - cubes.push_back (cube2); - } - - if (terminating_asked () && i >= min_depth) - break; - } - - CADICAL_assert (std::for_each ( - std::begin (cubes), std::end (cubes), - [] (std::vector cube) { return non_tautological_cube (cube); })); - reset_assumptions (); - - for (auto lit : current_assumptions) - assume (lit); - - STOP (lookahead); - lookingahead = false; - - if (unsat) { - LOG ("Solved during preprocessing"); - CubesWithStatus cubes; - cubes.status = 20; - return cubes; - } - - CubesWithStatus rcubes; - rcubes.status = 0; - rcubes.cubes = cubes; - - return rcubes; -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_lratchecker.cpp b/src/sat/cadical/cadical_lratchecker.cpp deleted file mode 100644 index 5f342a370..000000000 --- a/src/sat/cadical/cadical_lratchecker.cpp +++ /dev/null @@ -1,835 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -/*------------------------------------------------------------------------*/ - -inline unsigned LratChecker::l2u (int lit) { - CADICAL_assert (lit); - CADICAL_assert (lit != INT_MIN); - unsigned res = 2 * (abs (lit) - 1); - if (lit < 0) - res++; - return res; -} - -signed char &LratChecker::mark (int lit) { - const unsigned u = l2u (lit); - CADICAL_assert (u < marks.size ()); - return marks[u]; -} - -signed char &LratChecker::checked_lit (int lit) { - const unsigned u = l2u (lit); - CADICAL_assert (u < checked_lits.size ()); - return checked_lits[u]; -} - -/*------------------------------------------------------------------------*/ - -LratCheckerClause *LratChecker::new_clause () { - const size_t size = imported_clause.size (); - CADICAL_assert (size <= UINT_MAX); - const int off = size ? 1 : 0; - const size_t bytes = - sizeof (LratCheckerClause) + (size - off) * sizeof (int); - LratCheckerClause *res = (LratCheckerClause *) new char[bytes]; - res->garbage = false; - res->next = 0; - res->hash = last_hash; - res->id = last_id; - res->size = size; - res->used = false; - res->tautological = false; - int *literals = res->literals, *p = literals; -#ifndef CADICAL_NDEBUG - for (auto &b : checked_lits) - CADICAL_assert (!b); // = false; -#endif - for (const auto &lit : imported_clause) { - *p++ = lit; - checked_lit (-lit) = true; - if (checked_lit (lit)) { - LOG (imported_clause, "LRAT CHECKER clause tautological"); - res->tautological = true; - } - } - for (const auto &lit : imported_clause) - checked_lit (-lit) = false; - num_clauses++; - - return res; -} - -void LratChecker::delete_clause (LratCheckerClause *c) { - CADICAL_assert (c); - if (!c->garbage) { - CADICAL_assert (num_clauses); - num_clauses--; - } else { - CADICAL_assert (num_garbage); - num_garbage--; - } - delete[] (char *) c; -} - -void LratChecker::enlarge_clauses () { - CADICAL_assert (num_clauses == size_clauses); - const uint64_t new_size_clauses = size_clauses ? 2 * size_clauses : 1; - LOG ("LRAT CHECKER enlarging clauses of checker from %" PRIu64 - " to %" PRIu64, - (uint64_t) size_clauses, (uint64_t) new_size_clauses); - LratCheckerClause **new_clauses; - new_clauses = new LratCheckerClause *[new_size_clauses]; - clear_n (new_clauses, new_size_clauses); - for (uint64_t i = 0; i < size_clauses; i++) { - for (LratCheckerClause *c = clauses[i], *next; c; c = next) { - next = c->next; - const uint64_t h = reduce_hash (c->hash, new_size_clauses); - c->next = new_clauses[h]; - new_clauses[h] = c; - } - } - delete[] clauses; - clauses = new_clauses; - size_clauses = new_size_clauses; -} - -// Probably not necessary since we have no watches. -// -void LratChecker::collect_garbage_clauses () { - - stats.collections++; - - LOG ("LRAT CHECKER collecting %" PRIu64 " garbage clauses %.0f%%", - num_garbage, percent (num_garbage, num_clauses)); - - for (LratCheckerClause *c = garbage, *next; c; c = next) - next = c->next, delete_clause (c); - - CADICAL_assert (!num_garbage); - garbage = 0; -} - -/*------------------------------------------------------------------------*/ - -LratChecker::LratChecker (Internal *i) - : internal (i), size_vars (0), concluded (false), num_clauses (0), - num_finalized (0), num_garbage (0), size_clauses (0), clauses (0), - garbage (0), last_hash (0), last_id (0), current_id (0) { - - // Initialize random number table for hash function. - // - Random random (42); - for (unsigned n = 0; n < num_nonces; n++) { - uint64_t nonce = random.next (); - if (!(nonce & 1)) - nonce++; - CADICAL_assert (nonce), CADICAL_assert (nonce & 1); - nonces[n] = nonce; - } - - memset (&stats, 0, sizeof (stats)); // Initialize statistics. -} - -void LratChecker::connect_internal (Internal *i) { - internal = i; - LOG ("connected to internal"); -} - -LratChecker::~LratChecker () { - LOG ("LRAT CHECKER delete"); - for (size_t i = 0; i < size_clauses; i++) - for (LratCheckerClause *c = clauses[i], *next; c; c = next) - next = c->next, delete_clause (c); - for (LratCheckerClause *c = garbage, *next; c; c = next) - next = c->next, delete_clause (c); - delete[] clauses; -} - -/*------------------------------------------------------------------------*/ - -void LratChecker::enlarge_vars (int64_t idx) { - - CADICAL_assert (0 < idx), CADICAL_assert (idx <= INT_MAX); - - int64_t new_size_vars = size_vars ? 2 * size_vars : 2; - while (idx >= new_size_vars) - new_size_vars *= 2; - LOG ("LRAT CHECKER enlarging variables of checker from %" PRId64 - " to %" PRId64 "", - size_vars, new_size_vars); - - marks.resize (2 * new_size_vars); - checked_lits.resize (2 * new_size_vars); - - CADICAL_assert (idx < new_size_vars); - size_vars = new_size_vars; -} - -inline void LratChecker::import_literal (int lit) { - CADICAL_assert (lit); - CADICAL_assert (lit != INT_MIN); - int idx = abs (lit); - if (idx >= size_vars) - enlarge_vars (idx); - imported_clause.push_back (lit); -} - -void LratChecker::import_clause (const vector &c) { - for (const auto &lit : c) - import_literal (lit); -} - -/*------------------------------------------------------------------------*/ - -uint64_t LratChecker::reduce_hash (uint64_t hash, uint64_t size) { - CADICAL_assert (size > 0); - unsigned shift = 32; - uint64_t res = hash; - while ((((uint64_t) 1) << shift) > size) { - res ^= res >> shift; - shift >>= 1; - } - res &= size - 1; - CADICAL_assert (res < size); - return res; -} - -uint64_t LratChecker::compute_hash (const int64_t id) { - CADICAL_assert (id > 0); - unsigned j = id % num_nonces; - uint64_t tmp = nonces[j] * (uint64_t) id; - return last_hash = tmp; -} - -LratCheckerClause **LratChecker::find (const int64_t id) { - stats.searches++; - LratCheckerClause **res, *c; - const uint64_t hash = compute_hash (id); - const uint64_t h = reduce_hash (hash, size_clauses); - for (res = clauses + h; (c = *res); res = &c->next) { - if (c->hash == hash && c->id == id) { - break; - } - stats.collisions++; - } - return res; -} - -void LratChecker::insert () { - stats.insertions++; - if (num_clauses == size_clauses) - enlarge_clauses (); - const uint64_t h = reduce_hash (compute_hash (last_id), size_clauses); - LratCheckerClause *c = new_clause (); - c->next = clauses[h]; - clauses[h] = c; -} - -/*------------------------------------------------------------------------*/ - -// "strict" resolution check instead of rup check -bool LratChecker::check_resolution (vector proof_chain) { - if (proof_chain.empty ()) { - LOG ("LRAT CHECKER resolution check skipped clause is tautological"); - return true; - } - // LOG (imported_clause, "LRAT CHECKER checking clause with resolution"); -#ifndef CADICAL_NDEBUG - for (auto &b : checked_lits) - CADICAL_assert (!b); // = false; -#endif - if (!proof_chain.size () || proof_chain.back () < 0) - return false; - LratCheckerClause *c = *find (proof_chain.back ()); - CADICAL_assert (c); - for (int *i = c->literals; i < c->literals + c->size; i++) { - int lit = *i; - checked_lit (lit) = true; - CADICAL_assert (!checked_lit (-lit)); - } - for (auto p = proof_chain.end () - 2; p >= proof_chain.begin (); p--) { - auto &id = *p; - c = *find (id); - CADICAL_assert (c); // since this is checked in check already - for (int *i = c->literals; i < c->literals + c->size; i++) { - int lit = *i; - if (!checked_lit (-lit)) - checked_lit (lit) = true; - else - checked_lit (-lit) = false; - } - } - for (const auto &lit : imported_clause) { - if (checked_lit (-lit)) { - LOG ("LRAT CHECKER resolution failed, resolved literal %d in learned " - "clause", - lit); - for (auto &b : checked_lits) - b = false; // clearing checking bits - return false; - } - if (!checked_lit (lit)) { - // learned clause is subsumed by resolvents - checked_lit (lit) = true; - } - checked_lit (-lit) = true; - } - bool failed = false; - for (int64_t lit = 1; lit < size_vars; lit++) { - bool ok = checked_lit (lit) && checked_lit (-lit); - ok = ok || (!checked_lit (lit) && !checked_lit (-lit)); - checked_lit (lit) = checked_lit (-lit) = false; - if (!ok && !failed) { - LOG ("LRAT CHECKER resolution failed, learned clause does not match " - "on " - "variable %" PRId64, - lit); - failed = true; - } - } - - return !failed; -} - -/*------------------------------------------------------------------------*/ - -bool LratChecker::check (vector proof_chain) { - LOG (imported_clause, "LRAT CHECKER checking clause"); - stats.checks++; -#ifndef CADICAL_NDEBUG - for (auto &b : checked_lits) - CADICAL_assert (!b); // = false; -#endif - bool taut = false; - for (const auto &lit : imported_clause) { // tautological clauses - checked_lit (-lit) = true; - if (checked_lit (lit)) { - LOG (imported_clause, "LRAT CHECKER clause tautological"); - CADICAL_assert (!proof_chain.size ()); // would be unnecessary hence a bug - taut = true; - } - } - // we assume that we can have RUP and ER clauses. One side of the ER - // clauses are pure, i.e. without any chain, the long clause is blocked, - // so the chain consists only of negative ids. Therefore these checks are - // enough to distiguish between RUP and ER - if (taut || !proof_chain.size () || proof_chain.back () < 0) { - for (const auto &lit : imported_clause) { // tautological clauses - checked_lit (-lit) = false; - } - return taut; - } - - vector used_clauses; - bool checking = false; - for (auto &id : proof_chain) { - LratCheckerClause *c = *find (id); - if (!c) { - LOG ("LRAT CHECKER LRAT failed. Did not find clause with id %" PRIu64, - id); - break; - } - if (c->tautological) { - LOG ("LRAT CHECKER LRAT failed. Clause with id %" PRId64 - " is tautological", - id); - break; - } - used_clauses.push_back (c); - if (c->used) { - LOG ("LRAT CHECKER LRAT failed. Id %" PRId64 - " was used multiple times", - id); - break; - } else - c->used = true; - int unit = 0; - for (int *i = c->literals; i < c->literals + c->size; i++) { - int lit = *i; - if (checked_lit (-lit)) - continue; - if (unit && unit != lit) { - unit = INT_MIN; // multiple unfalsified literals - break; - } - unit = lit; // potential unit - } - if (unit == INT_MIN) { - LOG ("LRAT CHECKER check failed, found non unit clause %" PRId64, id); - break; - } - if (!unit) { - LOG ("LRAT CHECKER check succeded, clause falsified %" PRId64, id); - checking = true; - break; - } - // LOG ("LRAT CHECKER found unit clause %" PRIu64 ", assign %d", id, - // unit); - checked_lit (unit) = true; - } - for (auto &lc : used_clauses) { - lc->used = false; - } - for (auto &b : checked_lits) - b = false; - if (!checking) { - LOG ("LRAT CHECKER failed, no conflict found"); - return false; // check failed because no empty clause was found - } - return true; -} - -bool LratChecker::check_blocked (vector proof_chain) { - for (const auto &lit : imported_clause) { - checked_lit (-lit) = true; - mark (-lit) = true; - } - for (size_t i = 0; i < size_clauses; i++) { - for (LratCheckerClause *c = clauses[i], *next; c; c = next) { - next = c->next; - if (c->garbage) - continue; - // if c is part of the proof chain its id occurs negatively there. - if (std::find (proof_chain.begin (), proof_chain.end (), -c->id) != - proof_chain.end ()) { - // clause needs to be blocked - unsigned count = 0; - vector candidates; - for (unsigned i = 0; i < c->size; i++) { - const int lit = c->literals[i]; - if (checked_lit (lit)) { - count++; - } - if (mark (lit)) { - candidates.push_back (lit); - } - } - if (count < 2) { - // check failed - for (const auto &lit : imported_clause) { - checked_lit (-lit) = false; - mark (-lit) = false; - } - return false; - } else { - // all literals outside of candidates are not valid RAT candidates - for (auto &lit : imported_clause) { - if (mark (-lit) && - std::find (candidates.begin (), candidates.end (), -lit) == - candidates.end ()) { - mark (-lit) = false; - } - } - } - } else { - // any literal contained in the clause is not a valid RAT candidate - for (unsigned i = 0; i < c->size; i++) { - const int lit = c->literals[i]; - if (checked_lit (lit)) { - mark (lit) = false; - } - } - } - } - } - bool success = false; - for (const auto &lit : imported_clause) { - if (mark (-lit)) - success = true; - checked_lit (-lit) = mark (-lit) = false; - } - return success; -} - -/*------------------------------------------------------------------------*/ - -void LratChecker::add_original_clause (int64_t id, bool, - const vector &c, bool restore) { - START (checking); - LOG (c, "LRAT CHECKER addition of original clause[%" PRId64 "]", id); - if (restore) - restore_clause (id, c); - stats.added++; - stats.original++; - import_clause (c); - last_id = id; - if (!restore && id == 1 + current_id) - current_id = id; - - if (size_clauses && !restore) { - LratCheckerClause **p = find (id), *d = *p; - if (d) { - fatal_message_start (); - fputs ("different clause with id ", stderr); - fprintf (stderr, "%" PRId64, id); - fputs (" already present\n", stderr); - fatal_message_end (); - } - } - CADICAL_assert (id); - insert (); - imported_clause.clear (); - STOP (checking); -} - -void LratChecker::add_derived_clause (int64_t id, bool, - const vector &c, - const vector &proof_chain) { - START (checking); - LOG (c, "LRAT CHECKER addition of derived clause[%" PRId64 "]", id); - stats.added++; - stats.derived++; - import_clause (c); - last_id = id; - CADICAL_assert (id == current_id + 1); - current_id = id; - if (size_clauses) { - LratCheckerClause **p = find (id), *d = *p; - if (d) { - fatal_message_start (); - fputs ("different clause with id ", stderr); - fprintf (stderr, "%" PRId64, id); - fputs (" already present\n", stderr); - fatal_message_end (); - } - } - CADICAL_assert (id); - bool failed = true; - if (check (proof_chain) && check_resolution (proof_chain)) { - failed = false; - } else if (check_blocked (proof_chain)) { - failed = false; - } - if (failed) { - LOG (proof_chain, "LRAT CHECKER check failed with chain"); -#ifdef LOGGING - for (const auto &pid : proof_chain) { - const int64_t aid = abs (pid); - LratCheckerClause **p = find (aid), *d = *p; - LOG (d->literals, d->size, "clause[%" PRId64 "]", pid); - } -#endif - fatal_message_start (); - fputs ("failed to check derived clause:\n", stderr); - for (const auto &lit : imported_clause) - fprintf (stderr, "%d ", lit); - fputc ('0', stderr); - fatal_message_end (); - } else - insert (); - imported_clause.clear (); - STOP (checking); -} - -void LratChecker::add_assumption_clause (int64_t id, const vector &c, - const vector &chain) { - for (auto &lit : c) { - if (std::find (assumptions.begin (), assumptions.end (), -lit) != - assumptions.end ()) - continue; - if (std::find (constraint.begin (), constraint.end (), -lit) != - constraint.end ()) - continue; - fatal_message_start (); - fputs ("clause contains non assumptions or constraint literals\n", - stderr); - fatal_message_end (); - } - add_derived_clause (id, true, c, chain); - delete_clause (id, true, c); - assumption_clauses.push_back (id); -} - -void LratChecker::add_assumption (int a) { assumptions.push_back (a); } - -void LratChecker::add_constraint (const vector &c) { - constraint.clear (); - for (auto &lit : c) { - CADICAL_assert (lit); - if (std::find (constraint.begin (), constraint.end (), lit) != - constraint.end ()) - continue; - constraint.push_back (lit); - } -} - -void LratChecker::reset_assumptions () { - assumption_clauses.clear (); - assumptions.clear (); - concluded = false; - // constraint.clear (); -} - -void LratChecker::conclude_unsat (ConclusionType conclusion, - const vector &ids) { - if (concluded) { - fatal_message_start (); - fputs ("already concluded\n", stderr); - fatal_message_end (); - } - concluded = true; - if (conclusion == CONFLICT) { - LratCheckerClause **p = find (ids.back ()), *d = *p; - if (!d || d->size) { - fatal_message_start (); - fputs ("empty clause not in proof\n", stderr); - fatal_message_end (); - } - return; - } else if (conclusion == ASSUMPTIONS) { - if (ids.size () != 1 || assumption_clauses.size () != 1) { - fatal_message_start (); - fputs ("expected exactly one assumption clause\n", stderr); - fatal_message_end (); - } - if (ids.back () != assumption_clauses.back ()) { - fatal_message_start (); - fputs ("conclusion is not an assumption clause\n", stderr); - fatal_message_end (); - } - return; - } else { - CADICAL_assert (conclusion == CONSTRAINT); - if (constraint.size () != ids.size ()) { - fatal_message_start (); - fputs ("not complete conclusion given for constraint\n", stderr); - fputs ("The constraint contains the literals: ", stderr); - for (auto c : constraint) { - fprintf (stderr, "%d ", c); - } - - fputs ("\nThe ids are: ", stderr); - for (auto c : ids) { - fprintf (stderr, "%" PRId64 " ", c); - } - fatal_message_end (); - } - for (auto &id : ids) { - if (std::find (assumption_clauses.begin (), assumption_clauses.end (), - id) != assumption_clauses.end ()) - continue; - fatal_message_start (); - fputs ("assumption clause for constraint missing\n", stderr); - fatal_message_end (); - } - } -} - -/*------------------------------------------------------------------------*/ - -void LratChecker::delete_clause (int64_t id, bool, const vector &c) { - START (checking); - LOG (c, "LRAT CHECKER checking deletion of clause[%" PRId64 "]", id); - stats.deleted++; - import_clause (c); - last_id = id; - LratCheckerClause **p = find (id), *d = *p; - if (d) { - for (const auto &lit : imported_clause) - mark (lit) = true; - const int *dp = d->literals; - for (unsigned i = 0; i < d->size; i++) { - int lit = *(dp + i); - if (!mark (lit)) { // should never happen since ids - fatal_message_start (); // are unique. - fputs ("deleted clause not in proof:\n", stderr); - for (const auto &lit : imported_clause) - fprintf (stderr, "%d ", lit); - fputc ('0', stderr); - fatal_message_end (); - } - } - for (const auto &lit : imported_clause) - mark (lit) = false; - - // Remove from hash table, mark as garbage, connect to garbage list. - num_garbage++; - CADICAL_assert (num_clauses); - num_clauses--; - *p = d->next; - d->next = garbage; - garbage = d; - d->garbage = true; - - // If there are enough garbage clauses collect them. - // TODO: probably can just delete clause directly without - // specific garbage collection phase. - if (num_garbage > 0.5 * max ((size_t) size_clauses, (size_t) size_vars)) - collect_garbage_clauses (); - } else { - fatal_message_start (); - fputs ("deleted clause not in proof:\n", stderr); - for (const auto &lit : imported_clause) - fprintf (stderr, "%d ", lit); - fputc ('0', stderr); - fatal_message_end (); - } - imported_clause.clear (); - STOP (checking); -} - -/*------------------------------------------------------------------------*/ - -void LratChecker::weaken_minus (int64_t id, const vector &c) { - LOG (c, "LRAT CHECKER saving clause[%" PRId64 "] to restore later", id); - import_clause (c); - - CADICAL_assert (id <= current_id); - last_id = id; - LratCheckerClause **p = find (id), *d = *p; - if (d) { - for (const auto &lit : imported_clause) - mark (lit) = true; - const int *dp = d->literals; - for (unsigned i = 0; i < d->size; i++) { - int lit = *(dp + i); - if (!mark (lit)) { // should never happen since ids - fatal_message_start (); // are unique. - fputs ("deleted clause not in proof:\n", stderr); - for (const auto &lit : imported_clause) - fprintf (stderr, "%d ", lit); - fputc ('0', stderr); - fatal_message_end (); - } - } - for (const auto &lit : imported_clause) - mark (lit) = false; - } else { - fatal_message_start (); - fputs ("weakened clause not in proof:\n", stderr); - for (const auto &lit : imported_clause) - fprintf (stderr, "%d ", lit); - fputc ('0', stderr); - fatal_message_end (); - } - imported_clause.clear (); - - vector e = c; - sort (begin (e), end (e)); - clauses_to_reconstruct[id] = e; -} - -void LratChecker::restore_clause (int64_t id, const vector &c) { - LOG (c, "LRAT CHECKER check of restoration of clause[%" PRId64 "]", id); - if (clauses_to_reconstruct.find (id) == end (clauses_to_reconstruct)) { - fatal_message_start (); - fputs ("restoring clauses not deleted previously:\n", stderr); - for (const auto &lit : c) - fprintf (stderr, "%d ", lit); - fputc ('0', stderr); - fatal_message_end (); - } - vector e = c; - sort (begin (e), end (e)); - const vector &d = clauses_to_reconstruct.find (id)->second; - bool eq = true; - if (c.size () != d.size ()) { - eq = false; - } - - for (std::vector::size_type i = 0; i < e.size () && eq; ++i) { - eq = (e[i] == d[i]); - } - - if (!eq) { - fatal_message_start (); - fputs ("restoring clause that is different than the one imported:\n", - stderr); - for (const auto &lit : c) - fprintf (stderr, "%d ", lit); - fputc ('0', stderr); - fputs ("vs:\n", stderr); - for (const auto &lit : d) - fprintf (stderr, "%d ", lit); - fputc ('0', stderr); - fatal_message_end (); - } - - clauses_to_reconstruct.erase (id); -} - -void LratChecker::finalize_clause (int64_t id, const vector &c) { - START (checking); - LOG (c, "LRAT CHECKER checking finalize of clause[%" PRId64 "]", id); - stats.finalized++; - num_finalized++; - import_clause (c); - CADICAL_assert (id <= current_id); - last_id = id; - LratCheckerClause **p = find (id), *d = *p; - if (d) { - for (const auto &lit : imported_clause) - mark (lit) = true; - const int *dp = d->literals; - for (unsigned i = 0; i < d->size; i++) { - int lit = *(dp + i); - if (!mark (lit)) { // should never happen since ids - fatal_message_start (); // are unique. - fputs ("deleted clause not in proof:\n", stderr); - for (const auto &lit : imported_clause) - fprintf (stderr, "%d ", lit); - fputc ('0', stderr); - fatal_message_end (); - } - } - for (const auto &lit : imported_clause) - mark (lit) = false; - - } else { - fatal_message_start (); - fputs ("deleted clause not in proof:\n", stderr); - for (const auto &lit : imported_clause) - fprintf (stderr, "%d ", lit); - fputc ('0', stderr); - fatal_message_end (); - } - imported_clause.clear (); - STOP (checking); -} - -// check if all clauses have been deleted -void LratChecker::report_status (int, int64_t) { - START (checking); - if (num_finalized == num_clauses) { - num_finalized = 0; - LOG ("LRAT CHECKER successful finalize check, all clauses have been " - "deleted"); - } else { - fatal_message_start (); - fputs ("finalize check failed ", stderr); - fprintf (stderr, "%" PRIu64, num_clauses); - fputs (" are not finalized", stderr); - fatal_message_end (); - } - STOP (checking); -} - -/*------------------------------------------------------------------------*/ - -void LratChecker::dump () { - int max_var = 0; - for (uint64_t i = 0; i < size_clauses; i++) - for (LratCheckerClause *c = clauses[i]; c; c = c->next) - for (unsigned i = 0; i < c->size; i++) - if (abs (c->literals[i]) > max_var) - max_var = abs (c->literals[i]); - printf ("p cnf %d %" PRIu64 "\n", max_var, num_clauses); - for (uint64_t i = 0; i < size_clauses; i++) - for (LratCheckerClause *c = clauses[i]; c; c = c->next) { - for (unsigned i = 0; i < c->size; i++) - printf ("%d ", c->literals[i]); - printf ("0\n"); - } -} - -void LratChecker::begin_proof (int64_t id) { current_id = id; } - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_lrattracer.cpp b/src/sat/cadical/cadical_lrattracer.cpp deleted file mode 100644 index 4da728e18..000000000 --- a/src/sat/cadical/cadical_lrattracer.cpp +++ /dev/null @@ -1,206 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -#include - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -/*------------------------------------------------------------------------*/ - -LratTracer::LratTracer (Internal *i, File *f, bool b) - : internal (i), file (f), binary (b) -#ifndef CADICAL_QUIET - , - added (0), deleted (0) -#endif - , - latest_id (0) { - (void) internal; -} - -void LratTracer::connect_internal (Internal *i) { - internal = i; - file->connect_internal (internal); - LOG ("LRAT TRACER connected to internal"); -} - -LratTracer::~LratTracer () { - LOG ("LRAT TRACER delete"); - delete file; -} - -/*------------------------------------------------------------------------*/ - -inline void LratTracer::put_binary_zero () { - CADICAL_assert (binary); - CADICAL_assert (file); - file->put ((unsigned char) 0); -} - -inline void LratTracer::put_binary_lit (int lit) { - CADICAL_assert (binary); - CADICAL_assert (file); - CADICAL_assert (lit != INT_MIN); - unsigned idx = abs (lit); - CADICAL_assert (idx < (1u << 31)); - unsigned x = 2 * idx + (lit < 0); - unsigned char ch; - while (x & ~0x7f) { - ch = (x & 0x7f) | 0x80; - file->put (ch); - x >>= 7; - } - ch = x; - file->put (ch); -} - -inline void LratTracer::put_binary_id (int64_t id) { - CADICAL_assert (binary); - CADICAL_assert (file); - uint64_t x = abs (id); - x = 2 * x + (id < 0); - unsigned char ch; - while (x & ~0x7f) { - ch = (x & 0x7f) | 0x80; - file->put (ch); - x >>= 7; - } - ch = x; - file->put (ch); -} - -/*------------------------------------------------------------------------*/ - -void LratTracer::lrat_add_clause (int64_t id, const vector &clause, - const vector &chain) { - if (delete_ids.size ()) { - if (!binary) - file->put (latest_id), file->put (" "); - if (binary) - file->put ('d'); - else - file->put ("d "); - for (auto &did : delete_ids) { - if (binary) - put_binary_id (did); - else - file->put (did), file->put (" "); - } - if (binary) - put_binary_zero (); - else - file->put ("0\n"); - delete_ids.clear (); - } - latest_id = id; - - if (binary) - file->put ('a'), put_binary_id (id); - else - file->put (id), file->put (" "); - for (const auto &external_lit : clause) - if (binary) - put_binary_lit (external_lit); - else - file->put (external_lit), file->put (' '); - if (binary) - put_binary_zero (); - else - file->put ("0 "); - for (const auto &c : chain) - if (binary) - put_binary_id (c); - else - file->put (c), file->put (' '); // in proof chain, so they get - if (binary) - put_binary_zero (); // since cadical has no rat-steps - else - file->put ("0\n"); // this is just 2c here -} - -void LratTracer::lrat_delete_clause (int64_t id) { - delete_ids.push_back (id); // pushing off deletion for later -} - -/*------------------------------------------------------------------------*/ - -void LratTracer::add_derived_clause (int64_t id, bool, - const vector &clause, - const vector &chain) { - if (file->closed ()) - return; - LOG ("LRAT TRACER tracing addition of derived clause"); - lrat_add_clause (id, clause, chain); -#ifndef CADICAL_QUIET - added++; -#endif -} - -void LratTracer::delete_clause (int64_t id, bool, const vector &) { - if (file->closed ()) - return; - LOG ("LRAT TRACER tracing deletion of clause"); - lrat_delete_clause (id); -#ifndef CADICAL_QUIET - deleted++; -#endif -} - -void LratTracer::begin_proof (int64_t id) { - if (file->closed ()) - return; - LOG ("LRAT TRACER tracing begin of proof"); - latest_id = id; -} - -/*------------------------------------------------------------------------*/ - -bool LratTracer::closed () { return file->closed (); } - -#ifndef CADICAL_QUIET - -void LratTracer::print_statistics () { - uint64_t bytes = file->bytes (); - uint64_t total = added + deleted; - MSG ("LRAT %" PRId64 " added clauses %.2f%%", added, - percent (added, total)); - MSG ("LRAT %" PRId64 " deleted clauses %.2f%%", deleted, - percent (deleted, total)); - MSG ("LRAT %" PRId64 " bytes (%.2f MB)", bytes, - bytes / (double) (1 << 20)); -} - -#endif - -void LratTracer::close (bool print) { - CADICAL_assert (!closed ()); - file->close (); -#ifndef CADICAL_QUIET - if (print) { - MSG ("LRAT proof file '%s' closed", file->name ()); - print_statistics (); - } -#else - (void) print; -#endif -} - -void LratTracer::flush (bool print) { - CADICAL_assert (!closed ()); - file->flush (); -#ifndef CADICAL_QUIET - if (print) { - MSG ("LRAT proof file '%s' flushed", file->name ()); - print_statistics (); - } -#else - (void) print; -#endif -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_lucky.cpp b/src/sat/cadical/cadical_lucky.cpp deleted file mode 100644 index d67782db4..000000000 --- a/src/sat/cadical/cadical_lucky.cpp +++ /dev/null @@ -1,440 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -// It turns out that even in the competition there are formulas which are -// easy to satisfy by either setting all variables to the same truth value -// or by assigning variables to the same value and propagating it. In the -// latter situation this can be done either in the order of all variables -// (forward or backward) or in the order of all clauses. These lucky -// assignments can be tested initially in a kind of pre-solving step. - -// This function factors out clean up code common among the 'lucky' -// functions for backtracking and resetting a potential conflict. One could -// also use exceptions here, but there are two different reasons for -// aborting early. The first kind of aborting is due to asynchronous -// termination and the second kind due to a situation in which it is clear -// that a particular function will not be successful (for instance a -// completely negative clause is found). The latter situation returns zero -// and will just abort the particular lucky function, while the former will -// abort all (by returning '-1'). - -int Internal::unlucky (int res) { - if (level > 0) - backtrack (); - if (conflict) - conflict = 0; - return res; -} - -int Internal::trivially_false_satisfiable () { - LOG ("checking that all clauses contain a negative literal"); - CADICAL_assert (!level); - CADICAL_assert (assumptions.empty ()); - for (const auto &c : clauses) { - if (terminated_asynchronously (100)) - return unlucky (-1); - if (c->garbage) - continue; - if (c->redundant) - continue; - bool satisfied = false, found_negative_literal = false; - for (const auto &lit : *c) { - const signed char tmp = val (lit); - if (tmp > 0) { - satisfied = true; - break; - } - if (tmp < 0) - continue; - if (lit > 0) - continue; - found_negative_literal = true; - break; - } - if (satisfied || found_negative_literal) - continue; - LOG (c, "found purely positively"); - return unlucky (0); - } - VERBOSE (1, "all clauses contain a negative literal"); - for (auto idx : vars) { - if (terminated_asynchronously (10)) - return unlucky (-1); - if (val (idx)) - continue; - search_assume_decision (-idx); - if (propagate ()) - continue; - CADICAL_assert (level > 0); - LOG ("propagation failed including redundant clauses"); - return unlucky (0); - } - stats.lucky.constant.zero++; - return 10; -} - -int Internal::trivially_true_satisfiable () { - LOG ("checking that all clauses contain a positive literal"); - CADICAL_assert (!level); - CADICAL_assert (assumptions.empty ()); - for (const auto &c : clauses) { - if (terminated_asynchronously (100)) - return unlucky (-1); - if (c->garbage) - continue; - if (c->redundant) - continue; - bool satisfied = false, found_positive_literal = false; - for (const auto &lit : *c) { - const signed char tmp = val (lit); - if (tmp > 0) { - satisfied = true; - break; - } - if (tmp < 0) - continue; - if (lit < 0) - continue; - found_positive_literal = true; - break; - } - if (satisfied || found_positive_literal) - continue; - LOG (c, "found purely negatively"); - return unlucky (0); - } - VERBOSE (1, "all clauses contain a positive literal"); - for (auto idx : vars) { - if (terminated_asynchronously (10)) - return unlucky (-1); - if (val (idx)) - continue; - search_assume_decision (idx); - if (propagate ()) - continue; - CADICAL_assert (level > 0); - LOG ("propagation failed including redundant clauses"); - return unlucky (0); - } - stats.lucky.constant.one++; - return 10; -} - -/*------------------------------------------------------------------------*/ -inline bool Internal::lucky_propagate_discrepency (int dec) { - search_assume_decision (dec); - bool no_conflict = propagate (); - if (no_conflict) - return false; - if (level > 1) { - backtrack (level - 1); - search_assume_decision (-dec); - no_conflict = propagate (); - if (no_conflict) - return false; - return true; - } else { - analyze (); - CADICAL_assert (!level); - no_conflict = propagate (); - if (!no_conflict) { - analyze (); - LOG ("lucky inconsistency backward assigning to true"); - return true; - } - } - return false; -} - -int Internal::forward_false_satisfiable () { - LOG ("checking increasing variable index false assignment"); - CADICAL_assert (!unsat); - CADICAL_assert (!level); - CADICAL_assert (assumptions.empty ()); - for (auto idx : vars) { - START: - if (terminated_asynchronously (100)) - return unlucky (-1); - if (val (idx)) - continue; - if (lucky_propagate_discrepency (-idx)) { - if (unsat) - return 20; - else - return unlucky (0); - } else - goto START; - } - VERBOSE (1, "forward assuming variables false satisfies formula"); - CADICAL_assert (satisfied ()); - stats.lucky.forward.zero++; - return 10; -} - -int Internal::forward_true_satisfiable () { - LOG ("checking increasing variable index true assignment"); - CADICAL_assert (!unsat); - CADICAL_assert (!level); - CADICAL_assert (assumptions.empty ()); - for (auto idx : vars) { - START: - if (terminated_asynchronously (10)) - return unlucky (-1); - if (val (idx)) - continue; - if (lucky_propagate_discrepency (idx)) { - if (unsat) - return 20; - else - return unlucky (0); - } else - goto START; - } - VERBOSE (1, "forward assuming variables true satisfies formula"); - CADICAL_assert (satisfied ()); - stats.lucky.forward.one++; - return 10; -} - -/*------------------------------------------------------------------------*/ - -int Internal::backward_false_satisfiable () { - LOG ("checking decreasing variable index false assignment"); - CADICAL_assert (!unsat); - CADICAL_assert (!level); - CADICAL_assert (assumptions.empty ()); - for (int idx = max_var; idx > 0; idx--) { - START: - if (terminated_asynchronously (10)) - return unlucky (-1); - if (val (idx)) - continue; - if (lucky_propagate_discrepency (-idx)) { - if (unsat) - return 20; - else - return unlucky (0); - } else - goto START; - } - VERBOSE (1, "backward assuming variables false satisfies formula"); - CADICAL_assert (satisfied ()); - stats.lucky.backward.zero++; - return 10; -} - -int Internal::backward_true_satisfiable () { - LOG ("checking decreasing variable index true assignment"); - CADICAL_assert (!unsat); - CADICAL_assert (!level); - CADICAL_assert (assumptions.empty ()); - for (int idx = max_var; idx > 0; idx--) { - START: - if (terminated_asynchronously (10)) - return unlucky (-1); - if (val (idx)) - continue; - if (lucky_propagate_discrepency (idx)) { - if (unsat) - return 20; - else - return unlucky (0); - } else - goto START; - } - VERBOSE (1, "backward assuming variables true satisfies formula"); - CADICAL_assert (satisfied ()); - stats.lucky.backward.one++; - return 10; -} - -/*------------------------------------------------------------------------*/ - -// The following two functions test if the formula is a satisfiable horn -// formula. Actually the test is slightly more general. It goes over all -// clauses and assigns the first positive literal to true and propagates. -// Already satisfied clauses are of course skipped. A reverse function -// is not implemented yet. - -int Internal::positive_horn_satisfiable () { - LOG ("checking that all clauses are positive horn satisfiable"); - CADICAL_assert (!level); - CADICAL_assert (assumptions.empty ()); - for (const auto &c : clauses) { - if (terminated_asynchronously (10)) - return unlucky (-1); - if (c->garbage) - continue; - if (c->redundant) - continue; - int positive_literal = 0; - bool satisfied = false; - for (const auto &lit : *c) { - const signed char tmp = val (lit); - if (tmp > 0) { - satisfied = true; - break; - } - if (tmp < 0) - continue; - if (lit < 0) - continue; - positive_literal = lit; - break; - } - if (satisfied) - continue; - if (!positive_literal) { - LOG (c, "no positive unassigned literal in"); - return unlucky (0); - } - CADICAL_assert (positive_literal > 0); - LOG (c, "found positive literal %d in", positive_literal); - search_assume_decision (positive_literal); - if (propagate ()) - continue; - LOG ("propagation of positive literal %d leads to conflict", - positive_literal); - return unlucky (0); - } - for (auto idx : vars) { - if (terminated_asynchronously (10)) - return unlucky (-1); - if (val (idx)) - continue; - search_assume_decision (-idx); - if (propagate ()) - continue; - LOG ("propagation of remaining literal %d leads to conflict", -idx); - return unlucky (0); - } - VERBOSE (1, "clauses are positive horn satisfied"); - CADICAL_assert (!conflict); - CADICAL_assert (satisfied ()); - stats.lucky.horn.positive++; - return 10; -} - -int Internal::negative_horn_satisfiable () { - LOG ("checking that all clauses are negative horn satisfiable"); - CADICAL_assert (!level); - CADICAL_assert (assumptions.empty ()); - for (const auto &c : clauses) { - if (terminated_asynchronously (10)) - return unlucky (-1); - if (c->garbage) - continue; - if (c->redundant) - continue; - int negative_literal = 0; - bool satisfied = false; - for (const auto &lit : *c) { - const signed char tmp = val (lit); - if (tmp > 0) { - satisfied = true; - break; - } - if (tmp < 0) - continue; - if (lit > 0) - continue; - negative_literal = lit; - break; - } - if (satisfied) - continue; - if (!negative_literal) { - if (level > 0) - backtrack (); - LOG (c, "no negative unassigned literal in"); - return unlucky (0); - } - CADICAL_assert (negative_literal < 0); - LOG (c, "found negative literal %d in", negative_literal); - search_assume_decision (negative_literal); - if (propagate ()) - continue; - LOG ("propagation of negative literal %d leads to conflict", - negative_literal); - return unlucky (0); - } - for (auto idx : vars) { - if (terminated_asynchronously (10)) - return unlucky (-1); - if (val (idx)) - continue; - search_assume_decision (idx); - if (propagate ()) - continue; - LOG ("propagation of remaining literal %d leads to conflict", idx); - return unlucky (0); - } - VERBOSE (1, "clauses are negative horn satisfied"); - CADICAL_assert (!conflict); - CADICAL_assert (satisfied ()); - stats.lucky.horn.negative++; - return 10; -} - -/*------------------------------------------------------------------------*/ - -int Internal::lucky_phases () { - CADICAL_assert (!level); - require_mode (SEARCH); - if (!opts.lucky) - return 0; - - // TODO: Some of the lucky assignments can also be found if there are - // assumptions, but this is not completely implemented nor tested yet. - // Nothing done for constraint either. - // External propagator assumes a CDCL loop, so lucky is not tried here. - if (!assumptions.empty () || !constraint.empty () || external_prop) - return 0; - - START (search); - START (lucky); - CADICAL_assert (!searching_lucky_phases); - searching_lucky_phases = true; - stats.lucky.tried++; - const int64_t active_before = stats.active; - int res = trivially_false_satisfiable (); - if (!res) - res = trivially_true_satisfiable (); - if (!res) - res = forward_true_satisfiable (); - if (!res) - res = forward_false_satisfiable (); - if (!res) - res = backward_false_satisfiable (); - if (!res) - res = backward_true_satisfiable (); - if (!res) - res = positive_horn_satisfiable (); - if (!res) - res = negative_horn_satisfiable (); - if (res < 0) - CADICAL_assert (termination_forced), res = 0; - if (res == 10) - stats.lucky.succeeded++; - report ('l', !res); - CADICAL_assert (searching_lucky_phases); - - const int64_t units = active_before - stats.active; - - if (!res && units) - LOG ("lucky %zd units", units); - searching_lucky_phases = false; - STOP (lucky); - STOP (search); - - return res; -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_message.cpp b/src/sat/cadical/cadical_message.cpp deleted file mode 100644 index 42d8c0e48..000000000 --- a/src/sat/cadical/cadical_message.cpp +++ /dev/null @@ -1,218 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -/*------------------------------------------------------------------------*/ -#ifndef CADICAL_QUIET -/*------------------------------------------------------------------------*/ - -void Internal::print_prefix () { fputs (prefix.c_str (), stdout); } - -void Internal::vmessage (const char *fmt, va_list &ap) { -#ifdef LOGGING - if (!opts.log) -#endif - if (opts.quiet) - return; - print_prefix (); - vprintf (fmt, ap); - fputc ('\n', stdout); - fflush (stdout); -} - -void Internal::message (const char *fmt, ...) { - va_list ap; - va_start (ap, fmt); - vmessage (fmt, ap); - va_end (ap); -} - -void Internal::message () { -#ifdef LOGGING - if (!opts.log) -#endif - if (opts.quiet) - return; - print_prefix (); - fputc ('\n', stdout); - fflush (stdout); -} - -/*------------------------------------------------------------------------*/ - -void Internal::vverbose (int level, const char *fmt, va_list &ap) { -#ifdef LOGGING - if (!opts.log) -#endif - if (opts.quiet || level > opts.verbose) - return; - print_prefix (); - vprintf (fmt, ap); - fputc ('\n', stdout); - fflush (stdout); -} - -void Internal::verbose (int level, const char *fmt, ...) { - va_list ap; - va_start (ap, fmt); - vverbose (level, fmt, ap); - va_end (ap); -} - -void Internal::verbose (int level) { -#ifdef LOGGING - if (!opts.log) -#endif - if (opts.quiet || level > opts.verbose) - return; - print_prefix (); - fputc ('\n', stdout); - fflush (stdout); -} - -/*------------------------------------------------------------------------*/ - -void Internal::section (const char *title) { -#ifdef LOGGING - if (!opts.log) -#endif - if (opts.quiet) - return; - if (stats.sections++) - MSG (); - print_prefix (); - tout.blue (); - fputs ("--- [ ", stdout); - tout.blue (true); - fputs (title, stdout); - tout.blue (); - fputs (" ] ", stdout); - for (int i = strlen (title) + strlen (prefix.c_str ()) + 9; i < 78; i++) - fputc ('-', stdout); - tout.normal (); - fputc ('\n', stdout); - MSG (); -} - -/*------------------------------------------------------------------------*/ - -void Internal::phase (const char *phase, const char *fmt, ...) { -#ifdef LOGGING - if (!opts.log) -#endif - if (opts.quiet || (!force_phase_messages && opts.verbose < 2)) - return; - print_prefix (); - printf ("[%s] ", phase); - va_list ap; - va_start (ap, fmt); - vprintf (fmt, ap); - va_end (ap); - fputc ('\n', stdout); - fflush (stdout); -} - -void Internal::phase (const char *phase, int64_t count, const char *fmt, - ...) { -#ifdef LOGGING - if (!opts.log) -#endif - if (opts.quiet || (!force_phase_messages && opts.verbose < 2)) - return; - print_prefix (); - printf ("[%s-%" PRId64 "] ", phase, count); - va_list ap; - va_start (ap, fmt); - vprintf (fmt, ap); - va_end (ap); - fputc ('\n', stdout); - fflush (stdout); -} - -/*------------------------------------------------------------------------*/ -#endif // ifndef CADICAL_QUIET -/*------------------------------------------------------------------------*/ - -void Internal::warning (const char *fmt, ...) { - fflush (stdout); - terr.bold (); - fputs ("cadical: ", stderr); - terr.red (1); - fputs ("warning:", stderr); - terr.normal (); - fputc (' ', stderr); - va_list ap; - va_start (ap, fmt); - vfprintf (stderr, fmt, ap); - va_end (ap); - fputc ('\n', stderr); - fflush (stderr); -} - -/*------------------------------------------------------------------------*/ - -void Internal::error_message_start () { - fflush (stdout); - terr.bold (); - fputs ("cadical: ", stderr); - terr.red (1); - fputs ("error:", stderr); - terr.normal (); - fputc (' ', stderr); -} - -void Internal::error_message_end () { - fputc ('\n', stderr); - fflush (stderr); - // TODO add possibility to use call back instead. - exit (1); -} - -void Internal::verror (const char *fmt, va_list &ap) { - error_message_start (); - vfprintf (stderr, fmt, ap); - error_message_end (); -} - -void Internal::error (const char *fmt, ...) { - va_list ap; - va_start (ap, fmt); - verror (fmt, ap); - va_end (ap); // unreachable -} - -/*------------------------------------------------------------------------*/ - -void fatal_message_start () { - fflush (stdout); - terr.bold (); - fputs ("cadical: ", stderr); - terr.red (1); - fputs ("fatal error:", stderr); - terr.normal (); - fputc (' ', stderr); -} - -void fatal_message_end () { - fputc ('\n', stderr); - fflush (stderr); - abort (); -} - -void fatal (const char *fmt, ...) { - fatal_message_start (); - va_list ap; - va_start (ap, fmt); - vfprintf (stderr, fmt, ap); - va_end (ap); - fatal_message_end (); - abort (); -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_minimize.cpp b/src/sat/cadical/cadical_minimize.cpp deleted file mode 100644 index 97af5fbe6..000000000 --- a/src/sat/cadical/cadical_minimize.cpp +++ /dev/null @@ -1,230 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -// Functions for learned clause minimization. We only have the recursive -// version, which actually really is implemented recursively. We also -// played with a derecursified version, which however was more complex and -// slower. The trick to keep potential stack exhausting recursion under -// guards is to explicitly limit the recursion depth. - -// Instead of signatures as in the original implementation in MiniSAT and -// our corresponding paper, we use the 'poison' idea of Allen Van Gelder to -// mark unsuccessful removal attempts, then Donald Knuth's idea to abort -// minimization if only one literal was seen on the level and a new idea of -// also aborting if the earliest seen literal was assigned afterwards. - -bool Internal::minimize_literal (int lit, int depth) { - LOG ("attempt to minimize lit %d at depth %d", lit, depth); - CADICAL_assert (val (lit) > 0); - Flags &f = flags (lit); - Var &v = var (lit); - if (!v.level || f.removable || f.keep) - return true; - if (!v.reason || f.poison || v.level == level) - return false; - const Level &l = control[v.level]; - if (!depth && l.seen.count < 2) - return false; // Don Knuth's idea - if (v.trail <= l.seen.trail) - return false; // new early abort - if (depth > opts.minimizedepth) - return false; - bool res = true; - CADICAL_assert (v.reason); - if (opts.minimizeticks) - stats.ticks.search[stable]++; - if (v.reason == external_reason) { - CADICAL_assert (!opts.exteagerreasons); - v.reason = learn_external_reason_clause (lit, 0, true); - if (!v.reason) { - CADICAL_assert (!v.level); - return true; - } - } - CADICAL_assert (v.reason != external_reason); - const const_literal_iterator end = v.reason->end (); - const_literal_iterator i; - for (i = v.reason->begin (); res && i != end; i++) { - const int other = *i; - if (other == lit) - continue; - res = minimize_literal (-other, depth + 1); - } - if (res) - f.removable = true; - else - f.poison = true; - minimized.push_back (lit); - if (!depth) { - LOG ("minimizing %d %s", lit, res ? "succeeded" : "failed"); - } - return res; -} - -// Sorting the clause before minimization with respect to the trail order -// (literals with smaller trail height first) is necessary but natural and -// might help to minimize the required recursion depth too. - -struct minimize_trail_positive_rank { - Internal *internal; - minimize_trail_positive_rank (Internal *s) : internal (s) {} - typedef unsigned Type; - Type operator() (const int &a) const { - CADICAL_assert (internal->val (a)); - return (unsigned) internal->var (a).trail; - } -}; - -struct minimize_trail_smaller { - Internal *internal; - minimize_trail_smaller (Internal *s) : internal (s) {} - bool operator() (const int &a, const int &b) const { - return internal->var (a).trail < internal->var (b).trail; - } -}; - -struct minimize_trail_level_positive_rank { - Internal *internal; - minimize_trail_level_positive_rank (Internal *s) : internal (s) {} - typedef uint64_t Type; - Type operator() (const int &a) const { - CADICAL_assert (internal->val (a)); - Var &v = internal->var (a); - uint64_t res = v.level; - res <<= 32; - res |= v.trail; - return res; - } -}; - -struct minimize_trail_level_smaller { - Internal *internal; - minimize_trail_level_smaller (Internal *s) : internal (s) {} - bool operator() (const int &a, const int &b) const { - return minimize_trail_level_positive_rank (internal) (a) < - minimize_trail_level_positive_rank (internal) (b); - } -}; - -void Internal::minimize_clause () { - START (minimize); - LOG (clause, "minimizing first UIP clause"); - - external->check_learned_clause (); // check 1st UIP learned clause first - minimize_sort_clause (); - - CADICAL_assert (minimized.empty ()); - CADICAL_assert (minimize_chain.empty ()); - const auto end = clause.end (); - auto j = clause.begin (), i = j; - std::vector stack; - for (; i != end; i++) { - if (minimize_literal (-*i)) { - if (lrat) { - CADICAL_assert (mini_chain.empty ()); - calculate_minimize_chain (-*i, stack); - for (auto p : mini_chain) { - minimize_chain.push_back (p); - } - mini_chain.clear (); - } - stats.minimized++; - } else - flags (*j++ = *i).keep = true; - } - LOG ("minimized %zd literals", (size_t) (clause.end () - j)); - if (j != end) - clause.resize (j - clause.begin ()); - clear_minimized_literals (); - for (auto p = minimize_chain.rbegin (); p != minimize_chain.rend (); - p++) { - lrat_chain.push_back (*p); - } - minimize_chain.clear (); - STOP (minimize); -} - -// go backwards in reason graph and add ids -// mini_chain is in correct order so we have to add it to minimize_chain -// and then reverse when we put it on lrat_chain -// -// We have to use the non-recursive as we cannot limit the depth like the -// minimize version. Unlike the minimize version, we have to keep literals -// on the stack in order to push its reason later. -void Internal::calculate_minimize_chain (int lit, std::vector &stack) { - CADICAL_assert (stack.empty ()); - stack.push_back (vidx (lit)); - - while (!stack.empty ()) { - const int idx = stack.back (); - CADICAL_assert (idx); - stack.pop_back (); - if (idx < 0) { - Var &v = var (idx); - mini_chain.push_back (v.reason->id); - continue; - } - CADICAL_assert (idx); - Flags &f = flags (idx); - Var &v = var (idx); - if (f.keep || f.added || f.poison) { - continue; - } - if (!v.level) { - if (f.seen) - continue; - f.seen = true; - unit_analyzed.push_back (idx); - const int lit = val (idx) > 0 ? idx : -idx; - int64_t id = unit_id (lit); - unit_chain.push_back (id); - continue; - } - f.added = true; - CADICAL_assert (v.reason && f.removable); - const const_literal_iterator end = v.reason->end (); - const_literal_iterator i; - LOG (v.reason, "LRAT chain for lit %d at depth %zd by going over", lit, - stack.size ()); - stack.push_back (-idx); - for (i = v.reason->begin (); i != end; i++) { - const int other = *i; - if (other == idx) - continue; - stack.push_back (vidx (other)); - } - } - CADICAL_assert (stack.empty ()); -} - -// Sort the literals in reverse assignment order (thus trail order) to -// establish the base case of the recursive minimization algorithm in the -// positive case (where a literal with 'keep' true is hit). -// -void Internal::minimize_sort_clause () { - MSORT (opts.radixsortlim, clause.begin (), clause.end (), - minimize_trail_positive_rank (this), - minimize_trail_smaller (this)); -} - -void Internal::clear_minimized_literals () { - LOG ("clearing %zd minimized literals", minimized.size ()); - for (const auto &lit : minimized) { - Flags &f = flags (lit); - f.poison = f.removable = f.shrinkable = f.added = false; - } - for (const auto &lit : clause) - CADICAL_assert (!flags (lit).shrinkable), flags (lit).keep = - flags (lit).shrinkable = - flags (lit).added = false; - minimized.clear (); -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_occs.cpp b/src/sat/cadical/cadical_occs.cpp deleted file mode 100644 index f79d7a690..000000000 --- a/src/sat/cadical/cadical_occs.cpp +++ /dev/null @@ -1,58 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -/*------------------------------------------------------------------------*/ - -// Occurrence lists. - -void Internal::init_occs () { - if (otab.size () < 2 * vsize) - otab.resize (2 * vsize, Occs ()); - LOG ("initialized occurrence lists"); -} - -void Internal::reset_occs () { - CADICAL_assert (occurring ()); - erase_vector (otab); - LOG ("reset occurrence lists"); -} - -void Internal::clear_occs () { - CADICAL_assert (occurring ()); - for (auto &occ : otab) - occ.clear (); - LOG ("clear occurrence lists"); -} - -/*------------------------------------------------------------------------*/ - -// One-sided occurrence counter (each literal has its own counter). - -void Internal::init_noccs () { - CADICAL_assert (ntab.empty ()); - if (ntab.size () < 2 * vsize) - ntab.resize (2 * vsize, 0); - LOG ("initialized two-sided occurrence counters"); -} - -void Internal::clear_noccs () { - CADICAL_assert (!ntab.empty ()); - for (auto &nt : ntab) - nt = 0; - LOG ("clear two-sided occurrence counters"); -} - -void Internal::reset_noccs () { - CADICAL_assert (!max_var || !ntab.empty ()); - erase_vector (ntab); - LOG ("reset two-sided occurrence counters"); -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_options.cpp b/src/sat/cadical/cadical_options.cpp deleted file mode 100644 index 88eba53ab..000000000 --- a/src/sat/cadical/cadical_options.cpp +++ /dev/null @@ -1,365 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -/*------------------------------------------------------------------------*/ - -// By default, e.g., for library usage, the 'opts.report' value is zero -// ('false') but can be set to '1' by the stand alone solver. Using here -// a static default value avoids that the stand alone solver reports that -// '--report=1' is different from the default in 'print ()' below. -// -int Options::reportdefault; - -/*------------------------------------------------------------------------*/ - -// The order of initializations of static objects is undefined and thus we -// can not assume that this table is already initialized if a solver and -// thus the constructor of 'Options' is called. Therefore we just have to -// reinitialize this table in every call to 'Options::Options'. This does -// not produce a data race even for parallel initialization since the -// same values are written by all threads under the assumption that the -// 'reportdefault' is set before any solver is initialized. We do have to -// perform this static initialization though, since 'has' is static and does -// not require that the 'Options' constructor was called. - -Option Options::table[] = { -#define OPTION(N, V, L, H, O, P, R, D) \ - {#N, (int) V, (int) L, (int) H, (int) O, (bool) P, D}, - OPTIONS -#undef OPTION -}; - -/*------------------------------------------------------------------------*/ - -// Binary search in 'table', which requires option names to be sorted, which -// in turned is checked at start-up in 'Options::Options'. - -Option *Options::has (const char *name) { - size_t l = 0, r = number_of_options; - while (l < r) { - size_t m = l + (r - l) / 2; - Option *res = &table[m]; - int tmp = strcmp (name, res->name); - if (!tmp) - return res; - if (tmp < 0) - r = m; - if (tmp > 0) - l = m + 1; - } - return 0; -} - -/*------------------------------------------------------------------------*/ - -bool Options::parse_long_option (const char *arg, string &name, int &val) { - if (arg[0] != '-' || arg[1] != '-') - return false; - const bool has_no_prefix = - (arg[2] == 'n' && arg[3] == 'o' && arg[4] == '-'); - const size_t offset = has_no_prefix ? 5 : 2; - name = arg + offset; - const size_t pos = name.find_first_of ('='); - if (pos != string::npos) - name[pos] = 0; - if (!Options::has (name.c_str ())) - return false; - if (pos == string::npos) - val = !has_no_prefix; - else { - const char *val_str = name.c_str () + pos + 1; - if (!parse_int_str (val_str, val)) - return false; - } - return true; -} - -/*------------------------------------------------------------------------*/ - -void Options::initialize_from_environment (int &val, const char *name, - const int L, const int H) { - char key[80], *q; - const char *p; - CADICAL_assert (strlen (name) + strlen ("CADICAL_") + 1 < sizeof (key)); - for (p = "CADICAL_", q = key; *p; p++) - *q++ = *p; - for (p = name; *p; p++) - *q++ = toupper (*p); - CADICAL_assert (q < key + sizeof (key)); - *q = 0; - const char *val_str = getenv (key); - if (!val_str) - return; - if (!parse_int_str (val_str, val)) - return; - if (val < L) - val = L; - if (val > H) - val = H; -} - -// Initialize all the options to their default value 'V'. - -Options::Options (Internal *s) : internal (s) { - CADICAL_assert (number_of_options == sizeof Options::table / sizeof (Option)); - - // First initialize them according to defaults in 'options.hpp'. - // - const char *prev = ""; - size_t i = 0; -#define OPTION(N, V, L, H, O, P, R, D) \ - do { \ - if ((L) > (V)) \ - FATAL ("'" #N "' default '" #V "' " \ - "lower minimum '" #L "' in 'options.hpp'"); \ - if ((H) < (V)) \ - FATAL ("'" #N "' default '" #V "' " \ - "larger maximum '" #H "' in 'options.hpp'"); \ - if (strcmp (prev, #N) > 0) \ - FATAL ("'%s' ordered before '" #N "' in 'options.hpp'", prev); \ - N = (int) (V); \ - CADICAL_assert (&val (i) == &N); \ - /* The order of initializing static data is undefined and thus */ \ - /* it might be the case that the 'table' is not initialized yet. */ \ - /* Thus this construction just reinitializes the table too even */ \ - /* though it might not be necessary. */ \ - CADICAL_assert (!table[i].name || !strcmp (table[i].name, #N)); \ - table[i] = {#N, (int) (V), (int) (L), (int) (H), \ - (int) (O), (bool) (P), D}; \ - prev = #N; \ - i++; \ - } while (0); - OPTIONS -#undef OPTION - - // Check consistency in debugging mode. - // -#ifndef CADICAL_NDEBUG - CADICAL_assert (i == number_of_options); - CADICAL_assert (!has ("aaaaa")); - CADICAL_assert (!has ("non-existing-option")); - CADICAL_assert (!has ("zzzzz")); -#endif - - // Now overwrite default options with environment values. - // -#define OPTION(N, V, L, H, O, P, R, D) \ - initialize_from_environment (N, #N, L, H); - OPTIONS -#undef OPTION -} - -/*------------------------------------------------------------------------*/ - -void Options::set (Option *o, int new_val) { - CADICAL_assert (o); - int &val = o->val (this), old_val = val; - if (old_val == new_val) { - LOG ("keeping value '%d' of option '%s'", old_val, o->name); - return; - } - if (new_val < o->lo) { - LOG ("bounding '%d' to lower limit '%d' for option '%s'", new_val, - o->lo, o->name); - new_val = o->lo; - } - if (new_val > o->hi) { - LOG ("bounding '%d' to upper limit '%d' for option '%s'", new_val, - o->hi, o->name); - new_val = o->hi; - } - val = new_val; - LOG ("set option 'set (\"%s\", %d)' from '%d'", o->name, new_val, - old_val); -} - -// Explicit option value setting. - -bool Options::set (const char *name, int val) { - Option *o = has (name); - if (!o) - return false; - set (o, val); - return true; -} - -int Options::get (const char *name) { - Option *o = has (name); - return o ? o->val (this) : 0; -} - -/*------------------------------------------------------------------------*/ - -void Options::print () { - unsigned different = 0; -#ifdef CADICAL_QUIET - const bool verbose = false; -#endif - char buffer[256]; - // We prefer the macro iteration here since '[VLH]' might be '1e9' etc. -#define OPTION(N, V, L, H, O, P, R, D) \ - if (N != (V)) \ - different++; \ - if (verbose || N != (V)) { \ - if ((L) == 0 && (H) == 1) { \ - snprintf (buffer, sizeof buffer, "--" #N "=%s", \ - (N ? "true" : "false")); \ - MSG (" %s%-30s%s (%s default %s'%s'%s)", \ - ((N == (V)) ? "" : tout.bright_yellow_code ()), buffer, \ - ((N == (V)) ? "" : tout.normal_code ()), \ - ((N == (V)) ? "same as" : "different from"), \ - ((N == (V)) ? tout.green_code () : tout.yellow_code ()), \ - (bool) (V) ? "true" : "false", tout.normal_code ()); \ - } else { \ - snprintf (buffer, sizeof buffer, "--" #N "=%d", N); \ - MSG (" %s%-30s%s (%s default %s'" #V "'%s)", \ - ((N == (V)) ? "" : tout.bright_yellow_code ()), buffer, \ - ((N == (V)) ? "" : tout.normal_code ()), \ - ((N == (V)) ? "same as" : "different from"), \ - ((N == (V)) ? tout.green_code () : tout.yellow_code ()), \ - tout.normal_code ()); \ - } \ - } - OPTIONS -#undef OPTION - if (!different) - MSG ("all options are set to their default value"); -} - -/*------------------------------------------------------------------------*/ - -void Options::usage () { - // We prefer the macro iteration here since '[VLH]' might be '1e9' etc. -#define OPTION(N, V, L, H, O, P, R, D) \ - if ((L) == 0 && (H) == 1) \ - printf (" %-26s " D " [%s]\n", "--" #N "=bool", \ - (bool) (V) ? "true" : "false"); \ - else \ - printf (" %-26s " D " [" #V "]\n", "--" #N "=" #L ".." #H); - OPTIONS -#undef OPTION -} - -/*------------------------------------------------------------------------*/ - -void Options::optimize (int val) { - - if (val < 0) { - LOG ("ignoring negative optimization mode '%d'", val); - return; - } - - const int max_val = 31; - if (val > max_val) { - LOG ("optimization argument '%d' reduced to '%d'", val, max_val); - val = max_val; - } - - int64_t factor2 = 1; - for (int i = 0; i < val && factor2 <= INT_MAX; i++) - factor2 *= 2; - - int64_t factor10 = 1; - for (int i = 0; i < val && factor10 <= INT_MAX; i++) - factor10 *= 10; - - unsigned increased = 0; -#define OPTION(N, V, L, H, O, P, R, D) \ - do { \ - if (!(O)) \ - break; \ - const int64_t factor1 = ((O) == 1 ? factor2 : factor10); \ - int64_t new_val = factor1 * (int64_t) (V); \ - if (new_val > (H)) \ - new_val = (H); \ - if (new_val == (int) (V)) \ - break; \ - LOG ("optimization mode '%d' for '%s' " \ - "gives '%" PRId64 "' instead of '%d", \ - val, #N, new_val, (int) (V)); \ - CADICAL_assert (new_val <= INT_MAX); \ - N = (int) new_val; \ - increased++; \ - } while (0); - OPTIONS -#undef OPTION - if (increased) - MSG ("optimization mode '-O%d' increased %u limits", val, increased); -} - -/*------------------------------------------------------------------------*/ - -void Options::disable_preprocessing () { - size_t count = 0; -#define OPTION(N, V, L, H, O, P, R, D) \ - do { \ - if (!(P)) \ - break; \ - if (!(N)) \ - break; \ - LOG ("plain mode disables '%s'", #N); \ - CADICAL_assert ((L) == 0); \ - CADICAL_assert ((H) == 1); \ - count++; \ - N = 0; \ - } while (0); - OPTIONS -#undef OPTION - LOG ("forced plain mode disabled %zd preprocessing options", count); -#ifndef LOGGING - (void) count; -#endif -} - -bool Options::is_preprocessing_option (const char *name) { - Option *o = has (name); - return o ? o->preprocessing : false; -} - -/*------------------------------------------------------------------------*/ - -void Options::reset_default_values () { - size_t count = 0; -#define OPTION(N, V, L, H, O, P, R, D) \ - do { \ - if (!(R)) \ - break; \ - if (N == (V)) \ - break; \ - LOG ("resetting option '%s' to default %s", #N, #V); \ - count++; \ - N = (int) (V); \ - } while (0); - OPTIONS -#undef OPTION - LOG ("reset %zd options to their default values", count); -#ifndef LOGGING - (void) count; -#endif -} - -/*------------------------------------------------------------------------*/ - -void Options::copy (Options &other) const { -#ifdef LOGGING - Internal *internal = other.internal; -#endif -#define OPTION(N, V, L, H, O, P, R, D) \ - if ((N) == (int) (V)) \ - LOG ("keeping non default option '--%s=%s'", #N, #V); \ - else if ((N) != (int) (V)) { \ - LOG ("overwriting default option by '--%s=%d'", #N, N); \ - other.N = N; \ - } - OPTIONS -#undef OPTION -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_parse.cpp b/src/sat/cadical/cadical_parse.cpp deleted file mode 100644 index 0668aca7d..000000000 --- a/src/sat/cadical/cadical_parse.cpp +++ /dev/null @@ -1,442 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -/*------------------------------------------------------------------------*/ - -namespace CaDiCaL { - -/*------------------------------------------------------------------------*/ - -// Parse error. - -#define PER(...) \ - do { \ - internal->error_message.init ( \ - "%s:%" PRIu64 ": parse error: ", file->name (), \ - (uint64_t) file->lineno ()); \ - return internal->error_message.append (__VA_ARGS__); \ - } while (0) - -/*------------------------------------------------------------------------*/ - -// Parsing utilities. - -inline int Parser::parse_char () { return file->get (); } - -// Return an non zero error string if a parse error occurred. - -inline const char *Parser::parse_string (const char *str, char prev) { - for (const char *p = str; *p; p++) - if (parse_char () == *p) - prev = *p; - else if (*p == ' ') - PER ("expected space after '%c'", prev); - else - PER ("expected '%c' after '%c'", *p, prev); - return 0; -} - -inline const char *Parser::parse_positive_int (int &ch, int &res, - const char *name) { - CADICAL_assert (isdigit (ch)); - res = ch - '0'; - while (isdigit (ch = parse_char ())) { - int digit = ch - '0'; - if (INT_MAX / 10 < res || INT_MAX - digit < 10 * res) - PER ("too large '%s' in header", name); - res = 10 * res + digit; - } - return 0; -} - -static const char *cube_token = "unexpected 'a' in CNF"; - -inline const char *Parser::parse_lit (int &ch, int &lit, int &vars, - int strict) { - if (ch == 'a') - return cube_token; - int sign = 0; - if (ch == '-') { - if (!isdigit (ch = parse_char ())) - PER ("expected digit after '-'"); - sign = -1; - } else if (!isdigit (ch)) - PER ("expected digit or '-'"); - else - sign = 1; - lit = ch - '0'; - while (isdigit (ch = parse_char ())) { - int digit = ch - '0'; - if (INT_MAX / 10 < lit || INT_MAX - digit < 10 * lit) - PER ("literal too large"); - lit = 10 * lit + digit; - } - if (ch == '\r') - ch = parse_char (); - if (ch != 'c' && ch != ' ' && ch != '\t' && ch != '\n' && ch != EOF) - PER ("expected white space after '%d'", sign * lit); - if (lit > vars) { - if (strict != FORCED) - PER ("literal %d exceeds maximum variable %d", sign * lit, vars); - else - vars = lit; - } - lit *= sign; - return 0; -} - -/*------------------------------------------------------------------------*/ - -// Parsing CNF in DIMACS format. - -const char *Parser::parse_dimacs_non_profiled (int &vars, int strict) { - -#ifndef CADICAL_QUIET - double start = internal->time (); -#endif - - bool found_inccnf_header = false; - int ch, clauses = 0; - vars = 0; - - // First read comments before header with possibly embedded options. - // - for (;;) { - ch = parse_char (); - if (strict != STRICT) - if (ch == ' ' || ch == '\n' || ch == '\t' || ch == '\r') - continue; - if (ch != 'c') - break; - string buf; - while ((ch = parse_char ()) != '\n') - if (ch == EOF) - PER ("unexpected end-of-file in header comment"); - else if (ch != '\r') - buf.push_back (ch); - const char *o; - for (o = buf.c_str (); *o && *o != '-'; o++) - ; - if (!*o) - continue; - PHASE ("parse-dimacs", "found option '%s'", o); - if (*o) - solver->set_long_option (o); - } - - if (ch != 'p') - PER ("expected 'c' or 'p'"); - - ch = parse_char (); - if (strict == STRICT) { - if (ch != ' ') - PER ("expected space after 'p'"); - ch = parse_char (); - } else if (ch != ' ' && ch != '\t') - PER ("expected white space after 'p'"); - else { - do - ch = parse_char (); - while (ch == ' ' || ch == '\t'); - } - - // Now read 'p cnf ' header of DIMACS file - // or 'p inccnf' of incremental 'INCCNF' file. - // - if (ch == 'c') { - CADICAL_assert (!found_inccnf_header); - if (strict == STRICT) { - const char *err = parse_string ("nf ", 'c'); - if (err) - return err; - ch = parse_char (); - if (!isdigit (ch)) - PER ("expected digit after 'p cnf '"); - err = parse_positive_int (ch, vars, ""); - if (err) - return err; - if (ch != ' ') - PER ("expected ' ' after 'p cnf %d'", vars); - if (!isdigit (ch = parse_char ())) - PER ("expected digit after 'p cnf %d '", vars); - err = parse_positive_int (ch, clauses, ""); - if (err) - return err; - if (ch != '\n') - PER ("expected new-line after 'p cnf %d %d'", vars, clauses); - } else { - if (parse_char () != 'n') - PER ("expected 'n' after 'p c'"); - if (parse_char () != 'f') - PER ("expected 'f' after 'p cn'"); - ch = parse_char (); - if (!isspace (ch)) - PER ("expected space after 'p cnf'"); - do - ch = parse_char (); - while (isspace (ch)); - if (!isdigit (ch)) - PER ("expected digit after 'p cnf '"); - const char *err = parse_positive_int (ch, vars, ""); - if (err) - return err; - if (!isspace (ch)) - PER ("expected space after 'p cnf %d'", vars); - do - ch = parse_char (); - while (isspace (ch)); - if (!isdigit (ch)) - PER ("expected digit after 'p cnf %d '", vars); - err = parse_positive_int (ch, clauses, ""); - if (err) - return err; - while (ch != '\n') { - if (ch != '\r' && !isspace (ch)) - PER ("expected new-line after 'p cnf %d %d'", vars, clauses); - ch = parse_char (); - } - } - - MSG ("found %s'p cnf %d %d'%s header", tout.green_code (), vars, - clauses, tout.normal_code ()); - - if (strict != FORCED) - solver->reserve (vars); - internal->reserve_ids (clauses); - } else if (!parse_inccnf_too) - PER ("expected 'c' after 'p '"); - else if (ch == 'i') { - found_inccnf_header = true; - const char *err = parse_string ("nccnf", 'i'); - if (err) - return err; - ch = parse_char (); - if (strict == STRICT) { - if (ch != '\n') - PER ("expected new-line after 'p inccnf'"); - } else { - while (ch != '\n') { - if (ch != '\r' && !isspace (ch)) - PER ("expected new-line after 'p inccnf'"); - ch = parse_char (); - } - } - - MSG ("found %s'p inccnf'%s header", tout.green_code (), - tout.normal_code ()); - - strict = FORCED; - } else - PER ("expected 'c' or 'i' after 'p '"); - - if (parse_inccnf_too) - *parse_inccnf_too = false; - - // Now read body of DIMACS part. - // - int lit = 0, parsed = 0; - while ((ch = parse_char ()) != EOF) { - if (ch == ' ' || ch == '\n' || ch == '\t' || ch == '\r') - continue; - if (ch == 'c') { - while ((ch = parse_char ()) != '\n' && ch != EOF) - ; - if (ch == EOF) - break; - continue; - } - if (ch == 'a' && found_inccnf_header) - break; - const char *err = parse_lit (ch, lit, vars, strict); - if (err) - return err; - if (ch == 'c') { - while ((ch = parse_char ()) != '\n') - if (ch == EOF) - PER ("unexpected end-of-file in comment"); - } - solver->add (lit); - if (!found_inccnf_header && !lit && parsed++ >= clauses && - strict != FORCED) - PER ("too many clauses"); - } - - if (lit) - PER ("last clause without terminating '0'"); - - if (!found_inccnf_header && parsed < clauses && strict != FORCED) - PER ("clause missing"); - -#ifndef CADICAL_QUIET - double end = internal->time (); - MSG ("parsed %d clauses in %.2f seconds %s time", parsed, end - start, - internal->opts.realtime ? "real" : "process"); -#endif - -#ifndef CADICAL_QUIET - start = end; - size_t num_cubes = 0; -#endif - if (ch == 'a') { - CADICAL_assert (parse_inccnf_too); - CADICAL_assert (found_inccnf_header); - if (!*parse_inccnf_too) - *parse_inccnf_too = true; - for (;;) { - ch = parse_char (); - if (ch == ' ' || ch == '\n' || ch == '\t' || ch == '\r') - continue; - if (ch == 'c') { - while ((ch = parse_char ()) != '\n' && ch != EOF) - ; - if (ch == EOF) - break; - continue; - } - const char *err = parse_lit (ch, lit, vars, strict); - if (err == cube_token) - PER ("two 'a' in a row"); - else if (err) - return err; - if (ch == 'c') { - while ((ch = parse_char ()) != '\n') - if (ch == EOF) - PER ("unexpected end-of-file in comment"); - } - if (cubes) - cubes->push_back (lit); - if (!lit) { -#ifndef CADICAL_QUIET - num_cubes++; -#endif - for (;;) { - ch = parse_char (); - if (ch == ' ' || ch == '\n' || ch == '\t' || ch == '\r') - continue; - if (ch == 'c') { - while ((ch = parse_char ()) != '\n' && ch != EOF) - ; - if (ch == EOF) - break; - } - if (ch == EOF) - break; - if (ch != 'a') - PER ("expected 'a' or end-of-file after zero"); - lit = INT_MIN; - break; - } - if (ch == EOF) - break; - } - } - if (lit) - PER ("last cube without terminating '0'"); - } -#ifndef CADICAL_QUIET - if (found_inccnf_header) { - double end = internal->time (); - MSG ("parsed %zd cubes in %.2f seconds %s time", num_cubes, end - start, - internal->opts.realtime ? "real" : "process"); - } -#endif - - return 0; -} - -/*------------------------------------------------------------------------*/ - -// Parsing solution in competition output format. - -const char *Parser::parse_solution_non_profiled () { - external->solution = new signed char[external->max_var + 1u]; - external->solution_size = external->max_var; - clear_n (external->solution, external->max_var + 1u); - int ch; - for (;;) { - ch = parse_char (); - if (ch == EOF) - PER ("missing 's' line"); - else if (ch == 'c') { - while ((ch = parse_char ()) != '\n') - if (ch == EOF) - PER ("unexpected end-of-file in comment"); - } else if (ch == 's') - break; - else - PER ("expected 'c' or 's'"); - } - const char *err = parse_string (" SATISFIABLE", 's'); - if (err) - return err; - if ((ch = parse_char ()) == '\r') - ch = parse_char (); - if (ch != '\n') - PER ("expected new-line after 's SATISFIABLE'"); -#ifndef CADICAL_QUIET - int count = 0; -#endif - for (;;) { - ch = parse_char (); - if (ch != 'v') - PER ("expected 'v' at start-of-line"); - if ((ch = parse_char ()) != ' ') - PER ("expected ' ' after 'v'"); - int lit = 0; - ch = parse_char (); - do { - if (ch == ' ' || ch == '\t') { - ch = parse_char (); - continue; - } - err = parse_lit (ch, lit, external->max_var, false); - if (err) - return err; - if (ch == 'c') - PER ("unexpected comment"); - if (!lit) - break; - if (external->solution[abs (lit)]) - PER ("variable %d occurs twice", abs (lit)); - LOG ("solution %d", lit); - external->solution[abs (lit)] = sign (lit); -#ifndef CADICAL_QUIET - count++; -#endif - if (ch == '\r') - ch = parse_char (); - } while (ch != '\n'); - if (!lit) - break; - } - MSG ("parsed %d values %.2f%%", count, - percent (count, external->max_var)); - return 0; -} - -/*------------------------------------------------------------------------*/ - -// Wrappers to profile parsing and at the same time use the convenient -// implicit 'return' in PER in the non-profiled versions. - -const char *Parser::parse_dimacs (int &vars, int strict) { - CADICAL_assert (strict == FORCED || strict == RELAXED || strict == STRICT); - START (parse); - const char *err = parse_dimacs_non_profiled (vars, strict); - STOP (parse); - return err; -} - -const char *Parser::parse_solution () { - START (parse); - const char *err = parse_solution_non_profiled (); - STOP (parse); - return err; -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_phases.cpp b/src/sat/cadical/cadical_phases.cpp deleted file mode 100644 index f7e4eaffd..000000000 --- a/src/sat/cadical/cadical_phases.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -void Internal::copy_phases (vector &dst) { - START (copy); - for (auto i : vars) - dst[i] = phases.saved[i]; - STOP (copy); -} - -void Internal::clear_phases (vector &dst) { - START (copy); - for (auto i : vars) - dst[i] = 0; - STOP (copy); -} - -void Internal::phase (int lit) { - const int idx = vidx (lit); - signed char old_forced_phase = phases.forced[idx]; - signed char new_forced_phase = sign (lit); - if (old_forced_phase == new_forced_phase) { - LOG ("forced phase remains at %d", old_forced_phase * idx); - return; - } - if (old_forced_phase) - LOG ("overwriting old forced phase %d", old_forced_phase * idx); - LOG ("new forced phase %d", new_forced_phase * idx); - phases.forced[idx] = new_forced_phase; -} - -void Internal::unphase (int lit) { - const int idx = vidx (lit); - signed char old_forced_phase = phases.forced[idx]; - if (!old_forced_phase) { - LOG ("forced phase of %d already reset", lit); - return; - } - LOG ("clearing old forced phase %d", old_forced_phase * idx); - phases.forced[idx] = 0; -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_probe.cpp b/src/sat/cadical/cadical_probe.cpp deleted file mode 100644 index 19ff0961f..000000000 --- a/src/sat/cadical/cadical_probe.cpp +++ /dev/null @@ -1,993 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -/*------------------------------------------------------------------------*/ - -// Failed literal probing uses its own propagation and assignment -// functions. It further provides on-the-fly generation of hyper binary -// resolvents but only probes on roots of the binary implication graph. The -// search for failed literals is limited, but untried roots are kept until -// the next time 'probe' is called. Left over probes from the last attempt -// and new probes are tried until the limit is hit or all are tried. - -/*------------------------------------------------------------------------*/ - -bool Internal::inprobing () { - if (!opts.inprobing) - return false; - if (!preprocessing && !opts.inprocessing) - return false; - if (preprocessing) - CADICAL_assert (lim.preprocessing); - if (stats.inprobingphases && last.inprobe.reductions == stats.reductions) - return false; - return lim.inprobe <= stats.conflicts; -} - -/*------------------------------------------------------------------------*/ - -inline int Internal::get_parent_reason_literal (int lit) { - const int idx = vidx (lit); - int res = parents[idx]; - if (lit < 0) - res = -res; - return res; -} - -inline void Internal::set_parent_reason_literal (int lit, int reason) { - const int idx = vidx (lit); - if (lit < 0) - reason = -reason; - parents[idx] = reason; -} - -/*-----------------------------------------------------------------------*/ - -// for opts.probehbr=false we need to do a lot of extra work to remember the -// correct lrat_chains... This solution is also memory intensive I think -// all corresponding functions are guarded to only work with the right -// options so they can be called without checking for options -// -// call locally after failed_literal or backtracking -// -void Internal::clean_probehbr_lrat () { - if (!lrat || opts.probehbr) - return; - for (auto &field : probehbr_chains) { - for (auto &chain : field) { - chain.clear (); - } - } -} - -// call globally before a probe round (or a lookahead round) -// -void Internal::init_probehbr_lrat () { - if (!lrat || opts.probehbr) - return; - const size_t size = 2 * (1 + (size_t) max_var); - probehbr_chains.resize (size); - for (size_t i = 0; i < size; i++) { - probehbr_chains[i].resize (size); - // commented because not needed... should be empty already - /* - for (size_t j = 0; j < size; j++) { - vector empty; - probehbr_chains[i][j] = empty; - } - */ - } -} - -// sets lrat_chain to the stored chain in probehbr_chains. -// this leads to conflict with unit reason uip -// -void Internal::get_probehbr_lrat (int lit, int uip) { - if (!lrat || opts.probehbr) - return; - CADICAL_assert (lit); - CADICAL_assert (lrat_chain.empty ()); - CADICAL_assert (val (uip) < 0); - lrat_chain = probehbr_chains[vlit (lit)][vlit (uip)]; - int64_t id = unit_id (-uip); - lrat_chain.push_back (id); -} - -// sets the corresponding probehbr_chain to what is currently stored in -// lrat_chain. also clears lrat_chain. -// -void Internal::set_probehbr_lrat (int lit, int uip) { - if (!lrat || opts.probehbr) - return; - CADICAL_assert (lit); - CADICAL_assert (lrat_chain.size ()); - CADICAL_assert (probehbr_chains[vlit (lit)][vlit (uip)].empty ()); - probehbr_chains[vlit (lit)][vlit (uip)] = lrat_chain; - lrat_chain.clear (); -} - -// compute lrat_chain for the part of the tree from lit to dom -// use mini_chain because it needs to be reversed -// -void Internal::probe_dominator_lrat (int dom, Clause *reason) { - if (!lrat || !dom) - return; - LOG (reason, "probe dominator LRAT for %d from", dom); - for (const auto lit : *reason) { - if (val (lit) >= 0) - continue; - const auto other = -lit; - if (other == dom) - continue; - Flags &f = flags (other); - if (f.seen) - continue; - f.seen = true; - analyzed.push_back (other); - Var u = var (other); - if (u.level) { - if (!u.reason) { - LOG ("this may be a problem %d", other); - continue; - } - probe_dominator_lrat (dom, u.reason); - continue; - } - int64_t id = unit_id (other); - lrat_chain.push_back (id); - } - lrat_chain.push_back (reason->id); -} - -/*------------------------------------------------------------------------*/ - -// On-the-fly (dynamic) hyper binary resolution on decision level one can -// make use of the fact that the implication graph is actually a tree. - -// Compute a dominator of two literals in the binary implication tree. - -int Internal::probe_dominator (int a, int b) { - require_mode (PROBE); - int l = a, k = b; - Var *u = &var (l), *v = &var (k); - CADICAL_assert (val (l) > 0), CADICAL_assert (val (k) > 0); - CADICAL_assert (u->level == 1), CADICAL_assert (v->level == 1); - while (l != k) { - if (u->trail > v->trail) - swap (l, k), swap (u, v); - if (!get_parent_reason_literal (l)) - return l; - int parent = get_parent_reason_literal (k); - CADICAL_assert (parent), CADICAL_assert (val (parent) > 0); - v = &var (k = parent); - CADICAL_assert (v->level == 1); - } - LOG ("dominator %d of %d and %d", l, a, b); - CADICAL_assert (val (l) > 0); - return l; -} - -// The idea of dynamic on-the-fly hyper-binary resolution came up in the -// PrecoSAT solver, where it originally was used on all decision levels. - -// It turned out, that most of the hyper-binary resolvents were generated -// during probing on decision level one anyhow. Thus this version is -// specialized to decision level one, where actually all long (non-binary) -// forcing clauses can be resolved to become binary. So if we find a clause -// which would force a new assignment at decision level one during probing -// we resolve it (the 'reason' argument) to obtain a hyper binary resolvent. -// It consists of the still unassigned literal (the new unit) and the -// negation of the unique closest dominator of the negation of all (false) -// literals in the clause (which has to exist on decision level one). - -// There are two special cases which should be mentioned: -// -// (A) The reason is already a binary clause in a certain sense, since all -// its unwatched literals are root level fixed to false. In this -// situation it would be better to shrink the clause immediately instead -// of adding a new clause consisting only of the watched literals. -// However, this would happen during the next garbage collection anyhow. -// -// (B) The resolvent subsumes the original reason clause. This is -// equivalent to the property that the negated dominator is contained in -// the original reason. Again one could in principle shrink the clause. -// -// Note that (A) is actually subsumed by (B). The possible optimization to -// shrink the clause on-the-fly is difficult (need to update 'blit' and -// 'binary' of the other watch at least) and also not really that important. -// For (B) we simply add the new binary resolvent and mark the old subsumed -// clause as garbage instead. And since in the situation of (A) the -// shrinking will be performed at the next garbage collection anyhow, we -// do not change clauses in (A). - -// The hyper binary resolvent clause is redundant unless it subsumes the -// original reason and that one is irredundant. - -// If the option 'opts.probehbr' is 'false', we actually do not add the new -// hyper binary resolvent, but simply pretend we would have added it and -// still return the dominator as new reason / parent for the new unit. - -// Finally note that adding clauses changes the watches of the propagated -// literal and thus we can not use standard iterators during probing but -// need to fall back to indices. One watch for the hyper binary resolvent -// clause is added at the end of the currently propagated watches, but its -// watch is a binary watch and will be skipped during propagating long -// clauses anyhow. - -inline int Internal::hyper_binary_resolve (Clause *reason) { - require_mode (PROBE); - CADICAL_assert (level == 1); - CADICAL_assert (reason->size > 2); - const const_literal_iterator end = reason->end (); - const int *lits = reason->literals; - const_literal_iterator k; -#ifndef CADICAL_NDEBUG - // First literal unassigned, all others false. - CADICAL_assert (!val (lits[0])); - for (k = lits + 1; k != end; k++) - CADICAL_assert (val (*k) < 0); - CADICAL_assert (var (lits[1]).level == 1); -#endif - LOG (reason, "hyper binary resolving"); - stats.hbrs++; - stats.hbrsizes += reason->size; - const int lit = lits[1]; - int dom = -lit, non_root_level_literals = 0; - for (k = lits + 2; k != end; k++) { - const int other = -*k; - CADICAL_assert (val (other) > 0); - if (!var (other).level) - continue; - dom = probe_dominator (dom, other); - non_root_level_literals++; - } - probe_reason = reason; - if (non_root_level_literals && opts.probehbr) { // !(A) - bool contained = false; - for (k = lits + 1; !contained && k != end; k++) - contained = (*k == -dom); - const bool red = !contained || reason->redundant; - if (red) - stats.hbreds++; - LOG ("new %s hyper binary resolvent %d %d", - (red ? "redundant" : "irredundant"), -dom, lits[0]); - CADICAL_assert (clause.empty ()); - clause.push_back (-dom); - clause.push_back (lits[0]); - probe_dominator_lrat (dom, reason); - if (lrat) - clear_analyzed_literals (); - Clause *c = new_hyper_binary_resolved_clause (red, 2); - probe_reason = c; - if (red) - c->hyper = true; - clause.clear (); - lrat_chain.clear (); - if (contained) { - stats.hbrsubs++; - LOG (reason, "subsumed original"); - mark_garbage (reason); - } - } else if (non_root_level_literals && lrat) { - // still calculate LRAT and remember for later - CADICAL_assert (!opts.probehbr); - probe_dominator_lrat (dom, reason); - clear_analyzed_literals (); - set_probehbr_lrat (dom, lits[0]); - } - return dom; -} - -/*------------------------------------------------------------------------*/ - -// The following functions 'probe_assign' and 'probe_propagate' are used for -// propagating during failed literal probing in simplification mode, as -// replacement of the generic propagation routine 'propagate' and -// 'search_assign'. - -// The code is mostly copied from 'propagate.cpp' and specialized. We only -// comment on the differences. More explanations are in 'propagate.cpp'. - -inline void Internal::probe_assign (int lit, int parent) { - require_mode (PROBE); - int idx = vidx (lit); - CADICAL_assert (!val (idx)); - CADICAL_assert (!flags (idx).eliminated () || !parent); - CADICAL_assert (!parent || val (parent) > 0); - Var &v = var (idx); - v.level = level; - v.trail = (int) trail.size (); - CADICAL_assert ((int) num_assigned < max_var); - num_assigned++; - v.reason = level ? probe_reason : 0; - probe_reason = 0; - set_parent_reason_literal (lit, parent); - if (!level) - learn_unit_clause (lit); - else - CADICAL_assert (level == 1); - const signed char tmp = sign (lit); - set_val (idx, tmp); - CADICAL_assert (val (lit) > 0); - CADICAL_assert (val (-lit) < 0); - trail.push_back (lit); - - // Do not save the current phase during inprocessing but remember the - // number of units on the trail of the last time this literal was - // assigned. This allows us to avoid some redundant failed literal - // probing attempts. Search for 'propfixed' in 'probe.cpp' for details. - // - if (level) - propfixed (lit) = stats.all.fixed; - - if (parent) - LOG ("probe assign %d parent %d", lit, parent); - else if (level) - LOG ("probe assign %d probe", lit); - else - LOG ("probe assign %d negated failed literal UIP", lit); -} - -void Internal::probe_assign_decision (int lit) { - require_mode (PROBE); - CADICAL_assert (!level); - CADICAL_assert (propagated == trail.size ()); - level++; - control.push_back (Level (lit, trail.size ())); - probe_assign (lit, 0); -} - -void Internal::probe_assign_unit (int lit) { - require_mode (PROBE); - CADICAL_assert (!level); - CADICAL_assert (active (lit)); - probe_assign (lit, 0); -} - -/*------------------------------------------------------------------------*/ - -// same as in propagate but inlined here -// -inline void Internal::probe_lrat_for_units (int lit) { - if (!lrat) - return; - if (level) - return; // not decision level 0 - LOG ("building chain for units"); - CADICAL_assert (lrat_chain.empty ()); - CADICAL_assert (probe_reason); - for (auto &reason_lit : *probe_reason) { - if (lit == reason_lit) - continue; - CADICAL_assert (val (reason_lit)); - if (!val (reason_lit)) - continue; - const int signed_reason_lit = val (reason_lit) * reason_lit; - int64_t id = unit_id (signed_reason_lit); - lrat_chain.push_back (id); - } - lrat_chain.push_back (probe_reason->id); -} - -/*------------------------------------------------------------------------*/ - -// This is essentially the same as 'propagate' except that we prioritize and -// always propagate binary clauses first (see our CPAIOR'13 paper on tree -// based look ahead), then immediately stop at a conflict and of course use -// 'probe_assign' instead of 'search_assign'. The binary propagation part -// is factored out too. If a new unit on decision level one is found we -// perform hyper binary resolution and thus actually build an implication -// tree instead of a DAG. Statistics counters are also different. - -inline void Internal::probe_propagate2 () { - require_mode (PROBE); - int64_t &ticks = stats.ticks.probe; - while (propagated2 != trail.size ()) { - const int lit = -trail[propagated2++]; - LOG ("probe propagating %d over binary clauses", -lit); - Watches &ws = watches (lit); - ticks += 1 + cache_lines (ws.size (), sizeof (const_watch_iterator *)); - for (const auto &w : ws) { - if (!w.binary ()) - continue; - const signed char b = val (w.blit); - if (b > 0) - continue; - ticks++; - if (b < 0) - conflict = w.clause; // but continue - else { - CADICAL_assert (lrat_chain.empty ()); - CADICAL_assert (!probe_reason); - probe_reason = w.clause; - probe_lrat_for_units (w.blit); - probe_assign (w.blit, -lit); - lrat_chain.clear (); - } - } - } -} - -bool Internal::probe_propagate () { - require_mode (PROBE); - CADICAL_assert (!unsat); - START (propagate); - int64_t before = propagated2 = propagated; - int64_t &ticks = stats.ticks.probe; - while (!conflict) { - if (propagated2 != trail.size ()) - probe_propagate2 (); - else if (propagated != trail.size ()) { - const int lit = -trail[propagated++]; - LOG ("probe propagating %d over large clauses", -lit); - Watches &ws = watches (lit); - ticks += 1 + cache_lines (ws.size (), - sizeof (sizeof (const_watch_iterator *))); - size_t i = 0, j = 0; - while (i != ws.size ()) { - const Watch w = ws[j++] = ws[i++]; - if (w.binary ()) - continue; - const signed char b = val (w.blit); - if (b > 0) - continue; - ticks++; - if (w.clause->garbage) - continue; - const literal_iterator lits = w.clause->begin (); - const int other = lits[0] ^ lits[1] ^ lit; - // lits[0] = other, lits[1] = lit; - const signed char u = val (other); - if (u > 0) - ws[j - 1].blit = other; - else { - const int size = w.clause->size; - const const_literal_iterator end = lits + size; - const literal_iterator middle = lits + w.clause->pos; - literal_iterator k = middle; - int r = 0; - signed char v = -1; - while (k != end && (v = val (r = *k)) < 0) - k++; - if (v < 0) { - k = lits + 2; - CADICAL_assert (w.clause->pos <= size); - while (k != middle && (v = val (r = *k)) < 0) - k++; - } - w.clause->pos = k - lits; - CADICAL_assert (lits + 2 <= k), CADICAL_assert (k <= w.clause->end ()); - if (v > 0) - ws[j - 1].blit = r; - else if (!v) { - ticks++; - LOG (w.clause, "unwatch %d in", r); - *k = lit; - lits[0] = other; - lits[1] = r; - watch_literal (r, lit, w.clause); - j--; - } else if (!u) { - ticks++; - if (level == 1) { - lits[0] = other, lits[1] = lit; - CADICAL_assert (lrat_chain.empty ()); - CADICAL_assert (!probe_reason); - int dom = hyper_binary_resolve (w.clause); - probe_assign (other, dom); - } else { - ticks++; - CADICAL_assert (lrat_chain.empty ()); - CADICAL_assert (!probe_reason); - probe_reason = w.clause; - probe_lrat_for_units (other); - probe_assign_unit (other); - lrat_chain.clear (); - } - probe_propagate2 (); - } else - conflict = w.clause; - } - } - if (j != i) { - while (i != ws.size ()) - ws[j++] = ws[i++]; - ws.resize (j); - } - } else - break; - } - int64_t delta = propagated2 - before; - stats.propagations.probe += delta; - if (conflict) - LOG (conflict, "conflict"); - STOP (propagate); - return !conflict; -} - -/*------------------------------------------------------------------------*/ - -// This a specialized instance of 'analyze'. - -void Internal::failed_literal (int failed) { - - LOG ("analyzing failed literal probe %d", failed); - stats.failed++; - stats.probefailed++; - - CADICAL_assert (!unsat); - CADICAL_assert (conflict); - CADICAL_assert (level == 1); - CADICAL_assert (analyzed.empty ()); - CADICAL_assert (lrat_chain.empty ()); - - START (analyze); - - LOG (conflict, "analyzing failed literal conflict"); - - int uip = 0; - for (const auto &lit : *conflict) { - const int other = -lit; - if (!var (other).level) { - CADICAL_assert (val (other) > 0); - continue; - } - uip = uip ? probe_dominator (uip, other) : other; - } - probe_dominator_lrat (uip, conflict); - if (lrat) - clear_analyzed_literals (); - - LOG ("found probing UIP %d", uip); - CADICAL_assert (uip); - - vector work; - - int parent = uip; - while (parent != failed) { - const int next = get_parent_reason_literal (parent); - parent = next; - CADICAL_assert (parent); - work.push_back (parent); - } - - backtrack (); - conflict = 0; - - CADICAL_assert (!val (uip)); - probe_assign_unit (-uip); - lrat_chain.clear (); - - if (!probe_propagate ()) - learn_empty_clause (); - - size_t j = 0; - while (!unsat && j < work.size ()) { - // CADICAL_assert (!opts.probehbr); CADICAL_assertion fails ... - const int parent = work[j++]; - const signed char tmp = val (parent); - if (tmp > 0) { - CADICAL_assert (!opts.probehbr); // ... CADICAL_assertion should hold here - get_probehbr_lrat (parent, uip); - LOG ("clashing failed parent %d", parent); - learn_empty_clause (); - } else if (tmp == 0) { - CADICAL_assert (!opts.probehbr); // ... and here - LOG ("found unassigned failed parent %d", parent); - get_probehbr_lrat (parent, uip); // this is computed during - probe_assign_unit (-parent); // propagation and can include - lrat_chain.clear (); // multiple chains where only one - if (!probe_propagate ()) - learn_empty_clause (); // is needed! - } - uip = parent; - } - work.clear (); - erase_vector (work); - - STOP (analyze); - - CADICAL_assert (unsat || val (failed) < 0); -} - -/*------------------------------------------------------------------------*/ - -bool Internal::is_binary_clause (Clause *c, int &a, int &b) { - CADICAL_assert (!level); - if (c->garbage) - return false; - int first = 0, second = 0; - for (const auto &lit : *c) { - const signed char tmp = val (lit); - if (tmp > 0) - return false; - if (tmp < 0) - continue; - if (second) - return false; - if (first) - second = lit; - else - first = lit; - } - if (!second) - return false; - a = first, b = second; - return true; -} - -// We probe on literals first, which occur more often negated and thus we -// sort the 'probes' stack in such a way that literals which occur negated -// less frequently come first. Probes are taken from the back of the stack. - -struct probe_negated_noccs_rank { - Internal *internal; - probe_negated_noccs_rank (Internal *i) : internal (i) {} - typedef size_t Type; - Type operator() (int a) const { return internal->noccs (-a); } -}; - -// Fill the 'probes' schedule. - -void Internal::generate_probes () { - - CADICAL_assert (probes.empty ()); - - int64_t &ticks = stats.ticks.probe; - - // First determine all the literals which occur in binary clauses. It is - // way faster to go over the clauses once, instead of walking the watch - // lists for each literal. - // - init_noccs (); - ticks += 1 + cache_lines (clauses.size (), sizeof (Clause *)); - for (const auto &c : clauses) { - int a, b; - ticks++; - if (!is_binary_clause (c, a, b)) - continue; - noccs (a)++; - noccs (b)++; - } - - for (auto idx : vars) { - - // Then focus on roots of the binary implication graph, which are - // literals occurring negatively in a binary clause, but not positively. - // If neither 'idx' nor '-idx' is a root it makes less sense to probe - // this variable. - - // This argument requires that equivalent literal substitution through - // 'decompose' is performed, because otherwise there might be 'cyclic - // roots' which are not tried, i.e., -1 2 0, 1 -2 0, 1 2 3 0, 1 2 -3 0. - - ticks += 2; - - const bool have_pos_bin_occs = noccs (idx) > 0; - const bool have_neg_bin_occs = noccs (-idx) > 0; - - if (have_pos_bin_occs == have_neg_bin_occs) - continue; - - int probe = have_neg_bin_occs ? idx : -idx; - - // See the discussion where 'propfixed' is used below. - // - if (propfixed (probe) >= stats.all.fixed) - continue; - - LOG ("scheduling probe %d negated occs %" PRId64 "", probe, - noccs (-probe)); - probes.push_back (probe); - } - - rsort (probes.begin (), probes.end (), probe_negated_noccs_rank (this)); - - reset_noccs (); - shrink_vector (probes); - - PHASE ("probe-round", stats.probingrounds, - "scheduled %zd literals %.0f%%", probes.size (), - percent (probes.size (), 2u * max_var)); -} - -// Follow the ideas in 'generate_probes' but flush non root probes and -// reorder remaining probes. - -void Internal::flush_probes () { - - CADICAL_assert (!probes.empty ()); - int64_t &ticks = stats.ticks.probe; - - init_noccs (); - ticks += 1 + cache_lines (clauses.size (), sizeof (Clause *)); - for (const auto &c : clauses) { - int a, b; - ticks++; - if (!is_binary_clause (c, a, b)) - continue; - noccs (a)++; - noccs (b)++; - } - - const auto eop = probes.end (); - auto j = probes.begin (); - for (auto i = j; i != eop; i++) { - int lit = *i; - if (!active (lit)) - continue; - ticks += 2; - const bool have_pos_bin_occs = noccs (lit) > 0; - const bool have_neg_bin_occs = noccs (-lit) > 0; - if (have_pos_bin_occs == have_neg_bin_occs) - continue; - if (have_pos_bin_occs) - lit = -lit; - CADICAL_assert (!noccs (lit)), CADICAL_assert (noccs (-lit) > 0); - if (propfixed (lit) >= stats.all.fixed) - continue; - LOG ("keeping probe %d negated occs %" PRId64 "", lit, noccs (-lit)); - *j++ = lit; - } - size_t remain = j - probes.begin (); -#ifndef CADICAL_QUIET - size_t flushed = probes.size () - remain; -#endif - probes.resize (remain); - - rsort (probes.begin (), probes.end (), probe_negated_noccs_rank (this)); - - reset_noccs (); - shrink_vector (probes); - - PHASE ("probe-round", stats.probingrounds, - "flushed %zd literals %.0f%% remaining %zd", flushed, - percent (flushed, remain + flushed), remain); -} - -int Internal::next_probe () { - - int generated = 0; - - for (;;) { - - if (probes.empty ()) { - if (generated++) - return 0; - generate_probes (); - } - - while (!probes.empty ()) { - - int probe = probes.back (); - probes.pop_back (); - - // Eliminated or assigned. - // - if (!active (probe)) - continue; - - // There is now new unit since the last time we propagated this probe, - // thus we propagated it before without obtaining a conflict and - // nothing changed since then. Thus there is no need to propagate it - // again. This observation was independently made by Partik Simons - // et.al. in the context of implementing 'smodels' (see for instance - // Alg. 4 in his JAIR article from 2002) and it has also been - // contributed to the thesis work of Yacine Boufkhad. - // - if (propfixed (probe) >= stats.all.fixed) - continue; - - return probe; - } - } -} - -bool Internal::probe () { - - if (!opts.probe) - return false; - if (unsat) - return false; - if (terminated_asynchronously ()) - return false; - - SET_EFFORT_LIMIT (limit, probe, true); - - START_SIMPLIFIER (probe, PROBE); - stats.probingrounds++; - - // Probing is limited in terms of non-probing propagations - // 'stats.propagations'. We allow a certain percentage 'opts.probeeffort' - // (say %5) of probing propagations in each probing with a lower bound of - // 'opts.probmineff'. - // - - PHASE ("probe-round", stats.probingrounds, - "probing limit of %" PRId64 " propagations ", limit); - - int old_failed = stats.failed; -#ifndef CADICAL_QUIET - int64_t old_probed = stats.probed; -#endif - int64_t old_hbrs = stats.hbrs; - - if (!probes.empty ()) - flush_probes (); - - // We reset 'propfixed' since there was at least another conflict thus - // a new learned clause, which might produce new propagations (and hyper - // binary resolvents). During 'generate_probes' we keep the old value. - // - for (auto idx : vars) - propfixed (idx) = propfixed (-idx) = -1; - - CADICAL_assert (unsat || propagated == trail.size ()); - propagated = propagated2 = trail.size (); - - int probe; - init_probehbr_lrat (); - while (!unsat && !terminated_asynchronously () && - stats.ticks.probe < limit && (probe = next_probe ())) { - stats.probed++; - LOG ("probing %d", probe); - probe_assign_decision (probe); - if (probe_propagate ()) - backtrack (); - else - failed_literal (probe); - clean_probehbr_lrat (); - } - - if (unsat) - LOG ("probing derived empty clause"); - else if (propagated < trail.size ()) { - LOG ("probing produced %zd units", - (size_t) (trail.size () - propagated)); - if (!propagate ()) { - LOG ("propagating units after probing results in empty clause"); - learn_empty_clause (); - } else - sort_watches (); - } - - int failed = stats.failed - old_failed; -#ifndef CADICAL_QUIET - int64_t probed = stats.probed - old_probed; -#endif - int64_t hbrs = stats.hbrs - old_hbrs; - - PHASE ("probe-round", stats.probingrounds, - "probed %" PRId64 " and found %d failed literals", probed, failed); - - if (hbrs) - PHASE ("probe-round", stats.probingrounds, - "found %" PRId64 " hyper binary resolvents", hbrs); - - STOP_SIMPLIFIER (probe, PROBE); - - report ('p', !opts.reportall && !(unsat + failed + hbrs)); - - return !unsat && failed; -} - -/*------------------------------------------------------------------------*/ - -// This schedules a number of inprocessing techniques. -// These range from very cheap and beneficial (decompose) to -// more expensive and sometimes less beneficial. We want to limit -// expensive techniques to some fraction of total time or search time. -// this is done using 'ticks'. -// Generally, there are options for each of the techniques to set the -// efficiency, i.e., the fraction of ticks they are allowed as budget. -// Whenever e.g. vivify is called, the budget is calculated from the -// search ticks that have passed since the last vivify round and this -// efficiency. -// We want to be able to run inprocessing frequently, without it dominating -// runtimes. This entire inprocessing scheme is scheduled after a certain -// amount of conflicts were found, the gap between two inprocessing rounds -// increasing by a constant number each time. In effect, the number of -// inprocessing rounds is allways the square root of the number of conflicts -// with some constant factor. -// This factor can also be with the option 'inprobeint' -// Some of the techniques are not run always, for different reasons. -// 'factor' or BVA depends on certain structures of the irredundant clauses -// and as such will only be run when new irredundant clauses are derived or -// it was not able to finish with the entire search space. -// 'sweeping' is especially usefull on certain classes of formulas, and uses -// a increasing or decreasing delay that depends on how usefull it was. -// In cases where it is less usefull, we obviously want to reset the budged, -// even if the routine was delayed. -// Additionally 'vivify', 'sweep' and 'factor' can also have a big initial -// overhead in setting up the datastructures. This has to be accounted for -// with the 'ticks', however, since inprocessing is done frequently, this -// overhead is too expensive to pay. So instead, we accumulate the budget -// of 'ticks' and delay the technique until it passes a certain threshhold, -// which depends on the the cost of initialization. Note that in the case of -// sweeping, we have two different delays, one which resets the budged, and -// one which passes it to the next round. In this case the former takes -// precendent, until we would run sweeping once, at which point the focus -// switches to the latter delay until the budget is big enough, such that -// sweeping can be run. Then we switch back to the other delay. - -void CaDiCaL::Internal::inprobe (bool update_limits) { - - if (unsat) - return; - if (level) - backtrack (); - if (!propagate ()) { - learn_empty_clause (); - return; - } - - stats.inprobingphases++; - if (external_prop) { - CADICAL_assert (!level); - private_steps = true; - } - const int before = active (); - const int before_extended = stats.variables_extension; - - // schedule of inprobing techniques. - // - { - mark_duplicated_binary_clauses_as_garbage (); - decompose (); - if (ternary ()) - decompose (); // If we derived a binary clause - if (probe ()) - decompose (); - - if (extract_gates ()) - decompose (); - if (sweep ()) // full occurrence list - decompose (); // ... and (ELS) afterwards. - (void) vivify (); // resets watches - transred (); // builds big. - factor (); // resets watches, partial occurrence list - } - - if (external_prop) { - CADICAL_assert (!level); - private_steps = false; - } - - if (!update_limits) - return; - - const int after = active (); - const int after_extended = stats.variables_extension; - const int diff_extended = after_extended - before_extended; - CADICAL_assert (diff_extended >= 0); - const int removed = before - after + diff_extended; - CADICAL_assert (removed >= 0); - - if (removed) { - stats.inprobesuccess++; - PHASE ("probe-phase", stats.inprobingphases, - "successfully removed %d active variables %.0f%%", removed, - percent (removed, before)); - } else - PHASE ("probe-phase", stats.inprobingphases, - "could not remove any active variable"); - - const int64_t delta = - 25 * opts.inprobeint * log10 (stats.inprobingphases + 9); - lim.inprobe = stats.conflicts + delta; - - PHASE ("probe-phase", stats.inprobingphases, - "new limit at %" PRId64 " conflicts after %" PRId64 " conflicts", - lim.inprobe, delta); - - last.inprobe.reductions = stats.reductions; -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_profile.cpp b/src/sat/cadical/cadical_profile.cpp deleted file mode 100644 index a95c97661..000000000 --- a/src/sat/cadical/cadical_profile.cpp +++ /dev/null @@ -1,113 +0,0 @@ -#include "global.h" - -#ifndef CADICAL_QUIET - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -// Initialize all profile counters with constant name and profiling level. - -Profiles::Profiles (Internal *s) - : internal (s) -#define PROFILE(NAME, LEVEL) , NAME (#NAME, LEVEL) - PROFILES -#undef PROFILE -{ -} - -void Internal::start_profiling (Profile &profile, double s) { - CADICAL_assert (profile.level <= opts.profile); - CADICAL_assert (!profile.active); - profile.started = s; - profile.active = true; -} - -void Internal::stop_profiling (Profile &profile, double s) { - CADICAL_assert (profile.level <= opts.profile); - CADICAL_assert (profile.active); - profile.value += s - profile.started; - profile.active = false; -} - -double Internal::update_profiles () { - double now = time (); -#define PROFILE(NAME, LEVEL) \ - do { \ - Profile &profile = profiles.NAME; \ - if (profile.active) { \ - CADICAL_assert (profile.level <= opts.profile); \ - profile.value += now - profile.started; \ - profile.started = now; \ - } \ - } while (0); - PROFILES -#undef PROFILE - return now; -} - -double Internal::solve_time () { - (void) update_profiles (); - return profiles.solve.value; -} - -#define PRT(S, T) \ - MSG ("%s" S "%s", tout.magenta_code (), T, tout.normal_code ()) - -void Internal::print_profile () { - double now = update_profiles (); - const char *time_type = opts.realtime ? "real" : "process"; - SECTION ("run-time profiling"); - PRT ("%s time taken by individual solving procedures", time_type); - PRT ("(percentage relative to %s time for solving)", time_type); - LINE (); - const size_t size = sizeof profiles / sizeof (Profile); - struct Profile *profs[size]; - size_t n = 0; -#define PROFILE(NAME, LEVEL) \ - do { \ - if (LEVEL > opts.profile) \ - break; \ - Profile *p = &profiles.NAME; \ - if (p == &profiles.solve) \ - break; \ - if (!profiles.NAME.value && p != &profiles.parse && \ - p != &profiles.search && p != &profiles.simplify) \ - break; \ - profs[n++] = p; \ - } while (0); - PROFILES -#undef PROFILE - - CADICAL_assert (n <= size); - - // Explicit bubble sort to avoid heap allocation since 'print_profile' - // is also called during catching a signal after out of heap memory. - // This only makes sense if 'profs' is allocated on the stack, and - // not the heap, which should be the case. - - double solve = profiles.solve.value; - - for (size_t i = 0; i < n; i++) { - for (size_t j = i + 1; j < n; j++) - if (profs[j]->value > profs[i]->value) - swap (profs[i], profs[j]); - MSG ("%12.2f %7.2f%% %s", profs[i]->value, - percent (profs[i]->value, solve), profs[i]->name); - } - - MSG (" ================================="); - MSG ("%12.2f %7.2f%% solve", solve, percent (solve, now)); - - LINE (); - PRT ("last line shows %s time for solving", time_type); - PRT ("(percentage relative to total %s time)", time_type); -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END - -#endif // ifndef CADICAL_QUIET diff --git a/src/sat/cadical/cadical_proof.cpp b/src/sat/cadical/cadical_proof.cpp deleted file mode 100644 index 13c9a1a5d..000000000 --- a/src/sat/cadical/cadical_proof.cpp +++ /dev/null @@ -1,663 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -using namespace std; - -/*------------------------------------------------------------------------*/ - -// Enable proof logging and checking by allocating a 'Proof' object. - -void Internal::new_proof_on_demand () { - if (!proof) { - LOG ("connecting proof to internal solver"); - proof = new Proof (this); - } -} - -void Internal::resize_unit_clauses_idx () { - size_t new_vsize = vsize ? 2 * vsize : 1 + (size_t) max_var; - unit_clauses_idx.resize (2 * new_vsize, 0); -} - -void Internal::force_lrat () { - if (lrat) - return; - CADICAL_assert (proof); - lrat = true; -} - -void Internal::connect_proof_tracer (Tracer *tracer, bool antecedents, - bool finalize_clauses) { - new_proof_on_demand (); - if (antecedents) - force_lrat (); - if (finalize_clauses) - frat = true; - resize_unit_clauses_idx (); - proof->connect (tracer); - tracers.push_back (tracer); -} - -void Internal::connect_proof_tracer (InternalTracer *tracer, - bool antecedents, - bool finalize_clauses) { - new_proof_on_demand (); - if (antecedents) - force_lrat (); - if (finalize_clauses) - frat = true; - resize_unit_clauses_idx (); - tracer->connect_internal (this); - proof->connect (tracer); - tracers.push_back (tracer); -} - -void Internal::connect_proof_tracer (StatTracer *tracer, bool antecedents, - bool finalize_clauses) { - new_proof_on_demand (); - if (antecedents) - force_lrat (); - if (finalize_clauses) - frat = true; - resize_unit_clauses_idx (); - tracer->connect_internal (this); - proof->connect (tracer); - stat_tracers.push_back (tracer); -} - -void Internal::connect_proof_tracer (FileTracer *tracer, bool antecedents, - bool finalize_clauses) { - new_proof_on_demand (); - if (antecedents) - force_lrat (); - if (finalize_clauses) - frat = true; - resize_unit_clauses_idx (); - tracer->connect_internal (this); - proof->connect (tracer); - file_tracers.push_back (tracer); -} - -bool Internal::disconnect_proof_tracer (Tracer *tracer) { - auto it = std::find (tracers.begin (), tracers.end (), tracer); - if (it != tracers.end ()) { - tracers.erase (it); - CADICAL_assert (proof); - proof->disconnect (tracer); - return true; - } - return false; -} - -bool Internal::disconnect_proof_tracer (StatTracer *tracer) { - auto it = std::find (stat_tracers.begin (), stat_tracers.end (), tracer); - if (it != stat_tracers.end ()) { - stat_tracers.erase (it); - CADICAL_assert (proof); - proof->disconnect (tracer); - return true; - } - return false; -} - -bool Internal::disconnect_proof_tracer (FileTracer *tracer) { - auto it = std::find (file_tracers.begin (), file_tracers.end (), tracer); - if (it != file_tracers.end ()) { - file_tracers.erase (it); - CADICAL_assert (proof); - proof->disconnect (tracer); - return true; - } - return false; -} - -void Proof::disconnect (Tracer *t) { - tracers.erase (std::remove (tracers.begin (), tracers.end (), t), - tracers.end ()); -} - -// Enable proof tracing. - -void Internal::trace (File *file) { - if (opts.veripb) { - LOG ("PROOF connecting VeriPB tracer"); - bool antecedents = opts.veripb == 1 || opts.veripb == 2; - bool deletions = opts.veripb == 2 || opts.veripb == 4; - FileTracer *ft = - new VeripbTracer (this, file, opts.binary, antecedents, deletions); - connect_proof_tracer (ft, antecedents); - } else if (opts.frat) { - LOG ("PROOF connecting FRAT tracer"); - bool antecedents = opts.frat == 1; - resize_unit_clauses_idx (); - FileTracer *ft = - new FratTracer (this, file, opts.binary, opts.frat == 1); - connect_proof_tracer (ft, antecedents, true); - } else if (opts.lrat) { - LOG ("PROOF connecting LRAT tracer"); - FileTracer *ft = new LratTracer (this, file, opts.binary); - connect_proof_tracer (ft, true); - } else if (opts.idrup) { - LOG ("PROOF connecting IDRUP tracer"); - FileTracer *ft = new IdrupTracer (this, file, opts.binary); - connect_proof_tracer (ft, true); - } else if (opts.lidrup) { - LOG ("PROOF connecting LIDRUP tracer"); - FileTracer *ft = new LidrupTracer (this, file, opts.binary); - connect_proof_tracer (ft, true); - } else { - LOG ("PROOF connecting DRAT tracer"); - FileTracer *ft = new DratTracer (this, file, opts.binary); - connect_proof_tracer (ft, false); - } -} - -// Enable proof checking. - -void Internal::check () { - new_proof_on_demand (); - if (opts.checkproof > 1) { - StatTracer *lratchecker = new LratChecker (this); - DeferDeletePtr delete_lratchecker ( - (LratChecker *) lratchecker); - LOG ("PROOF connecting LRAT proof checker"); - force_lrat (); - frat = true; - resize_unit_clauses_idx (); - proof->connect (lratchecker); - stat_tracers.push_back (lratchecker); - delete_lratchecker.release (); - } - if (opts.checkproof == 1 || opts.checkproof == 3) { - StatTracer *checker = new Checker (this); - DeferDeletePtr delete_checker ((Checker *) checker); - LOG ("PROOF connecting proof checker"); - proof->connect (checker); - stat_tracers.push_back (checker); - delete_checker.release (); - } -} - -// We want to close a proof trace and stop checking as soon we are done. - -void Internal::close_trace (bool print) { - for (auto &tracer : file_tracers) - tracer->close (print); -} - -// We can flush a proof trace file before actually closing it. - -void Internal::flush_trace (bool print) { - for (auto &tracer : file_tracers) - tracer->flush (print); -} - -/*------------------------------------------------------------------------*/ - -Proof::Proof (Internal *s) : internal (s) { LOG ("PROOF new"); } - -Proof::~Proof () { LOG ("PROOF delete"); } - -/*------------------------------------------------------------------------*/ - -inline void Proof::add_literal (int internal_lit) { - const int external_lit = internal->externalize (internal_lit); - clause.push_back (external_lit); -} - -inline void Proof::add_literals (Clause *c) { - for (auto const &lit : *c) - add_literal (lit); -} - -inline void Proof::add_literals (const vector &c) { - for (auto const &lit : c) - add_literal (lit); -} - -/*------------------------------------------------------------------------*/ - -void Proof::add_original_clause (int64_t id, bool r, const vector &c) { - LOG (c, "PROOF adding original internal clause"); - add_literals (c); - clause_id = id; - redundant = r; - add_original_clause (); -} - -void Proof::add_external_original_clause (int64_t id, bool r, - const vector &c, - bool restore) { - // literals of c are already external - CADICAL_assert (clause.empty ()); - for (auto const &lit : c) - clause.push_back (lit); - clause_id = id; - redundant = r; - add_original_clause (restore); -} - -void Proof::delete_external_original_clause (int64_t id, bool r, - const vector &c) { - // literals of c are already external - CADICAL_assert (clause.empty ()); - for (auto const &lit : c) - clause.push_back (lit); - clause_id = id; - redundant = r; - delete_clause (); -} - -void Proof::add_derived_empty_clause (int64_t id, - const vector &chain) { - LOG ("PROOF adding empty clause"); - CADICAL_assert (clause.empty ()); - CADICAL_assert (proof_chain.empty ()); - for (const auto &cid : chain) - proof_chain.push_back (cid); - clause_id = id; - redundant = false; - add_derived_clause (); -} - -void Proof::add_derived_unit_clause (int64_t id, int internal_unit, - const vector &chain) { - LOG ("PROOF adding unit clause %d", internal_unit); - CADICAL_assert (proof_chain.empty ()); - CADICAL_assert (clause.empty ()); - add_literal (internal_unit); - for (const auto &cid : chain) - proof_chain.push_back (cid); - clause_id = id; - redundant = false; - add_derived_clause (); -} - -/*------------------------------------------------------------------------*/ - -void Proof::add_derived_clause (Clause *c, const vector &chain) { - LOG (c, "PROOF adding to proof derived"); - CADICAL_assert (clause.empty ()); - CADICAL_assert (proof_chain.empty ()); - add_literals (c); - for (const auto &cid : chain) - proof_chain.push_back (cid); - clause_id = c->id; - redundant = c->redundant; - add_derived_clause (); -} - -void Proof::add_derived_clause (int64_t id, bool r, const vector &c, - const vector &chain) { - LOG (c, "PROOF adding derived clause"); - CADICAL_assert (clause.empty ()); - CADICAL_assert (proof_chain.empty ()); - for (const auto &lit : c) - add_literal (lit); - for (const auto &cid : chain) - proof_chain.push_back (cid); - clause_id = id; - redundant = r; - add_derived_clause (); -} - -void Proof::add_assumption_clause (int64_t id, const vector &c, - const vector &chain) { - // literals of c are already external - CADICAL_assert (clause.empty ()); - CADICAL_assert (proof_chain.empty ()); - for (const auto &lit : c) - clause.push_back (lit); - for (const auto &cid : chain) - proof_chain.push_back (cid); - clause_id = id; - add_assumption_clause (); -} - -void Proof::add_assumption (int a) { - // a is already external - CADICAL_assert (clause.empty ()); - CADICAL_assert (proof_chain.empty ()); - clause.push_back (a); - add_assumption (); -} - -void Proof::add_constraint (const vector &c) { - // literals of c are already external - CADICAL_assert (clause.empty ()); - CADICAL_assert (proof_chain.empty ()); - for (const auto &lit : c) - clause.push_back (lit); - add_constraint (); -} - -void Proof::add_assumption_clause (int64_t id, int lit, - const vector &chain) { - CADICAL_assert (clause.empty ()); - CADICAL_assert (proof_chain.empty ()); - clause.push_back (lit); - for (const auto &cid : chain) - proof_chain.push_back (cid); - clause_id = id; - add_assumption_clause (); -} - -void Proof::delete_clause (Clause *c) { - LOG (c, "PROOF deleting from proof"); - clause.clear (); // Can be non-empty if an allocation fails during adding. - add_literals (c); - clause_id = c->id; - redundant = c->redundant; - delete_clause (); // Increments 'statistics.deleted'. -} - -void Proof::delete_clause (int64_t id, bool r, const vector &c) { - LOG (c, "PROOF deleting from proof"); - CADICAL_assert (clause.empty ()); - add_literals (c); - clause_id = id; - redundant = r; - delete_clause (); // Increments 'statistics.deleted'. -} - -void Proof::weaken_minus (Clause *c) { - LOG (c, "PROOF weaken minus of"); - CADICAL_assert (clause.empty ()); - add_literals (c); - clause_id = c->id; - weaken_minus (); -} - -void Proof::weaken_minus (int64_t id, const vector &c) { - LOG (c, "PROOF deleting from proof"); - CADICAL_assert (clause.empty ()); - add_literals (c); - clause_id = id; - weaken_minus (); -} - -void Proof::weaken_plus (Clause *c) { - weaken_minus (c); - delete_clause (c); // Increments 'statistics.deleted'. -} - -void Proof::weaken_plus (int64_t id, const vector &c) { - weaken_minus (id, c); - delete_clause (id, false, c); // Increments 'statistics.deleted'. -} - -void Proof::delete_unit_clause (int64_t id, const int lit) { - LOG ("PROOF deleting unit from proof %d", lit); - CADICAL_assert (clause.empty ()); - add_literal (lit); - clause_id = id; - redundant = false; - delete_clause (); -} - -void Proof::finalize_clause (Clause *c) { - LOG (c, "PROOF finalizing clause"); - CADICAL_assert (clause.empty ()); - add_literals (c); - clause_id = c->id; - finalize_clause (); -} - -void Proof::finalize_clause (int64_t id, const vector &c) { - LOG (c, "PROOF finalizing clause"); - CADICAL_assert (clause.empty ()); - for (const auto &lit : c) - add_literal (lit); - clause_id = id; - finalize_clause (); -} - -void Proof::finalize_unit (int64_t id, int lit) { - LOG ("PROOF finalizing clause %d", lit); - CADICAL_assert (clause.empty ()); - add_literal (lit); - clause_id = id; - finalize_clause (); -} - -void Proof::finalize_external_unit (int64_t id, int lit) { - LOG ("PROOF finalizing clause %d", lit); - CADICAL_assert (clause.empty ()); - clause.push_back (lit); - clause_id = id; - finalize_clause (); -} - -/*------------------------------------------------------------------------*/ - -// During garbage collection clauses are shrunken by removing falsified -// literals. To avoid copying the clause, we provide a specialized tracing -// function here, which traces the required 'add' and 'remove' operations. - -void Proof::flush_clause (Clause *c) { - LOG (c, "PROOF flushing falsified literals in"); - CADICAL_assert (clause.empty ()); - const bool antecedents = (internal->lrat || internal->frat); - for (int i = 0; i < c->size; i++) { - int internal_lit = c->literals[i]; - if (internal->fixed (internal_lit) < 0) { - if (antecedents) { - int64_t id = internal->unit_id (-internal_lit); - proof_chain.push_back (id); - } - continue; - } - add_literal (internal_lit); - } - proof_chain.push_back (c->id); - redundant = c->redundant; - int64_t id = ++internal->clause_id; - clause_id = id; - add_derived_clause (); - delete_clause (c); - c->id = id; -} - -// While strengthening clauses, e.g., through self-subsuming resolutions, -// during subsumption checking, we have a similar situation, except that we -// have to remove exactly one literal. Again the following function allows -// to avoid copying the clause and instead provides tracing of the required -// 'add' and 'remove' operations. - -void Proof::strengthen_clause (Clause *c, int remove, - const vector &chain) { - LOG (c, "PROOF strengthen by removing %d in", remove); - CADICAL_assert (clause.empty ()); - for (int i = 0; i < c->size; i++) { - int internal_lit = c->literals[i]; - if (internal_lit == remove) - continue; - add_literal (internal_lit); - } - int64_t id = ++internal->clause_id; - clause_id = id; - redundant = c->redundant; - for (const auto &cid : chain) - proof_chain.push_back (cid); - add_derived_clause (); - delete_clause (c); - c->id = id; -} - -void Proof::otfs_strengthen_clause (Clause *c, const std::vector &old, - const vector &chain) { - LOG (c, "PROOF otfs strengthen"); - CADICAL_assert (clause.empty ()); - for (int i = 0; i < c->size; i++) { - int internal_lit = c->literals[i]; - add_literal (internal_lit); - } - int64_t id = ++internal->clause_id; - clause_id = id; - redundant = c->redundant; - for (const auto &cid : chain) - proof_chain.push_back (cid); - add_derived_clause (); - delete_clause (c->id, c->redundant, old); - c->id = id; -} - -void Proof::strengthen (int64_t id) { - clause_id = id; - strengthen (); -} - -/*------------------------------------------------------------------------*/ - -void Proof::add_original_clause (bool restore) { - LOG (clause, "PROOF adding original external clause"); - CADICAL_assert (clause_id); - - for (auto &tracer : tracers) { - tracer->add_original_clause (clause_id, false, clause, restore); - } - clause.clear (); - clause_id = 0; -} - -void Proof::add_derived_clause () { - LOG (clause, "PROOF adding derived external clause (redundant: %d)", - redundant); - CADICAL_assert (clause_id); - for (auto &tracer : tracers) { - tracer->add_derived_clause (clause_id, redundant, clause, proof_chain); - } - proof_chain.clear (); - clause.clear (); - clause_id = 0; -} - -void Proof::delete_clause () { - LOG (clause, "PROOF deleting external clause"); - for (auto &tracer : tracers) { - tracer->delete_clause (clause_id, redundant, clause); - } - clause.clear (); - clause_id = 0; -} - -void Proof::demote_clause () { - LOG (clause, "PROOF demoting external clause"); - CADICAL_assert (!redundant); - for (auto &tracer : tracers) { - tracer->demote_clause (clause_id, clause); - } - clause.clear (); - clause_id = 0; -} - -void Proof::weaken_minus () { - LOG (clause, "PROOF marking as clause to restore"); - for (auto &tracer : tracers) { - tracer->weaken_minus (clause_id, clause); - } - clause.clear (); - clause_id = 0; -} - -void Proof::strengthen () { - LOG ("PROOF strengthen clause with id %" PRId64, clause_id); - for (auto &tracer : tracers) { - tracer->strengthen (clause_id); - } - clause_id = 0; -} - -void Proof::finalize_clause () { - for (auto &tracer : tracers) { - tracer->finalize_clause (clause_id, clause); - } - clause.clear (); - clause_id = 0; -} - -void Proof::add_assumption_clause () { - LOG (clause, "PROOF adding assumption clause"); - for (auto &tracer : tracers) { - tracer->add_assumption_clause (clause_id, clause, proof_chain); - } - proof_chain.clear (); - clause.clear (); - clause_id = 0; -} - -void Proof::add_assumption () { - LOG (clause, "PROOF adding assumption"); - CADICAL_assert (clause.size () == 1); - for (auto &tracer : tracers) { - tracer->add_assumption (clause.back ()); - } - clause.clear (); -} - -void Proof::add_constraint () { - LOG (clause, "PROOF adding constraint"); - for (auto &tracer : tracers) { - tracer->add_constraint (clause); - } - clause.clear (); -} - -void Proof::reset_assumptions () { - LOG ("PROOF reset assumptions"); - for (auto &tracer : tracers) { - tracer->reset_assumptions (); - } -} - -void Proof::report_status (int status, int64_t id) { - LOG ("PROOF reporting status %d", status); - for (auto &tracer : tracers) { - tracer->report_status (status, id); - } -} - -void Proof::begin_proof (int64_t id) { - LOG (clause, "PROOF begin proof"); - for (auto &tracer : tracers) { - tracer->begin_proof (id); - } -} - -void Proof::solve_query () { - LOG (clause, "PROOF solve query"); - for (auto &tracer : tracers) { - tracer->solve_query (); - } -} - -void Proof::conclude_unsat (ConclusionType con, - const vector &conclusion) { - LOG (clause, "PROOF conclude unsat"); - for (auto &tracer : tracers) { - tracer->conclude_unsat (con, conclusion); - } -} - -void Proof::conclude_sat (const vector &model) { - LOG (clause, "PROOF conclude sat"); - for (auto &tracer : tracers) { - tracer->conclude_sat (model); - } -} - -void Proof::conclude_unknown (const vector &trail) { - LOG (clause, "PROOF conclude unknown"); - for (auto &tracer : tracers) { - tracer->conclude_unknown (trail); - } -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_propagate.cpp b/src/sat/cadical/cadical_propagate.cpp deleted file mode 100644 index a4f21ee6a..000000000 --- a/src/sat/cadical/cadical_propagate.cpp +++ /dev/null @@ -1,586 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -/*------------------------------------------------------------------------*/ - -// We are using the address of 'decision_reason' as pseudo reason for -// decisions to distinguish assignment decisions from other assignments. -// Before we added chronological backtracking all learned units were -// assigned at decision level zero ('Solver.level == 0') and we just used a -// zero pointer as reason. After allowing chronological backtracking units -// were also assigned at higher decision level (but with assignment level -// zero), and it was not possible anymore to just distinguish the case -// 'unit' versus 'decision' by just looking at the current level. Both had -// a zero pointer as reason. Now only units have a zero reason and -// decisions need to use the pseudo reason 'decision_reason'. - -// External propagation steps use the pseudo reason 'external_reason'. -// The corresponding actual reason clauses are learned only when they are -// relevant in conflict analysis or in root-level fixing steps. - -static Clause decision_reason_clause; -static Clause *decision_reason = &decision_reason_clause; - -// If chronological backtracking is used the actual assignment level might -// be lower than the current decision level. In this case the assignment -// level is defined as the maximum level of the literals in the reason -// clause except the literal for which the clause is a reason. This -// function determines this assignment level. For non-chronological -// backtracking as in classical CDCL this function always returns the -// current decision level, the concept of assignment level does not make -// sense, and accordingly this function can be skipped. - -// In case of external propagation, it is implicitly assumed that the -// assignment level is the level of the literal (since the reason clause, -// i.e., the set of other literals, is unknown). - -inline int Internal::assignment_level (int lit, Clause *reason) { - - CADICAL_assert (opts.chrono || external_prop); - if (!reason || reason == external_reason) - return level; - - int res = 0; - - for (const auto &other : *reason) { - if (other == lit) - continue; - CADICAL_assert (val (other)); - int tmp = var (other).level; - if (tmp > res) - res = tmp; - } - - return res; -} - -// calculate lrat_chain -// -void Internal::build_chain_for_units (int lit, Clause *reason, - bool forced) { - if (!lrat) - return; - if (opts.chrono && assignment_level (lit, reason) && !forced) - return; - else if (!opts.chrono && level && !forced) - return; // not decision level 0 - CADICAL_assert (lrat_chain.empty ()); - for (auto &reason_lit : *reason) { - if (lit == reason_lit) - continue; - CADICAL_assert (val (reason_lit)); - if (!val (reason_lit)) - continue; - const int signed_reason_lit = val (reason_lit) * reason_lit; - int64_t id = unit_id (signed_reason_lit); - lrat_chain.push_back (id); - } - lrat_chain.push_back (reason->id); -} - -// same code as above but reason is assumed to be conflict and lit is not -// needed -// -void Internal::build_chain_for_empty () { - if (!lrat || !lrat_chain.empty ()) - return; - CADICAL_assert (!level); - CADICAL_assert (lrat_chain.empty ()); - CADICAL_assert (conflict); - LOG (conflict, "lrat for global empty clause with conflict"); - for (auto &lit : *conflict) { - CADICAL_assert (val (lit) < 0); - int64_t id = unit_id (-lit); - lrat_chain.push_back (id); - } - lrat_chain.push_back (conflict->id); -} - -/*------------------------------------------------------------------------*/ - -inline void Internal::search_assign (int lit, Clause *reason) { - - if (level) - require_mode (SEARCH); - - const int idx = vidx (lit); - const bool from_external = reason == external_reason; - CADICAL_assert (!val (idx)); - CADICAL_assert (!flags (idx).eliminated () || reason == decision_reason || - reason == external_reason); - Var &v = var (idx); - int lit_level; - CADICAL_assert (!lrat || level || reason == external_reason || - reason == decision_reason || !lrat_chain.empty ()); - // The following cases are explained in the two comments above before - // 'decision_reason' and 'assignment_level'. - // - // External decision reason means that the propagation was done by - // an external propagation and the reason clause not known (yet). - // In that case it is assumed that the propagation is NOT out of - // order (i.e. lit_level = level), because due to lazy explanation, - // we can not calculate the real assignment level. - // The function assignment_level () will also assign the current level - // to literals with external reason. - if (!reason) - lit_level = 0; // unit - else if (reason == decision_reason) - lit_level = level, reason = 0; - else if (opts.chrono) - lit_level = assignment_level (lit, reason); - else - lit_level = level; - if (!lit_level) - reason = 0; - - v.level = lit_level; - v.trail = trail.size (); - v.reason = reason; - CADICAL_assert ((int) num_assigned < max_var); - CADICAL_assert (num_assigned == trail.size ()); - num_assigned++; - if (!lit_level && !from_external) - learn_unit_clause (lit); // increases 'stats.fixed' - CADICAL_assert (lit_level || !from_external); - const signed char tmp = sign (lit); - set_val (idx, tmp); - CADICAL_assert (val (lit) > 0); // Just a bit paranoid but useful. - CADICAL_assert (val (-lit) < 0); // Ditto. - if (!searching_lucky_phases) - phases.saved[idx] = tmp; // phase saving during search - trail.push_back (lit); -#ifdef LOGGING - if (!lit_level) - LOG ("root-level unit assign %d @ 0", lit); - else - LOG (reason, "search assign %d @ %d", lit, lit_level); -#endif - - if (watching ()) { - const Watches &ws = watches (-lit); - if (!ws.empty ()) { - const Watch &w = ws[0]; -#ifndef WIN32 - __builtin_prefetch (&w, 0, 1); -#endif - } - } - lrat_chain.clear (); -} - -/*------------------------------------------------------------------------*/ - -// External versions of 'search_assign' which are not inlined. They either -// are used to assign unit clauses on the root-level, in 'decide' to assign -// a decision or in 'analyze' to assign the literal 'driven' by a learned -// clause. This happens far less frequently than the 'search_assign' above, -// which is called directly in 'propagate' below and thus is inlined. - -void Internal::assign_unit (int lit) { - CADICAL_assert (!level); - search_assign (lit, 0); -} - -// Just assume the given literal as decision (increase decision level and -// assign it). This is used below in 'decide'. - -void Internal::search_assume_decision (int lit) { - require_mode (SEARCH); - CADICAL_assert (propagated == trail.size ()); - new_trail_level (lit); - notify_decision (); - LOG ("search decide %d", lit); - search_assign (lit, decision_reason); -} - -void Internal::search_assign_driving (int lit, Clause *c) { - require_mode (SEARCH); - search_assign (lit, c); - notify_assignments (); -} - -void Internal::search_assign_external (int lit) { - require_mode (SEARCH); - search_assign (lit, external_reason); - notify_assignments (); -} - -/*------------------------------------------------------------------------*/ - -// The 'propagate' function is usually the hot-spot of a CDCL SAT solver. -// The 'trail' stack saves assigned variables and is used here as BFS queue -// for checking clauses with the negation of assigned variables for being in -// conflict or whether they produce additional assignments. - -// This version of 'propagate' uses lazy watches and keeps two watched -// literals at the beginning of the clause. We also use 'blocking literals' -// to reduce the number of times clauses have to be visited (2008 JSAT paper -// by Chu, Harwood and Stuckey). The watches know if a watched clause is -// binary, in which case it never has to be visited. If a binary clause is -// falsified we continue propagating. - -// Finally, for long clauses we save the position of the last watch -// replacement in 'pos', which in turn reduces certain quadratic accumulated -// propagation costs (2013 JAIR article by Ian Gent) at the expense of four -// more bytes for each clause. - -bool Internal::propagate () { - - if (level) - require_mode (SEARCH); - CADICAL_assert (!unsat); - LOG ("starting propagate"); - START (propagate); - - // Updating statistics counter in the propagation loops is costly so we - // delay until propagation ran to completion. - // - int64_t before = propagated; - int64_t ticks = 0; - - while (!conflict && propagated != trail.size ()) { - - const int lit = -trail[propagated++]; - LOG ("propagating %d", -lit); - Watches &ws = watches (lit); - - const const_watch_iterator eow = ws.end (); - watch_iterator j = ws.begin (); - const_watch_iterator i = j; - ticks += 1 + cache_lines (ws.size (), sizeof *i); - - while (i != eow) { - - const Watch w = *j++ = *i++; - const signed char b = val (w.blit); - LOG (w.clause, "checking"); - - if (b > 0) - continue; // blocking literal satisfied - - if (w.binary ()) { - - // CADICAL_assert (w.clause->redundant || !w.clause->garbage); - - // In principle we can ignore garbage binary clauses too, but that - // would require to dereference the clause pointer all the time with - // - // if (w.clause->garbage) { j--; continue; } // (*) - // - // This is too costly. It is however necessary to produce correct - // proof traces if binary clauses are traced to be deleted ('d ...' - // line) immediately as soon they are marked as garbage. Actually - // finding instances where this happens is pretty difficult (six - // parallel fuzzing jobs in parallel took an hour), but it does - // occur. Our strategy to avoid generating incorrect proofs now is - // to delay tracing the deletion of binary clauses marked as garbage - // until they are really deleted from memory. For large clauses - // this is not necessary since we have to access the clause anyhow. - // - // Thanks go to Mathias Fleury, who wanted me to explain why the - // line '(*)' above was in the code. Removing it actually really - // improved running times and thus I tried to find concrete - // instances where this happens (which I found), and then - // implemented the described fix. - - // Binary clauses are treated separately since they do not require - // to access the clause at all (only during conflict analysis, and - // there also only to simplify the code). - - if (b < 0) - conflict = w.clause; // but continue ... - else { - build_chain_for_units (w.blit, w.clause, 0); - search_assign (w.blit, w.clause); - // lrat_chain.clear (); done in search_assign - ticks++; - } - - } else { - CADICAL_assert (w.clause->size > 2); - - if (conflict) - break; // Stop if there was a binary conflict already. - - // The cache line with the clause data is forced to be loaded here - // and thus this first memory access below is the real hot-spot of - // the solver. Note, that this check is positive very rarely and - // thus branch prediction should be almost perfect here. - - ticks++; - - if (w.clause->garbage) { - j--; - continue; - } - - literal_iterator lits = w.clause->begin (); - - // Simplify code by forcing 'lit' to be the second literal in the - // clause. This goes back to MiniSAT. We use a branch-less version - // for conditionally swapping the first two literals, since it - // turned out to be substantially faster than this one - // - // if (lits[0] == lit) swap (lits[0], lits[1]); - // - // which achieves the same effect, but needs a branch. - // - const int other = lits[0] ^ lits[1] ^ lit; - const signed char u = val (other); // value of the other watch - - if (u > 0) - j[-1].blit = other; // satisfied, just replace blit - else { - - // This follows Ian Gent's (JAIR'13) idea of saving the position - // of the last watch replacement. In essence it needs two copies - // of the default search for a watch replacement (in essence the - // code in the 'if (v < 0) { ... }' block below), one starting at - // the saved position until the end of the clause and then if that - // one failed to find a replacement another one starting at the - // first non-watched literal until the saved position. - - const int size = w.clause->size; - const literal_iterator middle = lits + w.clause->pos; - const const_literal_iterator end = lits + size; - literal_iterator k = middle; - - // Find replacement watch 'r' at position 'k' with value 'v'. - - int r = 0; - signed char v = -1; - - while (k != end && (v = val (r = *k)) < 0) - k++; - - if (v < 0) { // need second search starting at the head? - - k = lits + 2; - CADICAL_assert (w.clause->pos <= size); - while (k != middle && (v = val (r = *k)) < 0) - k++; - } - - w.clause->pos = k - lits; // always save position - - CADICAL_assert (lits + 2 <= k), CADICAL_assert (k <= w.clause->end ()); - - if (v > 0) { - - // Replacement satisfied, so just replace 'blit'. - - j[-1].blit = r; - - } else if (!v) { - - // Found new unassigned replacement literal to be watched. - - LOG (w.clause, "unwatch %d in", lit); - - lits[0] = other; - lits[1] = r; - *k = lit; - - watch_literal (r, lit, w.clause); - - j--; // Drop this watch from the watch list of 'lit'. - - ticks++; - - } else if (!u) { - - CADICAL_assert (v < 0); - - // The other watch is unassigned ('!u') and all other literals - // assigned to false (still 'v < 0'), thus we found a unit. - // - build_chain_for_units (other, w.clause, 0); - search_assign (other, w.clause); - // lrat_chain.clear (); done in search_assign - ticks++; - - // Similar code is in the implementation of the SAT'18 paper on - // chronological backtracking but in our experience, this code - // first does not really seem to be necessary for correctness, - // and further does not improve running time either. - // - if (opts.chrono > 1) { - - const int other_level = var (other).level; - - if (other_level > var (lit).level) { - - // The assignment level of the new unit 'other' is larger - // than the assignment level of 'lit'. Thus we should find - // another literal in the clause at that higher assignment - // level and watch that instead of 'lit'. - - CADICAL_assert (size > 2); - - int pos, s = 0; - - for (pos = 2; pos < size; pos++) - if (var (s = lits[pos]).level == other_level) - break; - - CADICAL_assert (s); - CADICAL_assert (pos < size); - - LOG (w.clause, "unwatch %d in", lit); - lits[pos] = lit; - lits[0] = other; - lits[1] = s; - watch_literal (s, lit, w.clause); - - j--; // Drop this watch from the watch list of 'lit'. - } - } - } else { - - CADICAL_assert (u < 0); - CADICAL_assert (v < 0); - - // The other watch is assigned false ('u < 0') and all other - // literals as well (still 'v < 0'), thus we found a conflict. - - conflict = w.clause; - break; - } - } - } - } - - if (j != i) { - - while (i != eow) - *j++ = *i++; - - ws.resize (j - ws.begin ()); - } - } - - if (searching_lucky_phases) { - - if (conflict) - LOG (conflict, "ignoring lucky conflict"); - - } else { - - // Avoid updating stats eagerly in the hot-spot of the solver. - // - stats.propagations.search += propagated - before; - stats.ticks.search[stable] += ticks; - - if (!conflict) - no_conflict_until = propagated; - else { - - if (stable) - stats.stabconflicts++; - stats.conflicts++; - - LOG (conflict, "conflict"); - - // The trail before the current decision level was conflict free. - // - no_conflict_until = control[level].trail; - } - } - - STOP (propagate); - - return !conflict; -} - -/*------------------------------------------------------------------------*/ - -void Internal::propergate () { - - CADICAL_assert (!conflict); - CADICAL_assert (propagated == trail.size ()); - - while (propergated != trail.size ()) { - - const int lit = -trail[propergated++]; - LOG ("propergating %d", -lit); - Watches &ws = watches (lit); - - const const_watch_iterator eow = ws.end (); - watch_iterator j = ws.begin (); - const_watch_iterator i = j; - - while (i != eow) { - - const Watch w = *j++ = *i++; - - if (w.binary ()) { - CADICAL_assert (val (w.blit) > 0); - continue; - } - if (w.clause->garbage) { - j--; - continue; - } - - literal_iterator lits = w.clause->begin (); - - const int other = lits[0] ^ lits[1] ^ lit; - const signed char u = val (other); - - // TODO: check if u == 0 can happen. - if (u > 0) - continue; - CADICAL_assert (u < 0); - - const int size = w.clause->size; - const literal_iterator middle = lits + w.clause->pos; - const const_literal_iterator end = lits + size; - literal_iterator k = middle; - - int r = 0; - signed char v = -1; - - while (k != end && (v = val (r = *k)) < 0) - k++; - - if (v < 0) { - k = lits + 2; - CADICAL_assert (w.clause->pos <= size); - while (k != middle && (v = val (r = *k)) < 0) - k++; - } - - CADICAL_assert (lits + 2 <= k), CADICAL_assert (k <= w.clause->end ()); - w.clause->pos = k - lits; - - CADICAL_assert (v > 0); - - LOG (w.clause, "unwatch %d in", lit); - - lits[0] = other; - lits[1] = r; - *k = lit; - - watch_literal (r, lit, w.clause); - - j--; - } - - if (j != i) { - - while (i != eow) - *j++ = *i++; - - ws.resize (j - ws.begin ()); - } - } -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_queue.cpp b/src/sat/cadical/cadical_queue.cpp deleted file mode 100644 index c8b5b8030..000000000 --- a/src/sat/cadical/cadical_queue.cpp +++ /dev/null @@ -1,96 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -// Slightly different than 'bump_variable' since the variable is not -// enqueued at all. - -inline void Internal::init_enqueue (int idx) { - Link &l = links[idx]; - if (opts.reverse) { - l.prev = 0; - if (queue.first) { - CADICAL_assert (!links[queue.first].prev); - links[queue.first].prev = idx; - btab[idx] = btab[queue.first] - 1; - } else { - CADICAL_assert (!queue.last); - queue.last = idx; - btab[idx] = 0; - } - CADICAL_assert (btab[idx] <= stats.bumped); - l.next = queue.first; - queue.first = idx; - if (!queue.unassigned) - update_queue_unassigned (queue.last); - } else { - l.next = 0; - if (queue.last) { - CADICAL_assert (!links[queue.last].next); - links[queue.last].next = idx; - } else { - CADICAL_assert (!queue.first); - queue.first = idx; - } - btab[idx] = ++stats.bumped; - l.prev = queue.last; - queue.last = idx; - update_queue_unassigned (queue.last); - } -} - -// Initialize VMTF queue from current 'old_max_var + 1' to 'new_max_var'. -// This incorporates an initial variable order. We currently simply assume -// that variables with smaller index are more important. This is the same -// as in MiniSAT (implicitly) and also matches the 'scores' initialization. -// -void Internal::init_queue (int old_max_var, int new_max_var) { - LOG ("initializing VMTF queue from %d to %d", old_max_var + 1, - new_max_var); - CADICAL_assert (old_max_var < new_max_var); - // New variables can be created that can invoke enlarge anytime (eg via - // calls during ipasir-up call-backs), thus assuming (!level) is not - // correct - for (int idx = old_max_var; idx < new_max_var; idx++) - init_enqueue (idx + 1); -} - -// Shuffle the VMTF queue. - -void Internal::shuffle_queue () { - if (!opts.shuffle) - return; - if (!opts.shufflequeue) - return; - stats.shuffled++; - LOG ("shuffling queue"); - vector shuffle; - if (opts.shufflerandom) { - for (int idx = max_var; idx; idx--) - shuffle.push_back (idx); - Random random (opts.seed); // global seed - random += stats.shuffled; // different every time - for (int i = 0; i <= max_var - 2; i++) { - const int j = random.pick_int (i, max_var - 1); - swap (shuffle[i], shuffle[j]); - } - } else { - for (int idx = queue.last; idx; idx = links[idx].prev) - shuffle.push_back (idx); - } - queue.first = queue.last = 0; - for (const int idx : shuffle) - queue.enqueue (links, idx); - int64_t bumped = queue.bumped; - for (int idx = queue.last; idx; idx = links[idx].prev) - btab[idx] = bumped--; - queue.unassigned = queue.last; -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_random.cpp b/src/sat/cadical/cadical_random.cpp deleted file mode 100644 index 85d022e8f..000000000 --- a/src/sat/cadical/cadical_random.cpp +++ /dev/null @@ -1,233 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -/*------------------------------------------------------------------------*/ - -// Our random number generator is seeded by default (i.e., in the default -// constructor) with random seeds, which should be unique across machines, -// processes and time. This makes this code below rather operating system -// dependent. We also use in essence defensive programming, overlaying -// several methods to get randomness since in the past we were bitten a -// couple of times (and got the same seeds). Having several methods makes -// it also simpler to port randomly initializing seeds to different -// operating systems (even though currently it is only tested on Linux). -// This functionality is only used in the 'Mobical' model based tester at -// this point, since the main solver explicitly sets a random seed ('0' by -// default in 'options.hpp') and also currently only uses this seed in the -// local search procedure explicitly without using the default constructor. -// It is crucial for 'Mobical' to make sure that concurrent runs are really -// independent. - -/*------------------------------------------------------------------------*/ - -// Uncomment the following definition to force printing the computed hash -// values for individual machine and process properties. This is only needed -// for testing, porting and debugging different ports of this seeding and -// hashing functions (uncomment and run 'mobical' for instance). - -/* -#define DO_PRINT_HASH -*/ - -#ifdef DO_PRINT_HASH -#define PRINT_HASH(H) \ - do { \ - printf ("c PRINT_HASH %32s () = %020" PRIu64 "\n", __func__, H); \ - fflush (stdout); \ - } while (0) -#else -#define PRINT_HASH(...) \ - do { \ - } while (0) -#endif - -/*------------------------------------------------------------------------*/ - -// This is Linux specific but if '/var/lib/dbus/machine-id' does not exist -// does not have any effect. TODO: add a similar machine identity hashing -// function for other operating systems (Windows and macOS). - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -static uint64_t hash_machine_identifier () { - FILE *file = fopen ("/var/lib/dbus/machine-id", "r"); - uint64_t res = 0; - if (file) { - char buffer[128]; - memset (buffer, 0, sizeof buffer); - size_t bytes = fread (buffer, 1, sizeof buffer - 1, file); - CADICAL_assert (bytes); - fclose (file); - if (bytes && bytes < sizeof buffer) { - buffer[bytes] = 0; - res = hash_string (buffer); - } - } - PRINT_HASH (res); - return res; -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END - -/*------------------------------------------------------------------------*/ - -// On our Linux cluster where we used an NFS mounted root disk the -// 'machine-id' above (even on a locally mounted '/var' disk on each node) -// was copied from '/etc/machine-id' which was shared among all nodes -// (before figuring this out and fixing it). Thus the main idea of getting -// different hash values through this machine identifier machines did not -// work. As an additional measure to increase the possibility to get -// different seeds we are now also using network addresses (explicitly). - -#ifndef WIN32 - -extern "C" { -#include -#include -#include -#include -#include -#include -} - -#endif - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -static uint64_t hash_network_addresses () { - uint64_t res = 0; - - // We still need to properly port this to Windows, but since accessing the - // IP address is only required for better randomization during testing - // (running 'mobical' on a cluster for instance) it is not crucial unless - // you really need to run 'mobical' on a Windows cluster where each node - // has identical IP addresses. - -#ifndef WIN32 - struct ifaddrs *addrs; - if (!getifaddrs (&addrs)) { - for (struct ifaddrs *addr = addrs; addr; addr = addr->ifa_next) { - if (!addr->ifa_addr) - continue; - const int family = addr->ifa_addr->sa_family; - if (family == AF_INET || family == AF_INET6) { - const int size = (family == AF_INET) ? sizeof (struct sockaddr_in) - : sizeof (struct sockaddr_in6); - char buffer[128]; - if (!getnameinfo (addr->ifa_addr, size, buffer, sizeof buffer, 0, 0, - NI_NUMERICHOST)) { - uint64_t tmp = hash_string (buffer); -#ifdef DO_PRINT_HASH - printf ("c PRINT_HASH %35s = %020" PRIu64 "\n", buffer, tmp); - fflush (stdout); -#endif - res ^= tmp; - res *= 10000000000000000051ul; - } - } - } - freeifaddrs (addrs); - } -#endif - - PRINT_HASH (res); - return res; -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END - -/*------------------------------------------------------------------------*/ - -// Hash the current wall-clock time in seconds. - -extern "C" { -#include -} - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -static uint64_t hash_time () { - uint64_t res = ::time (0); - PRINT_HASH (res); - return res; -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END - -/*------------------------------------------------------------------------*/ - -// Hash the process identified. - -extern "C" { -#include -#ifdef WIN32 -#include -#else -#include -#endif -} - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -static uint64_t hash_process () { - uint64_t res = getpid (); - PRINT_HASH (res); - return res; -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END - -/*------------------------------------------------------------------------*/ - -// Hash the current number of clock cycles. - -#include - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -static uint64_t hash_clock_cycles () { - uint64_t res = std::clock (); - PRINT_HASH (res); - return res; -} - -} // namespace CaDiCaL - -/*------------------------------------------------------------------------*/ - -namespace CaDiCaL { - -Random::Random () : state (1) { - add (hash_machine_identifier ()); - add (hash_network_addresses ()); - add (hash_clock_cycles ()); - add (hash_process ()); - add (hash_time ()); -#ifdef DO_PRINT_HASH - printf ("c PRINT_HASH %32s = %020" PRIu64 "\n", "combined", state); - fflush (stdout); -#endif -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_reap.cpp b/src/sat/cadical/cadical_reap.cpp deleted file mode 100644 index 4625c44db..000000000 --- a/src/sat/cadical/cadical_reap.cpp +++ /dev/null @@ -1,142 +0,0 @@ -#include "global.h" - -#include "reap.hpp" -#include -#include -#include - -#ifdef _MSC_VER -#include -static inline int __builtin_clz(unsigned x) { - unsigned long r; - _BitScanReverse(&r, x); - return (int)(r ^ 31); -} -#endif - -ABC_NAMESPACE_IMPL_START - -void Reap::init () { - for (auto &bucket : buckets) - bucket = {0}; - CADICAL_assert (!num_elements); - CADICAL_assert (!last_deleted); - min_bucket = 32; - CADICAL_assert (!max_bucket); -} - -void Reap::release () { - num_elements = 0; - last_deleted = 0; - min_bucket = 32; - max_bucket = 0; -} - -Reap::Reap () { - num_elements = 0; - last_deleted = 0; - min_bucket = 32; - max_bucket = 0; -} - -static inline unsigned leading_zeroes_of_unsigned (unsigned x) { - return x ? __builtin_clz (x) : sizeof (unsigned) * 8; -} - -void Reap::push (unsigned e) { - CADICAL_assert (last_deleted <= e); - const unsigned diff = e ^ last_deleted; - const unsigned bucket = 32 - leading_zeroes_of_unsigned (diff); - buckets[bucket].push_back (e); - if (min_bucket > bucket) - min_bucket = bucket; - if (max_bucket < bucket) - max_bucket = bucket; - CADICAL_assert (num_elements != UINT_MAX); - num_elements++; -} - -unsigned Reap::pop () { - CADICAL_assert (num_elements > 0); - unsigned i = min_bucket; - for (;;) { - CADICAL_assert (i < 33); - CADICAL_assert (i <= max_bucket); - std::vector &s = buckets[i]; - if (s.empty ()) { - min_bucket = ++i; - continue; - } - unsigned res; - if (i) { - res = UINT_MAX; - const auto begin = std::begin (s); - const auto end = std::end (s); - auto q = std::begin (s); - CADICAL_assert (begin < end); - for (auto p = begin; p != end; ++p) { - const unsigned tmp = *p; - if (tmp >= res) - continue; - res = tmp; - q = p; - } - - for (auto p = begin; p != end; ++p) { - if (p == q) - continue; - const unsigned other = *p; - const unsigned diff = other ^ res; - CADICAL_assert (sizeof (unsigned) == 4); - const unsigned j = 32 - leading_zeroes_of_unsigned (diff); - CADICAL_assert (j < i); - buckets[j].push_back (other); - if (min_bucket > j) - min_bucket = j; - } - - s.clear (); - - if (i && max_bucket == i) { -#ifndef CADICAL_NDEBUG - for (unsigned j = i + 1; j < 33; j++) - CADICAL_assert (buckets[j].empty ()); -#endif - if (s.empty ()) - max_bucket = i - 1; - } - } else { - res = last_deleted; - CADICAL_assert (!buckets[0].empty ()); - CADICAL_assert (buckets[0].at (0) == res); - buckets[0].pop_back (); - } - - if (min_bucket == i) { -#ifndef CADICAL_NDEBUG - for (unsigned j = 0; j < i; j++) - CADICAL_assert (buckets[j].empty ()); -#endif - if (s.empty ()) - min_bucket = std::min ((int) (i + 1), 32); - } - - --num_elements; - CADICAL_assert (last_deleted <= res); - last_deleted = res; - - return res; - } -} - -void Reap::clear () { - CADICAL_assert (max_bucket <= 32); - for (unsigned i = 0; i < 33; i++) - buckets[i].clear (); - num_elements = 0; - last_deleted = 0; - min_bucket = 32; - max_bucket = 0; -} - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_reduce.cpp b/src/sat/cadical/cadical_reduce.cpp deleted file mode 100644 index cc6f35228..000000000 --- a/src/sat/cadical/cadical_reduce.cpp +++ /dev/null @@ -1,284 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -/*------------------------------------------------------------------------*/ - -// Once in a while we reduce, e.g., we remove learned clauses which are -// supposed to be less useful in the future. This is done in increasing -// intervals, which has the effect of allowing more and more learned clause -// to be kept for a longer period. The number of learned clauses kept -// in memory corresponds to an upper bound on the 'space' of a resolution -// proof needed to refute a formula in proof complexity sense. - -bool Internal::reducing () { - if (!opts.reduce) - return false; - if (!stats.current.redundant) - return false; - return stats.conflicts >= lim.reduce; -} - -/*------------------------------------------------------------------------*/ - -// Even less regularly we are flushing all redundant clauses. - -bool Internal::flushing () { - if (!opts.flush) - return false; - return stats.conflicts >= lim.flush; -} - -/*------------------------------------------------------------------------*/ - -void Internal::mark_clauses_to_be_flushed () { - const int tier1limit = tier1[false]; - const int tier2limit = max (tier1limit, tier2[false]); - for (const auto &c : clauses) { - if (!c->redundant) - continue; // keep irredundant - if (c->garbage) - continue; // already marked as garbage - if (c->reason) - continue; // need to keep reasons - const unsigned used = c->used; - if (used) - c->used--; - if (c->glue < tier1limit && used) - continue; - if (c->glue < tier2limit && used >= max_used - 1) - continue; - mark_garbage (c); // flush unused clauses - if (c->hyper) - stats.flush.hyper++; - else - stats.flush.learned++; - } - // No change to 'lim.kept{size,glue}'. -} - -/*------------------------------------------------------------------------*/ - -// Clauses of larger glue or larger size are considered less useful. -// -// We also follow the observations made by the Glucose team in their -// IJCAI'09 paper and keep all low glue clauses limited by -// 'options.keepglue' (typically '2'). -// -// In earlier versions we pre-computed a 64-bit sort key per clause and -// wrapped a pointer to the clause and the 64-bit sort key into a separate -// data structure for sorting. This was probably faster but awkward and -// so we moved back to a simpler scheme which also uses 'stable_sort' -// instead of 'rsort' below. Sorting here is not a hot-spot anyhow. - -struct reduce_less_useful { - bool operator() (const Clause *c, const Clause *d) const { - if (c->glue > d->glue) - return true; - if (c->glue < d->glue) - return false; - return c->size > d->size; - } -}; - -// This function implements the important reduction policy. It determines -// which redundant clauses are considered not useful and thus will be -// collected in a subsequent garbage collection phase. - -void Internal::mark_useless_redundant_clauses_as_garbage () { - - // We use a separate stack for sorting candidates for removal. This uses - // (slightly) more memory but has the advantage to keep the relative order - // in 'clauses' intact, which actually due to using stable sorting goes - // into the candidate selection (more recently learned clauses are kept if - // they otherwise have the same glue and size). - - vector stack; - const int tier1limit = tier1[false]; - const int tier2limit = max (tier1limit, tier2[false]); - - stack.reserve (stats.current.redundant); - - for (const auto &c : clauses) { - if (!c->redundant) - continue; // Keep irredundant. - if (c->garbage) - continue; // Skip already marked. - if (c->reason) - continue; // Need to keep reasons. - const unsigned used = c->used; - if (used) - c->used--; - if (c->glue <= tier1limit && used) - continue; - if (c->glue <= tier2limit && used >= max_used - 1) - continue; - if (c->hyper) { // Hyper binary and ternary resolvents - CADICAL_assert (c->size <= 3); // are only kept for one reduce round - if (!used) - mark_garbage (c); // unless - continue; // used recently. - } - stack.push_back (c); - } - - stable_sort (stack.begin (), stack.end (), reduce_less_useful ()); - size_t target = 1e-2 * opts.reducetarget * stack.size (); - - // This is defensive code, which I usually consider a bug, but here I am - // just not sure that using floating points in the line above is precise - // in all situations and instead of figuring that out, I just use this. - // - if (target > stack.size ()) - target = stack.size (); - - PHASE ("reduce", stats.reductions, "reducing %zd clauses %.0f%%", target, - percent (target, stats.current.redundant)); - - auto i = stack.begin (); - const auto t = i + target; - while (i != t) { - Clause *c = *i++; - LOG (c, "marking useless to be collected"); - mark_garbage (c); - stats.reduced++; - } - - lim.keptsize = lim.keptglue = 0; - - const auto end = stack.end (); - for (i = t; i != end; i++) { - Clause *c = *i; - LOG (c, "keeping"); - if (c->size > lim.keptsize) - lim.keptsize = c->size; - if (c->glue > lim.keptglue) - lim.keptglue = c->glue; - } - - erase_vector (stack); - - PHASE ("reduce", stats.reductions, "maximum kept size %d glue %d", - lim.keptsize, lim.keptglue); -} - -/*------------------------------------------------------------------------*/ - -// If chronological backtracking produces out-of-order assigned units, then -// it is necessary to completely propagate them at the root level in order -// to derive all implied units. Otherwise the blocking literals in -// 'flush_watches' are messed up and CADICAL_assertion 'FW1' fails. - -bool Internal::propagate_out_of_order_units () { - if (!level) - return true; - int oou = 0; - for (size_t i = control[1].trail; !oou && i < trail.size (); i++) { - const int lit = trail[i]; - CADICAL_assert (val (lit) > 0); - if (var (lit).level) - continue; - LOG ("found out-of-order assigned unit %d", oou); - oou = lit; - } - if (!oou) - return true; - CADICAL_assert (opts.chrono || external_prop); - backtrack (0); - if (propagate ()) - return true; - learn_empty_clause (); - return false; -} - -/*------------------------------------------------------------------------*/ - -// reduction is scheduled with reduceint, reducetarget and reduceopt. -// with reduceopt=1 the number of learnt clauses scale with -// sqrt of conflicts times reduceint -// the scaling is the same as with reduceopt=0 (the classical default) -// however, the constants are different. To avoid this (and get roughly the -// same behaviour with reduceopt=0 and reduceopt=1) we need to scale the -// interval, namely (reduceint^2/2) -// Lastly, reduceopt=2 just replaces sqrt conflicts with log conflicts. -// The learnt clauses should not be bigger than -// 1/reducetarget * reduceint * function (conflicts) -// for function being log if reduceint=2 an sqrt otherwise. -// This is however only the theoretical target and second chance for -// tier2 clauses and very long lifespan of tier1 clauses (through used flag) -// make this behave differently. -// reduceinit shifts the curve to the right, increasing the number of -// clauses in the solver. This impact will decrease over time. - -void Internal::reduce () { - START (reduce); - - stats.reductions++; - report ('.', 1); - - bool flush = flushing (); - if (flush) - stats.flush.count++; - - if (!propagate_out_of_order_units ()) - goto DONE; - - mark_satisfied_clauses_as_garbage (); - protect_reasons (); - if (flush) - mark_clauses_to_be_flushed (); - else - mark_useless_redundant_clauses_as_garbage (); - garbage_collection (); - - { - int64_t delta = opts.reduceint; - double factor = stats.reductions + 1; - if (opts.reduceopt == - 0) // adjust delta such this is the same as reduceopt=1 - delta = delta * delta / 2; - else if (opts.reduceopt == 1) { - // this is the same as reduceopt=0 if reduceint = sqrt (reduceint) = - // 17 - factor = sqrt ((double) stats.conflicts); - } else if (opts.reduceopt == 2) - // log scaling instead - factor = log ((double) stats.conflicts); - if (factor < 1) - factor = 1; - delta = delta * factor; - if (irredundant () > 1e5) { - delta *= log (irredundant () / 1e4) / log (10); - } - if (delta < 1) - delta = 1; - lim.reduce = stats.conflicts + delta; - PHASE ("reduce", stats.reductions, - "new reduce limit %" PRId64 " after %" PRId64 " conflicts", - lim.reduce, delta); - } - - if (flush) { - PHASE ("flush", stats.flush.count, "new flush increment %" PRId64 "", - inc.flush); - inc.flush *= opts.flushfactor; - lim.flush = stats.conflicts + inc.flush; - PHASE ("flush", stats.flush.count, "new flush limit %" PRId64 "", - lim.flush); - } - - last.reduce.conflicts = stats.conflicts; - -DONE: - - report (flush ? 'f' : '-'); - STOP (reduce); -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_rephase.cpp b/src/sat/cadical/cadical_rephase.cpp deleted file mode 100644 index 3b2e62526..000000000 --- a/src/sat/cadical/cadical_rephase.cpp +++ /dev/null @@ -1,342 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -/*------------------------------------------------------------------------*/ - -// We experimented with resetting and reinitializing the saved phase with -// many solvers. Actually RSAT had already such a scheme. Our newest -// version seems to be quite beneficial for satisfiable instances. In an -// arithmetic increasing interval in the number of conflicts we either use -// the original phase (set by the option 'phase'), its inverted value, flip -// the current phase, pick random phases, then pick the best since the last -// time a best phase was picked and finally also use local search to find -// phases which minimize the number of falsified clauses. During -// stabilization (see 'stabilizing' in 'restart.cpp' when 'stable' is true) -// we execute a different rephasing schedule. The same applies if local -// search is disabled. - -/*------------------------------------------------------------------------*/ - -bool Internal::rephasing () { - if (!opts.rephase) - return false; - if (opts.forcephase) - return false; - return stats.conflicts > lim.rephase; -} - -/*------------------------------------------------------------------------*/ - -// Pick the original default phase. - -char Internal::rephase_original () { - stats.rephased.original++; - signed char val = opts.phase ? 1 : -1; // original = initial - PHASE ("rephase", stats.rephased.total, "switching to original phase %d", - val); - for (auto idx : vars) - phases.saved[idx] = val; - return 'O'; -} - -// Pick the inverted original default phase. - -char Internal::rephase_inverted () { - stats.rephased.inverted++; - signed char val = opts.phase ? -1 : 1; // original = -initial - PHASE ("rephase", stats.rephased.total, - "switching to inverted original phase %d", val); - for (auto idx : vars) - phases.saved[idx] = val; - return 'I'; -} - -// Flip the current phase. - -char Internal::rephase_flipping () { - stats.rephased.flipped++; - PHASE ("rephase", stats.rephased.total, - "flipping all phases individually"); - for (auto idx : vars) - phases.saved[idx] *= -1; - return 'F'; -} - -// Complete random picking of phases. - -char Internal::rephase_random () { - stats.rephased.random++; - PHASE ("rephase", stats.rephased.total, "resetting all phases randomly"); - Random random (opts.seed); // global seed - random += stats.rephased.random; // different every time - for (auto idx : vars) - phases.saved[idx] = random.generate_bool () ? -1 : 1; - return '#'; -} - -// Best phases are those saved at the largest trail height without conflict. -// See code and comments in 'update_target_and_best' in 'backtrack.cpp' - -char Internal::rephase_best () { - stats.rephased.best++; - PHASE ("rephase", stats.rephased.total, - "overwriting saved phases by best phases"); - signed char val; - for (auto idx : vars) - if ((val = phases.best[idx])) - phases.saved[idx] = val; - return 'B'; -} - -// Trigger local search 'walk' in 'walk.cpp'. - -char Internal::rephase_walk () { - stats.rephased.walk++; - PHASE ("rephase", stats.rephased.total, - "starting local search to improve current phase"); - walk (); - return 'W'; -} - -/*------------------------------------------------------------------------*/ - -void Internal::rephase () { - - stats.rephased.total++; - PHASE ("rephase", stats.rephased.total, - "reached rephase limit %" PRId64 " after %" PRId64 " conflicts", - lim.rephase, stats.conflicts); - - // Report current 'target' and 'best' and then set 'rephased' below, which - // will trigger reporting the new 'target' and 'best' after updating it in - // the next 'update_target_and_best' called from the next 'backtrack'. - // - report ('~', 1); - - backtrack (); - clear_phases (phases.target); - target_assigned = 0; - - size_t count = lim.rephased[stable]++; - bool single; - char type; - - if (opts.stabilize && opts.stabilizeonly) - single = true; - else - single = !opts.stabilize; - - if (single && !opts.walk) { - // (inverted,best,flipping,best,random,best,original,best)^\omega - switch (count % 8) { - case 0: - type = rephase_inverted (); - break; - case 1: - type = rephase_best (); - break; - case 2: - type = rephase_flipping (); - break; - case 3: - type = rephase_best (); - break; - case 4: - type = rephase_random (); - break; - case 5: - type = rephase_best (); - break; - case 6: - type = rephase_original (); - break; - case 7: - type = rephase_best (); - break; - default: - type = 0; - break; - } - } else if (single && opts.walk) { - // (inverted,best,walk, - // flipping,best,walk, - // random,best,walk, - // original,best,walk)^\omega - switch (count % 12) { - case 0: - type = rephase_inverted (); - break; - case 1: - type = rephase_best (); - break; - case 2: - type = rephase_walk (); - break; - case 3: - type = rephase_flipping (); - break; - case 4: - type = rephase_best (); - break; - case 5: - type = rephase_walk (); - break; - case 6: - type = rephase_random (); - break; - case 7: - type = rephase_best (); - break; - case 8: - type = rephase_walk (); - break; - case 9: - type = rephase_original (); - break; - case 10: - type = rephase_best (); - break; - case 11: - type = rephase_walk (); - break; - default: - type = 0; - break; - } - } else if (stable && !opts.walk) { - // original,inverted,(best,original,best,inverted)^\omega - if (!count) - type = rephase_original (); - else if (count == 1) - type = rephase_inverted (); - else - switch ((count - 2) % 4) { - case 0: - type = rephase_best (); - break; - case 1: - type = rephase_original (); - break; - case 2: - type = rephase_best (); - break; - case 3: - type = rephase_inverted (); - break; - default: - type = 0; - break; - } - } else if (stable && opts.walk) { - // original,inverted,(best,walk,original,best,walk,inverted)^\omega - if (!count) - type = rephase_original (); - else if (count == 1) - type = rephase_inverted (); - else - switch ((count - 2) % 6) { - case 0: - type = rephase_best (); - break; - case 1: - type = rephase_walk (); - break; - case 2: - type = rephase_original (); - break; - case 3: - type = rephase_best (); - break; - case 4: - type = rephase_walk (); - break; - case 5: - type = rephase_inverted (); - break; - default: - type = 0; - break; - } - } else if (!stable && (!opts.walk || !opts.walknonstable)) { - // flipping,(random,best,flipping,best)^\omega - if (!count) - type = rephase_flipping (); - else - switch ((count - 1) % 4) { - case 0: - type = rephase_random (); - break; - case 1: - type = rephase_best (); - break; - case 2: - type = rephase_flipping (); - break; - case 3: - type = rephase_best (); - break; - default: - type = 0; - break; - } - } else { - CADICAL_assert (!stable && opts.walk && opts.walknonstable); - // flipping,(random,best,walk,flipping,best,walk)^\omega - if (!count) - type = rephase_flipping (); - else - switch ((count - 1) % 6) { - case 0: - type = rephase_random (); - break; - case 1: - type = rephase_best (); - break; - case 2: - type = rephase_walk (); - break; - case 3: - type = rephase_flipping (); - break; - case 4: - type = rephase_best (); - break; - case 5: - type = rephase_walk (); - break; - default: - type = 0; - break; - } - } - CADICAL_assert (type); - - int64_t delta = opts.rephaseint * (stats.rephased.total + 1); - lim.rephase = stats.conflicts + delta; - - PHASE ("rephase", stats.rephased.total, - "new rephase limit %" PRId64 " after %" PRId64 " conflicts", - lim.rephase, delta); - - // This will trigger to report the effect of this new set of phases at the - // 'backtrack' (actually 'update_target_and_best') after the next - // conflict, as well as resetting 'best_assigned' then to allow to compute - // a new "best" assignment at that point. - // - last.rephase.conflicts = stats.conflicts; - rephased = type; - - if (stable) - shuffle_scores (); - else - shuffle_queue (); -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_report.cpp b/src/sat/cadical/cadical_report.cpp deleted file mode 100644 index 18271d17e..000000000 --- a/src/sat/cadical/cadical_report.cpp +++ /dev/null @@ -1,302 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -#ifndef CADICAL_QUIET - -/*------------------------------------------------------------------------*/ - -// Provide nicely formatted progress report messages while running through -// the 'report' function below. The code is so complex, because it should -// be easy to add and remove reporting of certain statistics, while still -// providing a nicely looking format with automatically aligned headers. - -/*------------------------------------------------------------------------*\ - -The 'reports' are shown as 'c ...' with '' as follows: - -i propagated learned unit clause -O backtracked after phases reset to original phase -F backtracked after flipping phases -# backtracked after randomly setting phases -B backtracked after resetting to best phases -W backtracked after local search improved phases -b blocked clause elimination -G before garbage collection -C after garbage collection -/ compacted internal literals and remapped external to internal -c covered clause elimination -d decomposed binary implication graph and substituted equivalent literals -2 removed duplicated binary clauses -e bounded variable elimination round -^ variable elimination bound increased -I variable instantiation -[ start of stable search phase -] end of stable search phase -{ start of unstable search phase -} end of unstable search phase -P preprocessing round (capital 'P') -L local search round -* start of solving without the need to restore clauses -+ start of solving before restoring clauses -r start of solving after restoring clauses -1 end of solving returns satisfiable -0 end of solving returns unsatisfiable -? end of solving due to interrupt -l lucky phase solving -p failed literal probing round (lower case 'p') -. before reducing redundant clauses -f flushed redundant clauses -- reduced redundant clauses -~ start of resetting phases -R restart -s subsumed clause removal round -3 ternary resolution round -t transition reduction of binary implication graph -u vivified tier1 clauses -v vivified tier2 clauses -x vivified tier3 clauses -w vivified irredundant clauses - -The order of the list follows the occurrences of 'report' in the source -files, i.e., obtained from "grep 'report (' *.cpp". Note that some of the -reports are only printed for higher verbosity level (for instance 'R'). - -\*------------------------------------------------------------------------*/ - -struct Report { - - const char *header; - char buffer[32]; - int pos; - - Report (const char *h, int precision, int min, double value); - Report () {} - - void print_header (char *line); -}; - -/*------------------------------------------------------------------------*/ - -void Report::print_header (char *line) { - int len = strlen (header); - for (int i = -1, j = pos - (len + 1) / 2 - 3; i < len; i++, j++) - line[j] = i < 0 ? ' ' : header[i]; -} - -Report::Report (const char *h, int precision, int min, double value) - : header (h) { - char fmt[32]; - if (precision < 0) - snprintf (fmt, sizeof fmt, "%%.%df", -precision - 1); - else - snprintf (fmt, sizeof fmt, "%%.%df", precision); - snprintf (buffer, sizeof buffer, fmt, value); - const int width = strlen (buffer); - if (precision < 0) - strcat (buffer, "%"); - if (width >= min) - return; - if (precision < 0) - snprintf (fmt, sizeof fmt, "%%%d.%df%%%%", min, -precision - 1); - else - snprintf (fmt, sizeof fmt, "%%%d.%df", min, precision); - snprintf (buffer, sizeof buffer, fmt, value); -} - -/*------------------------------------------------------------------------*/ - -// The following statistics are printed in columns, whenever 'report' is -// called. For instance 'reduce' with prefix '-' will call it. The other -// more interesting report is due to learning a unit, called iteration, with -// prefix 'i'. To add another statistics column, add a corresponding line -// here. If you want to report something else add 'report (..)' functions. - -#define TIME opts.reportsolve ? solve_time () : time () - -#define MB (current_resident_set_size () / (double) (1l << 20)) - -#define REMAINING (percent (active (), stats.variables_original)) - -#define TRAIL (percent (averages.current.trail.slow, max_var)) - -#define TARGET (percent (target_assigned, max_var)) - -#define BEST (percent (best_assigned, max_var)) - -#define REPORTS \ - /* HEADER, PRECISION, MIN, VALUE */ \ - REPORT ("seconds", 2, 5, TIME) \ - REPORT ("MB", 0, 2, MB) \ - REPORT ("level", 0, 2, averages.current.level) \ - REPORT ("reductions", 0, 1, stats.reductions) \ - REPORT ("restarts", 0, 3, stats.restarts) \ - REPORT ("rate", 0, 2, averages.current.decisions) \ - REPORT ("conflicts", 0, 4, stats.conflicts) \ - REPORT ("redundant", 0, 4, stats.current.redundant) \ - REPORT ("trail", -1, 2, TRAIL) \ - REPORT ("glue", 0, 1, averages.current.glue.slow) \ - REPORT ("irredundant", 0, 4, stats.current.irredundant) \ - REPORT ("variables", 0, 3, active ()) \ - REPORT ("remaining", -1, 2, REMAINING) - -// Note, keep an empty line before this line (because of '\')! - -#if 0 // ADDITIONAL STATISTICS TO REPORT - -REPORT("best", -1, 2, BEST) \ -REPORT("target", -1, 2, TARGET) \ -REPORT("maxvar", 0, 2, external->max_var) - -#endif - -static const int num_reports = // as compile time constant -#define REPORT(HEAD, PREC, MIN, EXPR) 1 + - REPORTS -#undef REPORT - 0; - -/*------------------------------------------------------------------------*/ - -void Internal::report (char type, int verbose) { - if (!opts.report) - return; -#ifdef LOGGING - if (!opts.log) -#endif - if (opts.quiet || (verbose > opts.verbose)) - return; - if (!reported) { - CADICAL_assert (!lim.report); - reported = true; - MSG ("%stime measured in %s time %s%s", tout.magenta_code (), - internal->opts.realtime ? "real" : "process", - internal->opts.reportsolve ? "in solving" : "since initialization", - tout.normal_code ()); - } - Report reports[num_reports]; - int n = 0; -#define REPORT(HEAD, PREC, MIN, EXPR) \ - CADICAL_assert (n < num_reports); \ - reports[n++] = Report (HEAD, PREC, MIN, (double) (EXPR)); - REPORTS -#undef REPORT - if (!lim.report) { - print_prefix (); - fputc ('\n', stdout); - int pos = 4; - for (int i = 0; i < n; i++) { - int len = strlen (reports[i].buffer); - reports[i].pos = pos + (len + 1) / 2; - pos += len + 1; - } - const int max_line = pos + 20, nrows = 3; - char *line = new char[max_line]; - for (int start = 0; start < nrows; start++) { - int i; - for (i = 0; i < max_line; i++) - line[i] = ' '; - for (i = start; i < n; i += nrows) - reports[i].print_header (line); - for (i = max_line - 1; line[i - 1] == ' '; i--) - ; - line[i] = 0; - print_prefix (); - tout.yellow (); - fputs (line, stdout); - tout.normal (); - fputc ('\n', stdout); - } - print_prefix (); - fputc ('\n', stdout); - delete[] line; - lim.report = 19; - } else - lim.report--; - print_prefix (); - switch (type) { - case '[': - case ']': - tout.magenta (true); - break; - case 's': - case 'b': - case 'c': - tout.green (false); - break; - case 'e': - tout.green (true); - break; - case 'p': - case '2': - case '3': - case 'u': - case 'v': - case 'w': - case 'x': - case 'f': - case '=': - tout.blue (false); - break; - case 't': - tout.cyan (false); - break; - case 'd': - tout.blue (true); - break; - case 'z': - case '!': - tout.cyan (true); - break; - case '-': - tout.normal (); - break; - case '/': - tout.yellow (true); - break; - case 'a': - case 'n': - tout.red (false); - break; - case '0': - case '1': - case '?': - case 'i': - tout.bold (); - break; - case 'L': - case 'P': - tout.bold (); - tout.underline (); - break; - default: - break; - } - fputc (type, stdout); - if (stable || type == ']') - tout.magenta (); - else if (type != 'L' && type != 'P') - tout.normal (); - for (int i = 0; i < n; i++) { - fputc (' ', stdout); - fputs (reports[i].buffer, stdout); - } - if (stable || type == 'L' || type == 'P' || type == ']') - tout.normal (); - fputc ('\n', stdout); - fflush (stdout); -} - -#else // ifndef CADICAL_QUIET - -void Internal::report (char, int) {} - -#endif - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_resources.cpp b/src/sat/cadical/cadical_resources.cpp deleted file mode 100644 index 9a2b421e5..000000000 --- a/src/sat/cadical/cadical_resources.cpp +++ /dev/null @@ -1,166 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -/*------------------------------------------------------------------------*/ - -// This is operating system specific code. We mostly develop on Linux and -// there it should be fine and mostly works out-of-the-box on MacOS too but -// Windows needs special treatment (as probably other operating systems -// too). - -extern "C" { - -#ifdef WIN32 - -#ifndef __WIN32_WINNT -#define __WIN32_WINNT 0x0600 -#endif - -// Clang-format would reorder the includes which breaks the Windows code -// as it expects 'windows.h' to be included first. So disable it here. - -// clang-format off - -#include -#include - -// clang-format on - -#else - -#include -#include -#include -#include - -#endif - -#include -} - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -/*------------------------------------------------------------------------*/ - -#ifdef WIN32 - -double absolute_real_time () { - FILETIME f; - GetSystemTimeAsFileTime (&f); - ULARGE_INTEGER t; - t.LowPart = f.dwLowDateTime; - t.HighPart = f.dwHighDateTime; - double res = (__int64) t.QuadPart; - res *= 1e-7; - return res; -} - -double absolute_process_time () { - double res = 0; - FILETIME fc, fe, fu, fs; - if (GetProcessTimes (GetCurrentProcess (), &fc, &fe, &fu, &fs)) { - ULARGE_INTEGER u, s; - u.LowPart = fu.dwLowDateTime; - u.HighPart = fu.dwHighDateTime; - s.LowPart = fs.dwLowDateTime; - s.HighPart = fs.dwHighDateTime; - res = (__int64) u.QuadPart + (__int64) s.QuadPart; - res *= 1e-7; - } - return res; -} - -#else - -double absolute_real_time () { - struct timeval tv; - if (gettimeofday (&tv, 0)) - return 0; - return 1e-6 * tv.tv_usec + tv.tv_sec; -} - -// We use 'getrusage' for 'process_time' and 'maximum_resident_set_size' -// which is pretty standard on Unix but probably not available on Windows -// etc. For different variants of Unix not all fields are meaningful. - -double absolute_process_time () { - double res; - struct rusage u; - if (getrusage (RUSAGE_SELF, &u)) - return 0; - res = u.ru_utime.tv_sec + 1e-6 * u.ru_utime.tv_usec; // user time - res += u.ru_stime.tv_sec + 1e-6 * u.ru_stime.tv_usec; // + system time - return res; -} - -#endif - -double Internal::real_time () const { - return absolute_real_time () - stats.time.real; -} - -double Internal::process_time () const { - return absolute_process_time () - stats.time.process; -} - -/*------------------------------------------------------------------------*/ - -#ifdef WIN32 - -uint64_t current_resident_set_size () { - PROCESS_MEMORY_COUNTERS pmc; - if (GetProcessMemoryInfo (GetCurrentProcess (), &pmc, sizeof (pmc))) { - return pmc.WorkingSetSize; - } else - return 0; -} - -uint64_t maximum_resident_set_size () { - PROCESS_MEMORY_COUNTERS pmc; - if (GetProcessMemoryInfo (GetCurrentProcess (), &pmc, sizeof (pmc))) { - return pmc.PeakWorkingSetSize; - } else - return 0; -} - -#else - -// This seems to work on Linux (man page says since Linux 2.6.32). - -uint64_t maximum_resident_set_size () { - struct rusage u; - if (getrusage (RUSAGE_SELF, &u)) - return 0; - return ((uint64_t) u.ru_maxrss) << 10; -} - -// Unfortunately 'getrusage' on Linux does not support current resident set -// size (the field 'ru_ixrss' is there but according to the man page -// 'unused'). Thus we fall back to use the '/proc' file system instead. So -// this is not portable at all and needs to be replaced on other systems -// The code would still compile though (assuming 'sysconf' and -// '_SC_PAGESIZE' are available). - -uint64_t current_resident_set_size () { - char path[64]; - snprintf (path, sizeof path, "/proc/%" PRId64 "/statm", - (int64_t) getpid ()); - FILE *file = fopen (path, "r"); - if (!file) - return 0; - uint64_t dummy, rss; - int scanned = fscanf (file, "%" PRIu64 " %" PRIu64 "", &dummy, &rss); - fclose (file); - return scanned == 2 ? rss * sysconf (_SC_PAGESIZE) : 0; -} - -#endif - -/*------------------------------------------------------------------------*/ - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_restart.cpp b/src/sat/cadical/cadical_restart.cpp deleted file mode 100644 index 1c6dc44c8..000000000 --- a/src/sat/cadical/cadical_restart.cpp +++ /dev/null @@ -1,165 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -// As observed by Chanseok Oh and implemented in MapleSAT solvers too, -// various mostly satisfiable instances benefit from long quiet phases -// with less or almost no restarts. We implement this idea by prohibiting -// the Glucose style restart scheme in a geometric fashion, which is very -// similar to how originally restarts were scheduled in MiniSAT and earlier -// solvers. We start with say 1e3 = 1000 (opts.stabilizeinit) conflicts of -// Glucose restarts. Then in a "stabilizing" phase we disable these -// until 1e4 = 2000 conflicts (if 'opts.stabilizefactor' is '200' percent) -// have passed. After that we switch back to regular Glucose style restarts -// until again 2 times more conflicts than the previous limit are reached. -// Actually, in the latest version we still restarts during stabilization -// but only in a reluctant doubling scheme with a rather high interval. - -bool Internal::stabilizing () { - if (!opts.stabilize) - return false; - if (stable && opts.stabilizeonly) - return true; - if (!inc.stabilize) { - CADICAL_assert (!stable); - if (stats.conflicts <= lim.stabilize) - return false; - } else if (stats.ticks.search[stable] <= lim.stabilize) - return stable; - report (stable ? ']' : '}'); - if (stable) - STOP (stable); - else - STOP (unstable); - const int64_t delta_conflicts = - stats.conflicts - last.stabilize.conflicts; - const int64_t delta_ticks = - stats.ticks.search[stable] - last.stabilize.ticks; - const char *current_mode = stable ? "stable" : "unstable"; - const char *next_mode = stable ? "unstable" : "stable"; - PHASE ("stabilizing", stats.stabphases, - "reached %s stabilization limit %" PRId64 " after %" PRId64 - " conflicts and %" PRId64 " ticks at %" PRId64 - " conflicts and %" PRId64 " ticks", - current_mode, lim.stabilize, delta_conflicts, delta_ticks, - stats.conflicts, stats.ticks.search[stable]); - if (!inc.stabilize) - inc.stabilize = delta_ticks; - if (!inc.stabilize) // rare occurence in incremental calls requiring no - // ticks - inc.stabilize = 1; - - stable = !stable; // Switch!!!!! - - int64_t next_delta_ticks = inc.stabilize; - int64_t stabphases = stats.stabphases + 1; - next_delta_ticks *= stabphases * stabphases; - - lim.stabilize = stats.ticks.search[stable] + next_delta_ticks; - if (lim.stabilize <= stats.ticks.search[stable]) - lim.stabilize = stats.ticks.search[stable] + 1; - - if (stable) - stats.stabphases++; - - swap_averages (); - PHASE ("stabilizing", stats.stabphases, - "next %s stabilization limit %" PRId64 - " at ticks interval %" PRId64, - next_mode, lim.stabilize, next_delta_ticks); - report (stable ? '[' : '{'); - if (stable) - START (stable); - else - START (unstable); - return stable; -} - -// Restarts are scheduled by a variant of the Glucose scheme as presented -// in our POS'15 paper using exponential moving averages. There is a slow -// moving average of the average recent glucose level of learned clauses -// as well as a fast moving average of those glues. If the end of a base -// restart conflict interval has passed and the fast moving average is -// above a certain margin over the slow moving average then we restart. - -bool Internal::restarting () { - if (!opts.restart) - return false; - if ((size_t) level < assumptions.size () + 2) - return false; - if (stabilizing ()) - return reluctant; - if (stats.conflicts <= lim.restart) - return false; - double f = averages.current.glue.fast; - double margin = (100.0 + opts.restartmargin) / 100.0; - double s = averages.current.glue.slow, l = margin * s; - LOG ("EMA glue slow %.2f fast %.2f limit %.2f", s, f, l); - return l <= f; -} - -// This is Marijn's reuse trail idea. Instead of always backtracking to -// the top we figure out which decisions will be made again anyhow and -// only backtrack to the level of the last such decision or to the top if -// no such decision exists top (in which case we do not reuse any level). - -int Internal::reuse_trail () { - const int trivial_decisions = - assumptions.size () - // Plus 1 if the constraint is satisfied via implications of - // assumptions and a pseudo-decision level was introduced. - + !control[assumptions.size () + 1].decision; - if (!opts.restartreusetrail) - return trivial_decisions; - int next_decision = next_decision_variable (); - CADICAL_assert (1 <= next_decision); - int res = trivial_decisions; - if (use_scores ()) { - while (res < level) { - int decision = control[res + 1].decision; - if (decision && score_smaller (this) (abs (decision), next_decision)) - break; - res++; - } - } else { - int64_t limit = bumped (next_decision); - while (res < level) { - int decision = control[res + 1].decision; - if (decision && bumped (decision) < limit) - break; - res++; - } - } - int reused = res - trivial_decisions; - if (reused > 0) { - stats.reused++; - stats.reusedlevels += reused; - if (stable) - stats.reusedstable++; - } - return res; -} - -void Internal::restart () { - START (restart); - stats.restarts++; - stats.restartlevels += level; - if (stable) - stats.restartstable++; - LOG ("restart %" PRId64 "", stats.restarts); - backtrack (reuse_trail ()); - - lim.restart = stats.conflicts + opts.restartint; - LOG ("new restart limit at %" PRId64 " conflicts", lim.restart); - - report ('R', 2); - STOP (restart); -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_restore.cpp b/src/sat/cadical/cadical_restore.cpp deleted file mode 100644 index f9551fb5e..000000000 --- a/src/sat/cadical/cadical_restore.cpp +++ /dev/null @@ -1,273 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -/*------------------------------------------------------------------------*/ - -// In incremental solving after a first call to 'solve' has finished and -// before calling the internal 'solve' again incrementally we have to -// restore clauses which have the negation of a literal as a witness literal -// on the extension stack, which was added as original literal in a new -// clause or in an assumption. This procedure has to be applied -// recursively, i.e., the literals of restored clauses are treated in the -// same way as literals of a new original clause. -// -// To figure out whether literals are such witnesses we have a 'witness' -// bit for each external literal, which is set in 'block', 'elim', and -// 'decompose' if a clause is pushed on the extension stack. The witness -// bits are recomputed after restoring clauses. -// -// We further mark in the external solver newly internalized external -// literals in 'add' and 'assume' since the last call to 'solve' as tainted -// if they occur negated as a witness literal on the extension stack. Then -// we go through the extension stack and restore all clauses which have a -// tainted literal (and its negation a marked as witness). -// -// Since the API contract disallows to call 'val' and 'failed' in an -// 'UNKNOWN' state. We do not have to internalize literals there. -// -// In order to have tainted literals accepted by the internal solver they -// have to be active and thus we might need to 'reactivate' them before -// restoring clauses if they are inactive. In case they have completely -// been eliminated and removed from the internal solver in 'compact', then -// we just use a new internal variable. This is performed in 'internalize' -// during marking external literals as tainted. -// -// To check that this approach is correct the external solver can maintain a -// stack of original clauses and current assumptions both in terms of -// external literals. Whenever 'solve' determines that the current -// incremental call is satisfiable we check that the (extended) witness does -// satisfy the saved original clauses, as well as all the assumptions. To -// enable these checks set 'opts.check' as well as 'opts.checkwitness' and -// 'opts.checkassumptions' all to 'true'. The model based tester actually -// prefers to enable the 'opts.check' option and the other two are 'true' by -// default anyhow. -// -// See our SAT'19 paper [FazekasBiereScholl-SAT'19] for more details. - -/*------------------------------------------------------------------------*/ - -void External::restore_clause (const vector::const_iterator &begin, - const vector::const_iterator &end, - const int64_t id) { - LOG (begin, end, "restoring external clause[%" PRId64 "]", id); - CADICAL_assert (eclause.empty ()); - CADICAL_assert (id); - for (auto p = begin; p != end; p++) { - eclause.push_back (*p); - if (internal->proof && internal->lrat) { - const auto &elit = *p; - unsigned eidx = (elit > 0) + 2u * (unsigned) abs (elit); - CADICAL_assert ((size_t) eidx < ext_units.size ()); - const int64_t id = ext_units[eidx]; - bool added = ext_flags[abs (elit)]; - if (id && !added) { - ext_flags[abs (elit)] = true; - internal->lrat_chain.push_back (id); - } - } - int ilit = internalize (*p); - internal->add_original_lit (ilit), internal->stats.restoredlits++; - } - if (internal->proof && internal->lrat) { - for (const auto &elit : eclause) { - ext_flags[abs (elit)] = false; - } - } - internal->finish_added_clause_with_id (id, true); - eclause.clear (); - internal->stats.restored++; -} - -/*------------------------------------------------------------------------*/ - -void External::restore_clauses () { - - CADICAL_assert (internal->opts.restoreall == 2 || !tainted.empty ()); - - START (restore); - internal->stats.restorations++; - - struct { - int64_t weakened, satisfied, restored, removed; - } clauses; - memset (&clauses, 0, sizeof clauses); - - if (internal->opts.restoreall && tainted.empty ()) - PHASE ("restore", internal->stats.restorations, - "forced to restore all clauses"); - -#ifndef CADICAL_QUIET - { - unsigned numtainted = 0; - for (const auto b : tainted) - if (b) - numtainted++; - - PHASE ("restore", internal->stats.restorations, - "starting with %u tainted literals %.0f%%", numtainted, - percent (numtainted, 2u * max_var)); - } -#endif - - auto end_of_extension = extension.end (); - auto p = extension.begin (), q = p; - - // Go over all witness labelled clauses on the extension stack, restore - // those necessary, remove restored and flush satisfied clauses. - // - while (p != end_of_extension) { - - clauses.weakened++; - - CADICAL_assert (!*p); - const auto saved = q; // Save old start. - *q++ = *p++; // Copy zero '0'. - - // Copy witness part and try to find a tainted witness literal in it. - // - int tlit = 0; // Negation tainted. - int elit; - // - CADICAL_assert (p != end_of_extension); - // - while ((elit = *q++ = *p++)) { - - if (marked (tainted, -elit)) { - tlit = elit; - LOG ("negation of witness literal %d tainted", tlit); - } - - CADICAL_assert (p != end_of_extension); - } - - // now copy the id of the clause - const int64_t id = ((int64_t) (*p) << 32) + (int64_t) * (p + 1); - LOG ("id is %" PRId64, id); - *q++ = *p++; - *q++ = *p++; - CADICAL_assert (id); - CADICAL_assert (!*p); - *q++ = *p++; - - // Now find 'end_of_clause' (clause starts at 'p') and at the same time - // figure out whether the clause is actually root level satisfied. - // - int satisfied = 0; - auto end_of_clause = p; - while (end_of_clause != end_of_extension && (elit = *end_of_clause)) { - if (!satisfied && fixed (elit) > 0) - satisfied = elit; - end_of_clause++; - } - CADICAL_assert (id); - - // Do not apply our 'FLUSH' rule to remove satisfied (implied) clauses - // if the corresponding option is set simply by resetting 'satisfied'. - // - if (satisfied && !internal->opts.restoreflush) { - LOG (p, end_of_clause, "forced to not remove %d satisfied", - satisfied); - satisfied = 0; - } - - if (satisfied || tlit || internal->opts.restoreall) { - - if (satisfied) { - LOG (p, end_of_clause, - "flushing implied clause satisfied by %d from extension stack", - satisfied); - clauses.satisfied++; - } else { - restore_clause (p, end_of_clause, id); // Might taint literals. - clauses.restored++; - } - - clauses.removed++; - p = end_of_clause; - q = saved; - - } else { - - LOG (p, end_of_clause, "keeping clause on extension stack"); - - while (p != end_of_clause) // Copy clause too. - *q++ = *p++; - } - } - - extension.resize (q - extension.begin ()); - shrink_vector (extension); - -#ifndef CADICAL_QUIET - if (clauses.satisfied) - PHASE ("restore", internal->stats.restorations, - "removed %" PRId64 " satisfied %.0f%% of %" PRId64 - " weakened clauses", - clauses.satisfied, percent (clauses.satisfied, clauses.weakened), - clauses.weakened); - else - PHASE ("restore", internal->stats.restorations, - "no satisfied clause removed out of %" PRId64 - " weakened clauses", - clauses.weakened); - - if (clauses.restored) - PHASE ("restore", internal->stats.restorations, - "restored %" PRId64 " clauses %.0f%% out of %" PRId64 - " weakened clauses", - clauses.restored, percent (clauses.restored, clauses.weakened), - clauses.weakened); - else - PHASE ("restore", internal->stats.restorations, - "no clause restored out of %" PRId64 " weakened clauses", - clauses.weakened); - { - unsigned numtainted = 0; - for (const auto &b : tainted) - if (b) - numtainted++; - - PHASE ("restore", internal->stats.restorations, - "finishing with %u tainted literals %.0f%%", numtainted, - percent (numtainted, 2u * max_var)); - } - -#endif - LOG ("extension stack clean"); - tainted.clear (); - - // Finally recompute the witness bits. - // - witness.clear (); - const auto begin_of_extension = extension.begin (); - p = extension.end (); - while (p != begin_of_extension) { - while (*--p) - CADICAL_assert (p != begin_of_extension); - int elit; - CADICAL_assert (p != begin_of_extension); - --p; - CADICAL_assert (p != begin_of_extension); - CADICAL_assert (*p || *(p - 1)); - --p; - CADICAL_assert (p != begin_of_extension); - CADICAL_assert (!*p); - --p; - CADICAL_assert (p != begin_of_extension); - while ((elit = *--p)) { - mark (witness, elit); - CADICAL_assert (p != begin_of_extension); - } - } - - STOP (restore); -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_score.cpp b/src/sat/cadical/cadical_score.cpp deleted file mode 100644 index 420357929..000000000 --- a/src/sat/cadical/cadical_score.cpp +++ /dev/null @@ -1,57 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -// This initializes variables on the binary 'scores' heap also with -// smallest variable index first (thus picked first) and larger indices at -// the end. -// -void Internal::init_scores (int old_max_var, int new_max_var) { - LOG ("initializing EVSIDS scores from %d to %d", old_max_var + 1, - new_max_var); - for (int i = old_max_var; i < new_max_var; i++) - scores.push_back (i + 1); -} - -// Shuffle the EVSIDS heap. - -void Internal::shuffle_scores () { - if (!opts.shuffle) - return; - if (!opts.shufflescores) - return; - CADICAL_assert (!level); - stats.shuffled++; - LOG ("shuffling scores"); - vector shuffle; - if (opts.shufflerandom) { - scores.erase (); - for (int idx = max_var; idx; idx--) - shuffle.push_back (idx); - Random random (opts.seed); // global seed - random += stats.shuffled; // different every time - for (int i = 0; i <= max_var - 2; i++) { - const int j = random.pick_int (i, max_var - 1); - swap (shuffle[i], shuffle[j]); - } - } else { - while (!scores.empty ()) { - int idx = scores.front (); - (void) scores.pop_front (); - shuffle.push_back (idx); - } - } - score_inc = 0; - for (const auto &idx : shuffle) { - stab[idx] = score_inc++; - scores.push_back (idx); - } -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_shrink.cpp b/src/sat/cadical/cadical_shrink.cpp deleted file mode 100644 index 201c220e7..000000000 --- a/src/sat/cadical/cadical_shrink.cpp +++ /dev/null @@ -1,513 +0,0 @@ -#include "global.h" - -#include "internal.hpp" -#include "reap.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -void Internal::reset_shrinkable () { -#ifdef LOGGING - size_t reset = 0; -#endif - for (const auto &lit : shrinkable) { - LOG ("resetting lit %i", lit); - Flags &f = flags (lit); - CADICAL_assert (f.shrinkable); - f.shrinkable = false; -#ifdef LOGGING - ++reset; -#endif - } - LOG ("resetting %zu shrinkable variables", reset); -} - -void Internal::mark_shrinkable_as_removable ( - int blevel, std::vector::size_type minimized_start) { -#ifdef LOGGING - size_t marked = 0, reset = 0; -#endif -#ifndef CADICAL_NDEBUG - unsigned kept = 0, minireset = 0; - for (; minimized_start < minimized.size (); ++minimized_start) { - const int lit = minimized[minimized_start]; - Flags &f = flags (lit); - const Var &v = var (lit); - if (v.level == blevel) { - CADICAL_assert (!f.poison); - ++minireset; - } else - ++kept; - } - (void) kept; - (void) minireset; -#else - (void) blevel; - (void) minimized_start; -#endif - - for (const int lit : shrinkable) { - Flags &f = flags (lit); - CADICAL_assert (f.shrinkable); - CADICAL_assert (!f.poison); - f.shrinkable = false; -#ifdef LOGGING - ++reset; -#endif - if (f.removable) - continue; - f.removable = true; - minimized.push_back (lit); -#ifdef LOGGING - ++marked; -#endif - } - LOG ("resetting %zu shrinkable variables", reset); - LOG ("marked %zu removable variables", marked); -} - -int inline Internal::shrink_literal (int lit, int blevel, - unsigned max_trail) { - CADICAL_assert (val (lit) < 0); - - Flags &f = flags (lit); - Var &v = var (lit); - CADICAL_assert (v.level <= blevel); - - if (!v.level) { - LOG ("skipping root level assigned %d", (lit)); - return 0; - } - - if (v.reason == external_reason) { - CADICAL_assert (!opts.exteagerreasons); - v.reason = learn_external_reason_clause (-lit, 0, true); - if (!v.reason) { - CADICAL_assert (!v.level); - return 0; - } - } - CADICAL_assert (v.reason != external_reason); - if (f.shrinkable) { - LOG ("skipping already shrinkable literal %d", (lit)); - return 0; - } - - if (v.level < blevel) { - if (f.removable) { - LOG ("skipping removable thus shrinkable %d", (lit)); - return 0; - } - const bool always_minimize_on_lower_blevel = (opts.shrink > 2); - if (always_minimize_on_lower_blevel && minimize_literal (-lit, 1)) { - LOG ("minimized thus shrinkable %d", (lit)); - return 0; - } - LOG ("literal %d on lower blevel %u < %u not removable/shrinkable", - (lit), v.level, blevel); - return -1; - } - - LOG ("marking %d as shrinkable", lit); - f.shrinkable = true; - f.poison = false; - shrinkable.push_back (lit); - if (opts.shrinkreap) { - CADICAL_assert (max_trail < trail.size ()); - const unsigned dist = max_trail - v.trail; - reap.push (dist); - } - return 1; -} - -unsigned Internal::shrunken_block_uip ( - int uip, int blevel, std::vector::reverse_iterator &rbegin_block, - std::vector::reverse_iterator &rend_block, - std::vector::size_type minimized_start, const int uip0) { - CADICAL_assert (clause[0] == uip0); - - LOG ("UIP on level %u, uip: %i (replacing by %i)", blevel, uip, uip0); - CADICAL_assert (rend_block > rbegin_block); - CADICAL_assert (rend_block < clause.rend ()); - unsigned block_shrunken = 0; - *rbegin_block = -uip; - Var &v = var (-uip); - Level &l = control[v.level]; - l.seen.trail = v.trail; - l.seen.count = 1; - - Flags &f = flags (-uip); - if (!f.seen) { - analyzed.push_back (-uip); - f.seen = true; - } - - flags (-uip).keep = true; - for (auto p = rbegin_block + 1; p != rend_block; ++p) { - const int lit = *p; - if (lit == -uip0) - continue; - *p = uip0; - // if (lit == -uip) continue; - ++block_shrunken; - CADICAL_assert (clause[0] == uip0); - } - mark_shrinkable_as_removable (blevel, minimized_start); - CADICAL_assert (clause[0] == uip0); - return block_shrunken; -} - -void inline Internal::shrunken_block_no_uip ( - const std::vector::reverse_iterator &rbegin_block, - const std::vector::reverse_iterator &rend_block, - unsigned &block_minimized, const int uip0) { - STOP (shrink); - START (minimize); - CADICAL_assert (rend_block > rbegin_block); - LOG ("no UIP found, now minimizing"); - for (auto p = rbegin_block; p != rend_block; ++p) { - CADICAL_assert (p != clause.rend () - 1); - const int lit = *p; - if (opts.minimize && minimize_literal (-lit)) { - CADICAL_assert (!flags (lit).keep); - ++block_minimized; - *p = uip0; - } else { - flags (lit).keep = true; - CADICAL_assert (flags (lit).keep); - } - } - STOP (minimize); - START (shrink); -} - -void Internal::push_literals_of_block ( - const std::vector::reverse_iterator &rbegin_block, - const std::vector::reverse_iterator &rend_block, int blevel, - unsigned max_trail) { - CADICAL_assert (rbegin_block < rend_block); - for (auto p = rbegin_block; p != rend_block; ++p) { - CADICAL_assert (p != clause.rend () - 1); - CADICAL_assert (!flags (*p).keep); - const int lit = *p; - LOG ("pushing lit %i of blevel %i", lit, var (lit).level); -#ifndef CADICAL_NDEBUG - int tmp = -#endif - shrink_literal (lit, blevel, max_trail); - CADICAL_assert (tmp > 0); - } -} - -unsigned inline Internal::shrink_next (int blevel, unsigned &open, - unsigned &max_trail) { - const auto &t = &trail; - if (opts.shrinkreap) { - CADICAL_assert (!reap.empty ()); - const unsigned dist = reap.pop (); - --open; - CADICAL_assert (dist <= max_trail); - const unsigned pos = max_trail - dist; - CADICAL_assert (pos < t->size ()); - const int uip = (*t)[pos]; - CADICAL_assert (val (uip) > 0); - LOG ("trying to shrink literal %d at trail[%u] and level %d", uip, pos, - blevel); - return uip; - } else { - int uip; -#ifndef CADICAL_NDEBUG - unsigned init_max_trail = max_trail; -#endif - do { - CADICAL_assert (max_trail <= init_max_trail); - uip = (*t)[max_trail--]; - } while (!flags (uip).shrinkable); - --open; - LOG ("open is now %d, uip = %d, level %d", open, uip, blevel); - return uip; - } - (void) blevel; -} - -unsigned inline Internal::shrink_along_reason (int uip, int blevel, - bool resolve_large_clauses, - bool &failed_ptr, - unsigned max_trail) { - LOG ("shrinking along the reason of lit %i", uip); - unsigned open = 0; -#ifndef CADICAL_NDEBUG - const Flags &f = flags (uip); -#endif - const Var &v = var (uip); - - CADICAL_assert (f.shrinkable); - CADICAL_assert (v.level == blevel); - CADICAL_assert (v.reason); - - if (opts.minimizeticks) - stats.ticks.search[stable]++; - - if (resolve_large_clauses || v.reason->size == 2) { - const Clause &c = *v.reason; - LOG (v.reason, "resolving with reason"); - for (int lit : c) { - if (lit == uip) - continue; - CADICAL_assert (val (lit) < 0); - int tmp = shrink_literal (lit, blevel, max_trail); - if (tmp < 0) { - failed_ptr = true; - break; - } - if (tmp > 0) { - ++open; - } - } - } else { - failed_ptr = true; - } - return open; -} - -unsigned -Internal::shrink_block (std::vector::reverse_iterator &rbegin_lits, - std::vector::reverse_iterator &rend_block, - int blevel, unsigned &open, - unsigned &block_minimized, const int uip0, - unsigned max_trail) { - CADICAL_assert (shrinkable.empty ()); - CADICAL_assert (blevel <= this->level); - CADICAL_assert (open < clause.size ()); - CADICAL_assert (rbegin_lits >= clause.rbegin ()); - CADICAL_assert (rend_block < clause.rend ()); - CADICAL_assert (rbegin_lits < rend_block); - CADICAL_assert (opts.shrink); - -#ifdef LOGGING - - LOG ("trying to shrink %u literals on level %u", open, blevel); - - const auto &t = &trail; - - LOG ("maximum trail position %zd on level %u", t->size (), blevel); - if (opts.shrinkreap) - LOG ("shrinking up to %u", max_trail); -#endif - - const bool resolve_large_clauses = (opts.shrink > 1); - bool failed = false; - unsigned block_shrunken = 0; - std::vector::size_type minimized_start = minimized.size (); - int uip = uip0; - unsigned max_trail2 = max_trail; - - if (!failed) { - push_literals_of_block (rbegin_lits, rend_block, blevel, max_trail); - CADICAL_assert (!opts.shrinkreap || reap.size () == open); - - CADICAL_assert (open > 0); - while (!failed) { - CADICAL_assert (!opts.shrinkreap || reap.size () == open); - uip = shrink_next (blevel, open, max_trail); - if (open == 0) { - break; - } - open += shrink_along_reason (uip, blevel, resolve_large_clauses, - failed, max_trail2); - CADICAL_assert (open >= 1); - } - - if (!failed) - LOG ("shrinking found UIP %i on level %i (open: %d)", uip, blevel, - open); - else - LOG ("shrinking failed on level %i", blevel); - } - - if (failed) - reset_shrinkable (), shrunken_block_no_uip (rbegin_lits, rend_block, - block_minimized, uip0); - else - block_shrunken = shrunken_block_uip (uip, blevel, rbegin_lits, - rend_block, minimized_start, uip0); - - if (opts.shrinkreap) - reap.clear (); - shrinkable.clear (); - return block_shrunken; -} - -// Smaller level and trail. Comparing literals on their level is necessary -// for chronological backtracking, since trail order might in this case not -// respect level order. - -struct shrink_trail_negative_rank { - Internal *internal; - shrink_trail_negative_rank (Internal *s) : internal (s) {} - typedef uint64_t Type; - Type operator() (int a) { - Var &v = internal->var (a); - uint64_t res = v.level; - res <<= 32; - res |= v.trail; - return ~res; - } -}; - -struct shrink_trail_larger { - Internal *internal; - shrink_trail_larger (Internal *s) : internal (s) {} - bool operator() (const int &a, const int &b) const { - return shrink_trail_negative_rank (internal) (a) < - shrink_trail_negative_rank (internal) (b); - } -}; - -// Finds the beginning of the block (rend_block, non-included) ending at -// rend_block (included). Then tries to shrinks and minimizes literals the -// block -std::vector::reverse_iterator Internal::minimize_and_shrink_block ( - std::vector::reverse_iterator &rbegin_block, - unsigned &total_shrunken, unsigned &total_minimized, const int uip0) - -{ - LOG ("shrinking block"); - CADICAL_assert (rbegin_block < clause.rend () - 1); - int blevel; - unsigned open = 0; - unsigned max_trail; - - // find begining of block; - std::vector::reverse_iterator rend_block; - { - CADICAL_assert (rbegin_block <= clause.rend ()); - const int lit = *rbegin_block; - const int idx = vidx (lit); - blevel = vtab[idx].level; - max_trail = vtab[idx].trail; - LOG ("Block at level %i (first lit: %i)", blevel, lit); - - rend_block = rbegin_block; - bool finished; - do { - CADICAL_assert (rend_block < clause.rend () - 1); - const int lit = *(++rend_block); - const int idx = vidx (lit); - finished = (blevel != vtab[idx].level); - if (!finished && (unsigned) vtab[idx].trail > max_trail) - max_trail = vtab[idx].trail; - ++open; - LOG ( - "testing if lit %i is on the same level (of lit: %i, global: %i)", - lit, vtab[idx].level, blevel); - - } while (!finished); - } - CADICAL_assert (open > 0); - CADICAL_assert (open < clause.size ()); - CADICAL_assert (rbegin_block < clause.rend ()); - CADICAL_assert (rend_block < clause.rend ()); - - unsigned block_shrunken = 0, block_minimized = 0; - if (open < 2) { - flags (*rbegin_block).keep = true; - minimized.push_back (*rbegin_block); - } else - block_shrunken = shrink_block (rbegin_block, rend_block, blevel, open, - block_minimized, uip0, max_trail); - - LOG ("shrunken %u literals on level %u (including %u minimized)", - block_shrunken, blevel, block_minimized); - - total_shrunken += block_shrunken; - total_minimized += block_minimized; - - return rend_block; -} - -void Internal::shrink_and_minimize_clause () { - CADICAL_assert (opts.minimize || opts.shrink > 0); - LOG (clause, "shrink first UIP clause"); - - START (shrink); - external->check_learned_clause (); // check 1st UIP learned clause first - MSORT (opts.radixsortlim, clause.begin (), clause.end (), - shrink_trail_negative_rank (this), shrink_trail_larger (this)); - unsigned total_shrunken = 0; - unsigned total_minimized = 0; - - LOG (clause, "shrink first UIP clause (CADICAL_asserting lit: %i)", clause[0]); - - auto rend_lits = clause.rend () - 1; - auto rend_block = clause.rbegin (); - const int uip0 = clause[0]; - - // for direct LRAT we remember how the clause used to look - vector old_clause_lrat; - CADICAL_assert (minimize_chain.empty ()); - if (lrat) - for (auto &i : clause) - old_clause_lrat.push_back (i); - - while (rend_block != rend_lits) { - rend_block = minimize_and_shrink_block (rend_block, total_shrunken, - total_minimized, uip0); - } - - LOG (clause, - "post shrink pass (with uips, not removed) first UIP clause"); - LOG (old_clause_lrat, "(used for lratdirect) before shrink: clause"); -#if defined(LOGGING) || !defined(CADICAL_NDEBUG) - const unsigned old_size = clause.size (); -#endif - std::vector stack; - { - std::vector::size_type i = 1; - for (std::vector::size_type j = 1; j < clause.size (); ++j) { - CADICAL_assert (i <= j); - clause[i] = clause[j]; - if (lrat) { - CADICAL_assert (j < old_clause_lrat.size ()); - CADICAL_assert (mini_chain.empty ()); - if (clause[j] != old_clause_lrat[j]) { - calculate_minimize_chain (-old_clause_lrat[j], stack); - for (auto p : mini_chain) { - minimize_chain.push_back (p); - } - mini_chain.clear (); - } - } - if (clause[j] == uip0) { - continue; - } - CADICAL_assert (flags (clause[i]).keep); - ++i; - LOG ("keeping literal %i", clause[j]); - } - clause.resize (i); - } - CADICAL_assert (old_size == - (unsigned) clause.size () + total_shrunken + total_minimized); - LOG (clause, "after shrinking first UIP clause"); - LOG ("clause shrunken by %zd literals (including %u minimized)", - old_size - clause.size (), total_minimized); - - stats.shrunken += total_shrunken; - stats.minishrunken += total_minimized; - STOP (shrink); - - START (minimize); - clear_minimized_literals (); - for (auto p = minimize_chain.rbegin (); p != minimize_chain.rend (); - p++) { - lrat_chain.push_back (*p); - } - minimize_chain.clear (); - STOP (minimize); -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_signal.cpp b/src/sat/cadical/cadical_signal.cpp deleted file mode 100644 index 099277f03..000000000 --- a/src/sat/cadical/cadical_signal.cpp +++ /dev/null @@ -1,144 +0,0 @@ -#include "global.h" - -#include "signal.hpp" -#include "cadical.hpp" -#include "resources.hpp" - -/*------------------------------------------------------------------------*/ - -#include -#include - -/*------------------------------------------------------------------------*/ - -#ifndef WIN32 -extern "C" { -#include -} -#endif - -ABC_NAMESPACE_IMPL_START - -/*------------------------------------------------------------------------*/ - -// Signal handlers for printing statistics even if solver is interrupted. - -namespace CaDiCaL { - -static volatile bool caught_signal = false; -static Handler *signal_handler; - -#ifndef WIN32 - -static volatile bool caught_alarm = false; -static volatile bool alarm_set = false; -static int alarm_time = -1; - -void Handler::catch_alarm () { catch_signal (SIGALRM); } - -#endif - -#define SIGNALS \ - SIGNAL (SIGABRT) \ - SIGNAL (SIGINT) \ - SIGNAL (SIGSEGV) \ - SIGNAL (SIGTERM) - -#define SIGNAL(SIG) static void (*SIG##_handler) (int); -SIGNALS -#undef SIGNAL - -#ifndef WIN32 - -static void (*SIGALRM_handler) (int); - -void Signal::reset_alarm () { - if (!alarm_set) - return; - (void) signal (SIGALRM, SIGALRM_handler); - SIGALRM_handler = 0; - caught_alarm = false; - alarm_set = false; - alarm_time = -1; -} - -#endif - -void Signal::reset () { - signal_handler = 0; -#define SIGNAL(SIG) \ - (void) signal (SIG, SIG##_handler); \ - SIG##_handler = 0; - SIGNALS -#undef SIGNAL -#ifndef WIN32 - reset_alarm (); -#endif - caught_signal = false; -} - -const char *Signal::name (int sig) { -#define SIGNAL(SIG) \ - if (sig == SIG) \ - return #SIG; - SIGNALS -#undef SIGNAL -#ifndef WIN32 - if (sig == SIGALRM) - return "SIGALRM"; -#endif - return "UNKNOWN"; -} - -// TODO printing is not reentrant and might lead to deadlock if the signal -// is raised during another print attempt (and locked IO is used). To avoid -// this we have to either run our own low-level printing routine here or in -// 'Message' or just dump those statistics somewhere else were we have -// exclusive access to. All these solutions are painful and not elegant. - -static void catch_signal (int sig) { -#ifndef WIN32 - if (sig == SIGALRM && absolute_real_time () >= alarm_time) { - if (!caught_alarm) { - caught_alarm = true; - if (signal_handler) - signal_handler->catch_alarm (); - } - Signal::reset_alarm (); - } else -#endif - { - if (!caught_signal) { - caught_signal = true; - if (signal_handler) - signal_handler->catch_signal (sig); - } - Signal::reset (); - ::raise (sig); - } -} - -void Signal::set (Handler *h) { - signal_handler = h; -#define SIGNAL(SIG) SIG##_handler = signal (SIG, catch_signal); - SIGNALS -#undef SIGNAL -} - -#ifndef WIN32 - -void Signal::alarm (int seconds) { - CADICAL_assert (seconds >= 0); - CADICAL_assert (!alarm_set); - CADICAL_assert (alarm_time < 0); - SIGALRM_handler = signal (SIGALRM, catch_signal); - alarm_set = true; - alarm_time = absolute_real_time () + seconds; - ::alarm (seconds); -} - -#endif - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_solution.cpp b/src/sat/cadical/cadical_solution.cpp deleted file mode 100644 index 1d7514e42..000000000 --- a/src/sat/cadical/cadical_solution.cpp +++ /dev/null @@ -1,56 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -// Sam Buss suggested to debug the case where a solver incorrectly claims -// the formula to be unsatisfiable by checking every learned clause to be -// satisfied by a satisfying assignment. Thus the first inconsistent -// learned clause will be immediately flagged without the need to generate -// proof traces and perform forward proof checking. The incorrectly derived -// clause will raise an abort signal and thus allows to debug the issue with -// a symbolic debugger immediately. - -void External::check_solution_on_learned_clause () { - CADICAL_assert (solution); - for (const auto &lit : internal->clause) - if (sol (internal->externalize (lit)) == lit) - return; - fatal_message_start (); - fputs ("learned clause unsatisfied by solution:\n", stderr); - for (const auto &lit : internal->clause) - fprintf (stderr, "%d ", lit); - fputc ('0', stderr); - fatal_message_end (); -} - -void External::check_solution_on_shrunken_clause (Clause *c) { - CADICAL_assert (solution); - for (const auto &lit : *c) - if (sol (internal->externalize (lit)) == lit) - return; - fatal_message_start (); - for (const auto &lit : *c) - fprintf (stderr, "%d ", lit); - fputc ('0', stderr); - fatal_message_end (); -} - -void External::check_no_solution_after_learning_empty_clause () { - CADICAL_assert (solution); - FATAL ("learned empty clause but got solution"); -} - -void External::check_solution_on_learned_unit_clause (int unit) { - CADICAL_assert (solution); - if (sol (internal->externalize (unit)) == unit) - return; - FATAL ("learned unit %d contradicts solution", unit); -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_solver.cpp b/src/sat/cadical/cadical_solver.cpp deleted file mode 100644 index df051f4de..000000000 --- a/src/sat/cadical/cadical_solver.cpp +++ /dev/null @@ -1,1764 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -/*------------------------------------------------------------------------*/ - -namespace CaDiCaL { - -/*------------------------------------------------------------------------*/ - -// See corresponding header file 'cadical.hpp' (!) for more information. -// -// Again, to avoid confusion, note that, 'cadical.hpp' is the header file of -// this file 'solver.cpp', since we want to call the application and main -// file 'cadical.cpp', while at the same time using 'cadical.hpp' as the -// main header file of the library (and not 'solver.hpp'). - -/*------------------------------------------------------------------------*/ -#ifdef LOGGING - -// Needs to be kept in sync with the color schemes used in 'logging.cpp'. -// -#define api_code blue_code // API call color -#define log_code magenta_code // standard/default logging color -#define emph_code bright_magenta_code // emphasized logging color - -#endif -/*------------------------------------------------------------------------*/ - -// Log state transitions. - -#define STATE(S) \ - do { \ - CADICAL_assert (is_power_of_two (S)); \ - if (_state == S) \ - break; \ - _state = S; \ - LOG ("API enters state %s" #S "%s", tout.emph_code (), \ - tout.normal_code ()); \ - } while (0) - -void Solver::transition_to_steady_state () { - if (state () == CONFIGURING) { - LOG ("API leaves state %sCONFIGURING%s", tout.emph_code (), - tout.normal_code ()); - if (internal->opts.check && internal->opts.checkproof) { - internal->check (); - } - } else if (state () == SATISFIED) { - LOG ("API leaves state %sSATISFIED%s", tout.emph_code (), - tout.normal_code ()); - external->reset_assumptions (); - external->reset_concluded (); - external->reset_constraint (); - } else if (state () == UNSATISFIED) { - LOG ("API leaves state %sUNSATISFIED%s", tout.emph_code (), - tout.normal_code ()); - external->reset_assumptions (); - external->reset_concluded (); - external->reset_constraint (); - } else if (state() == INCONCLUSIVE) { - external->reset_assumptions (); - external->reset_concluded (); - external->reset_constraint (); - } - if (state () != STEADY) - STATE (STEADY); -} - -/*------------------------------------------------------------------------*/ -#ifdef LOGGING -/*------------------------------------------------------------------------*/ - -// The following logging code is useful for debugging mostly (or trying to -// understand what the solver is actually doing). It needs to be enabled -// during configuration using the '-l' option for './configure', which -// forces 'LOGGING' to be defined during compilation. This includes all the -// logging code, which then still needs to enabled during run-time with the -// '-l' or 'log' option. - -static void log_api_call (Internal *internal, const char *name, - const char *suffix) { - Logger::log (internal, "API call %s'%s ()'%s %s", tout.api_code (), name, - tout.log_code (), suffix); -} - -static void log_api_call (Internal *internal, const char *name, int arg, - const char *suffix) { - Logger::log (internal, "API call %s'%s (%d)'%s %s", tout.api_code (), - name, arg, tout.log_code (), suffix); -} - -static void log_api_call (Internal *internal, const char *name, - const char *arg, const char *suffix) { - Logger::log (internal, "API call %s'%s (\"%s\")'%s %s", tout.api_code (), - name, arg, tout.log_code (), suffix); -} - -static void log_api_call (Internal *internal, const char *name, - const char *a1, int a2, const char *s) { - Logger::log (internal, "API call %s'%s (\"%s\", %d)'%s %s", - tout.api_code (), name, a1, a2, tout.log_code (), s); -} - -/*------------------------------------------------------------------------*/ - -// We factored out API call begin/end logging and use overloaded functions. - -static void log_api_call_begin (Internal *internal, const char *name) { - Logger::log_empty_line (internal); - log_api_call (internal, name, "started"); -} - -static void log_api_call_begin (Internal *internal, const char *name, - int arg) { - Logger::log_empty_line (internal); - log_api_call (internal, name, arg, "started"); -} - -static void log_api_call_begin (Internal *internal, const char *name, - const char *arg) { - Logger::log_empty_line (internal); - log_api_call (internal, name, arg, "started"); -} - -static void log_api_call_begin (Internal *internal, const char *name, - const char *arg1, int arg2) { - Logger::log_empty_line (internal); - log_api_call (internal, name, arg1, arg2, "started"); -} - -/*------------------------------------------------------------------------*/ - -static void log_api_call_end (Internal *internal, const char *name) { - log_api_call (internal, name, "succeeded"); -} - -static void log_api_call_end (Internal *internal, const char *name, - int lit) { - log_api_call (internal, name, lit, "succeeded"); -} - -static void log_api_call_end (Internal *internal, const char *name, - const char *arg) { - Logger::log_empty_line (internal); - log_api_call (internal, name, arg, "succeeded"); -} - -static void log_api_call_end (Internal *internal, const char *name, - const char *arg, bool res) { - log_api_call (internal, name, arg, res ? "succeeded" : "failed"); -} - -static void log_api_call_end (Internal *internal, const char *name, - const char *arg, int val, bool res) { - log_api_call (internal, name, arg, val, res ? "succeeded" : "failed"); -} - -static void log_api_call_returns (Internal *internal, const char *name, - bool res) { - log_api_call (internal, name, res ? "returns 'true'" : "returns 'false'"); -} - -static void log_api_call_returns (Internal *internal, const char *name, - int res) { - char fmt[32]; - snprintf (fmt, sizeof fmt, "returns '%d'", res); - log_api_call (internal, name, fmt); -} - -static void log_api_call_returns (Internal *internal, const char *name, - int64_t res) { - char fmt[32]; - snprintf (fmt, sizeof fmt, "returns '%" PRId64 "'", res); - log_api_call (internal, name, fmt); -} - -static void log_api_call_returns (Internal *internal, const char *name, - int lit, int res) { - char fmt[32]; - snprintf (fmt, sizeof fmt, "returns '%d'", res); - log_api_call (internal, name, lit, fmt); -} - -static void log_api_call_returns (Internal *internal, const char *name, - const char *arg, bool res) { - log_api_call (internal, name, arg, - res ? "returns 'true'" : "returns 'false'"); -} - -static void log_api_call_returns (Internal *internal, const char *name, - int lit, bool res) { - log_api_call (internal, name, lit, - res ? "returns 'true'" : "returns 'false'"); -} - -static void log_api_call_returns (Internal *internal, const char *name, - const char *arg, const char *res) { - Logger::log (internal, "API call %s'%s (\"%s\")'%s returns '%s'", - tout.api_code (), name, arg, tout.log_code (), - res ? res : ""); -} - -static void log_api_call_returns (Internal *internal, const char *name, - const char *arg1, int arg2, - const char *res) { - Logger::log (internal, "API call %s'%s (\"%s\", %d)'%s returns '%s'", - tout.api_code (), name, arg1, arg2, tout.log_code (), - res ? res : ""); -} - -/*------------------------------------------------------------------------*/ - -#define LOG_API_CALL_BEGIN(...) \ - do { \ - if (!internal->opts.log) \ - break; \ - log_api_call_begin (internal, __VA_ARGS__); \ - } while (0) - -#define LOG_API_CALL_END(...) \ - do { \ - if (!internal->opts.log) \ - break; \ - log_api_call_end (internal, __VA_ARGS__); \ - } while (0) - -#define LOG_API_CALL_RETURNS(...) \ - do { \ - if (!internal->opts.log) \ - break; \ - log_api_call_returns (internal, __VA_ARGS__); \ - } while (0) - -/*------------------------------------------------------------------------*/ -#else // end of 'then' part of 'ifdef LOGGING' -/*------------------------------------------------------------------------*/ - -#define LOG_API_CALL_BEGIN(...) \ - do { \ - } while (0) -#define LOG_API_CALL_END(...) \ - do { \ - } while (0) -#define LOG_API_CALL_RETURNS(...) \ - do { \ - } while (0) - -/*------------------------------------------------------------------------*/ -#endif // end of 'else' part of 'ifdef LOGGING' -/*------------------------------------------------------------------------*/ - -/*------------------------------------------------------------------------*/ -#ifndef CADICAL_NTRACING -/*------------------------------------------------------------------------*/ - -#define TRACE(...) \ - do { \ - /*if ((this == 0)) break; */ /* gcc-12 produces warning */ \ - if ((internal == 0)) \ - break; \ - LOG_API_CALL_BEGIN (__VA_ARGS__); \ - if (!trace_api_file) \ - break; \ - trace_api_call (__VA_ARGS__); \ - } while (0) - -void Solver::trace_api_call (const char *s0) const { - CADICAL_assert (trace_api_file); - LOG ("TRACE %s", s0); - fprintf (trace_api_file, "%s\n", s0); - fflush (trace_api_file); -} - -void Solver::trace_api_call (const char *s0, int i1) const { - CADICAL_assert (trace_api_file); - LOG ("TRACE %s %d", s0, i1); - fprintf (trace_api_file, "%s %d\n", s0, i1); - fflush (trace_api_file); -} - -void Solver::trace_api_call (const char *s0, const char *s1) const { - CADICAL_assert (trace_api_file); - LOG ("TRACE %s %s", s0, s1); - fprintf (trace_api_file, "%s %s\n", s0, s1); - fflush (trace_api_file); -} - -void Solver::trace_api_call (const char *s0, const char *s1, int i2) const { - CADICAL_assert (trace_api_file); - LOG ("TRACE %s %s %d", s0, s1, i2); - fprintf (trace_api_file, "%s %s %d\n", s0, s1, i2); - fflush (trace_api_file); -} - -/*------------------------------------------------------------------------*/ - -// The global 'tracing_api_calls_through_environment_variable_method' flag -// is used to ensure that only one solver traces to a file. Otherwise the -// method to use an environment variable to point to the trace file is -// bogus, since those different solver instances would all write to the same -// file producing garbage. A more sophisticated solution would use a -// different mechanism to tell the solver to which file to trace to, but in -// our experience it is quite convenient to get traces out of applications -// which use the solver as library by just setting an environment variable -// without requiring to change any application code. -// -static bool tracing_api_calls_through_environment_variable_method; - -/*------------------------------------------------------------------------*/ -#else // CADICAL_NTRACING -/*------------------------------------------------------------------------*/ - -#define TRACE(...) \ - do { \ - } while (0) - -/*------------------------------------------------------------------------*/ -#endif -/*------------------------------------------------------------------------*/ - -static bool tracing_nb_lidrup_env_var_method = false; - -Solver::Solver () { - -#ifndef CADICAL_NTRACING - const char *path = getenv ("CADICAL_API_TRACE"); - if (!path) - path = getenv ("CADICALAPITRACE"); - if (path) { - if (tracing_api_calls_through_environment_variable_method) - FATAL ("can not trace API calls of two solver instances " - "using environment variable 'CADICAL_API_TRACE'"); - if (!(trace_api_file = fopen (path, "w"))) - FATAL ("failed to open file '%s' to trace API calls " - "using environment variable 'CADICAL_API_TRACE'", - path); - close_trace_api_file = true; - tracing_api_calls_through_environment_variable_method = true; - } else { - tracing_api_calls_through_environment_variable_method = false; - close_trace_api_file = false; - trace_api_file = 0; - } -#endif - - adding_clause = false; - adding_constraint = false; - _state = INITIALIZING; - internal = new Internal (); - DeferDeletePtr delete_internal (internal); - TRACE ("init"); - external = new External (internal); - DeferDeletePtr delete_external (external); - STATE (CONFIGURING); -#ifndef CADICAL_NTRACING - if (tracing_api_calls_through_environment_variable_method) - message ("tracing API calls to '%s'", path); -#endif - - const char *lidrup_path = getenv ("CADICAL_LIDRUP_TRACE"); - if (!lidrup_path) - lidrup_path = getenv ("CADICALLIDRUPTRACE"); - if (lidrup_path) { - - // if (tracing_nb_lidrup_env_var_method) - // FATAL ("can not trace LIDRUP of two solver instances " - // "using environment variable 'CADICAL_LIDRUP_TRACE'"); - // Here we use the solver interface to setup non-binary IDRUP tracing to - // the defined file. Options set by the user can and will overwrite - // these settings if neeed be. - set ("lidrup", 1); - set ("binary", 0); - trace_proof (lidrup_path); - tracing_nb_lidrup_env_var_method = true; - } else { - tracing_nb_lidrup_env_var_method = false; - } - - delete_internal.release (); - delete_external.release (); -} - -Solver::~Solver () { - - TRACE ("reset"); - REQUIRE_VALID_OR_SOLVING_STATE (); - STATE (DELETING); - - tracing_nb_lidrup_env_var_method = false; - -#ifdef LOGGING - // - // After deleting 'internal' logging does not work anymore. - // - bool logging = internal->opts.log; - int level = internal->level; - string prefix = internal->prefix; -#endif - - delete internal; - delete external; - -#ifndef CADICAL_NTRACING - if (close_trace_api_file) { - close_trace_api_file = false; - CADICAL_assert (trace_api_file); - CADICAL_assert (tracing_api_calls_through_environment_variable_method); - fclose (trace_api_file); - tracing_api_calls_through_environment_variable_method = false; - } -#endif - -#ifdef LOGGING - // - // Need to log success of this API call manually. - // - if (logging) { - printf ("%s%sLOG %s%d%s API call %s'reset ()'%s succeeded%s\n", - prefix.c_str (), tout.log_code (), tout.emph_code (), level, - tout.log_code (), tout.api_code (), tout.log_code (), - tout.normal_code ()); - fflush (stdout); - } -#endif -} - -/*------------------------------------------------------------------------*/ - -int Solver::vars () { - TRACE ("vars"); - REQUIRE_VALID_OR_SOLVING_STATE (); - int res = external->max_var; - LOG_API_CALL_RETURNS ("vars", res); - return res; -} - -void Solver::reserve (int min_max_var) { - TRACE ("reserve", min_max_var); - REQUIRE_VALID_STATE (); - transition_to_steady_state (); - external->reset_extended (); - external->init (min_max_var); - LOG_API_CALL_END ("reserve", min_max_var); -} - -int Solver::reserve_difference (int number_of_vars) { - TRACE ("reserve_difference", number_of_vars); - REQUIRE_VALID_STATE (); - transition_to_steady_state (); - external->reset_extended (); - int new_max_var = external->max_var + number_of_vars; - external->init (new_max_var); - LOG_API_CALL_END ("reserve_difference", number_of_vars); - return new_max_var; -} - -/*------------------------------------------------------------------------*/ -#ifndef CADICAL_NTRACING - -void Solver::trace_api_calls (FILE *file) { - LOG_API_CALL_BEGIN ("trace_api_calls"); - REQUIRE_VALID_STATE (); - REQUIRE (file != 0, "invalid zero file argument"); - REQUIRE (!tracing_api_calls_through_environment_variable_method, - "already tracing API calls " - "using environment variable 'CADICAL_API_TRACE'"); - REQUIRE (!trace_api_file, "called twice"); - trace_api_file = file; - LOG_API_CALL_END ("trace_api_calls"); - trace_api_call ("init"); -} - -#endif -/*------------------------------------------------------------------------*/ - -bool Solver::is_valid_option (const char *name) { - return Options::has (name); -} - -bool Solver::is_preprocessing_option (const char *name) { - return Options::is_preprocessing_option (name); -} - -bool Solver::is_valid_long_option (const char *arg) { - string name; - int tmp; - return Options::parse_long_option (arg, name, tmp); -} - -int Solver::get (const char *arg) { - REQUIRE_VALID_OR_SOLVING_STATE (); - return internal->opts.get (arg); -} - -bool Solver::set (const char *arg, int val) { - TRACE ("set", arg, val); - REQUIRE_VALID_STATE (); - if (strcmp (arg, "log") && strcmp (arg, "quiet") && - strcmp (arg, "report") && strcmp (arg, "verbose")) { - REQUIRE ( - state () == CONFIGURING, - "can only set option 'set (\"%s\", %d)' right after initialization", - arg, val); - } - bool res = internal->opts.set (arg, val); - LOG_API_CALL_END ("set", arg, val, res); - - return res; -} - -bool Solver::set_long_option (const char *arg) { - LOG_API_CALL_BEGIN ("set", arg); - REQUIRE_VALID_STATE (); - REQUIRE (state () == CONFIGURING, - "can only set option '%s' right after initialization", arg); - bool res; - if (arg[0] != '-' || arg[1] != '-') - res = false; - else { - int val; - string name; - res = Options::parse_long_option (arg, name, val); - if (res) - set (name.c_str (), val); - } - LOG_API_CALL_END ("set", arg, res); - return res; -} - -void Solver::optimize (int arg) { - LOG_API_CALL_BEGIN ("optimize", arg); - REQUIRE_VALID_STATE (); - internal->opts.optimize (arg); - LOG_API_CALL_END ("optimize", arg); -} - -bool Solver::limit (const char *arg, int val) { - TRACE ("limit", arg, val); - REQUIRE_VALID_STATE (); - bool res = internal->limit (arg, val); - LOG_API_CALL_END ("limit", arg, val, res); - return res; -} - -bool Solver::is_valid_limit (const char *arg) { - return Internal::is_valid_limit (arg); -} - -void Solver::prefix (const char *str) { - LOG_API_CALL_BEGIN ("prefix", str); - REQUIRE_VALID_OR_SOLVING_STATE (); - internal->prefix = str; - LOG_API_CALL_END ("prefix", str); -} - -bool Solver::is_valid_configuration (const char *name) { - return Config::has (name); -} - -bool Solver::configure (const char *name) { - TRACE ("configure", name); - LOG_API_CALL_BEGIN ("configure", name); - REQUIRE_VALID_STATE (); - REQUIRE (state () == CONFIGURING, - "can only set configuration '%s' right after initialization", - name); - bool res = Config::set (internal->opts, name); - LOG_API_CALL_END ("configure", name, res); - return res; -} - -/*===== IPASIR BEGIN =====================================================*/ - -void Solver::add (int lit) { - TRACE ("add", lit); - REQUIRE_VALID_STATE (); - if (lit) - REQUIRE_VALID_LIT (lit); - transition_to_steady_state (); - external->add (lit); - adding_clause = lit; - if (adding_clause) - STATE (ADDING); - else if (!adding_constraint) - STATE (STEADY); - LOG_API_CALL_END ("add", lit); -} - -void Solver::clause (int a) { - REQUIRE_VALID_LIT (a); - add (a), add (0); -} - -void Solver::clause (int a, int b) { - REQUIRE_VALID_LIT (a); - REQUIRE_VALID_LIT (b); - add (a), add (b), add (0); -} - -void Solver::clause (int a, int b, int c) { - REQUIRE_VALID_LIT (a); - REQUIRE_VALID_LIT (b); - REQUIRE_VALID_LIT (c); - add (a), add (b), add (c), add (0); -} - -void Solver::clause (int a, int b, int c, int d) { - REQUIRE_VALID_LIT (a); - REQUIRE_VALID_LIT (b); - REQUIRE_VALID_LIT (c); - REQUIRE_VALID_LIT (d); - add (a), add (b), add (c), add (d), add (0); -} - -void Solver::clause (int a, int b, int c, int d, int e) { - REQUIRE_VALID_LIT (a); - REQUIRE_VALID_LIT (b); - REQUIRE_VALID_LIT (c); - REQUIRE_VALID_LIT (d); - REQUIRE_VALID_LIT (e); - add (a), add (b), add (c), add (d), add (e), add (0); -} - -void Solver::clause (const int *lits, size_t size) { - REQUIRE (!size || lits, - "first argument 'lits' zero while second argument 'size' not"); - const int *end = lits + size; - for (const int *p = lits; p != end; p++) { - const int lit = *p; - REQUIRE_VALID_LIT (lit); - add (lit); - } - add (0); -} - -void Solver::clause (const std::vector &lits) { - for (auto lit : lits) { - REQUIRE_VALID_LIT (lit); - add (lit); - } - add (0); -} - -bool Solver::inconsistent () { return internal->unsat; } - -void Solver::constrain (int lit) { - TRACE ("constrain", lit); - REQUIRE_VALID_STATE (); - if (lit) - REQUIRE_VALID_LIT (lit); - transition_to_steady_state (); - external->constrain (lit); - adding_constraint = lit; - if (adding_constraint) - STATE (ADDING); - else if (!adding_clause) - STATE (STEADY); - LOG_API_CALL_END ("constrain", lit); -} - -void Solver::assume (int lit) { - TRACE ("assume", lit); - REQUIRE_VALID_STATE (); - REQUIRE_VALID_LIT (lit); - transition_to_steady_state (); - external->assume (lit); - LOG_API_CALL_END ("assume", lit); -} - -int Solver::lookahead () { - TRACE ("lookahead"); - REQUIRE_VALID_OR_SOLVING_STATE (); - int lit = external->lookahead (); - TRACE ("lookahead"); - return lit; -} - -Solver::CubesWithStatus Solver::generate_cubes (int depth, int min_depth) { - TRACE ("lookahead_cubes"); - REQUIRE_VALID_OR_SOLVING_STATE (); - auto cubes = external->generate_cubes (depth, min_depth); - TRACE ("lookahead_cubes"); - - CubesWithStatus cubes2; - cubes2.status = cubes.status; - cubes2.cubes = cubes.cubes; - return cubes2; -} - -void Solver::reset_assumptions () { - TRACE ("reset_assumptions"); - REQUIRE_VALID_STATE (); - transition_to_steady_state (); - external->reset_assumptions (); - external->reset_concluded (); - LOG_API_CALL_END ("reset_assumptions"); -} - -void Solver::reset_constraint () { - TRACE ("reset_constraint"); - REQUIRE_VALID_STATE (); - transition_to_steady_state (); - external->reset_constraint (); - external->reset_concluded (); - LOG_API_CALL_END ("reset_constraint"); -} - -/*------------------------------------------------------------------------*/ - -int Solver::propagate () { - TRACE ("propagate_assumptions"); - REQUIRE_VALID_STATE (); - transition_to_steady_state (); - const int res = external->propagate_assumptions (); - if (tracing_nb_lidrup_env_var_method) - flush_proof_trace (true); - LOG_API_CALL_RETURNS ("propagate_assumptions", res); - if (res == 10) - STATE (SATISFIED); - else if (res == 20) - STATE (UNSATISFIED); - else - STATE (INCONCLUSIVE); - return res; -} - -void Solver::implied (std::vector &entrailed) { - TRACE ("implied"); - REQUIRE_VALID_STATE (); - REQUIRE (state () == INCONCLUSIVE, - "can only get implied literals only in unknown state"); - external->conclude_unknown (); - external->implied (entrailed); - if (tracing_nb_lidrup_env_var_method) - flush_proof_trace (true); - LOG_API_CALL_RETURNS ("implied", (int) entrailed.size ()); -} - -/*------------------------------------------------------------------------*/ - -int Solver::call_external_solve_and_check_results (bool preprocess_only) { - transition_to_steady_state (); - CADICAL_assert (state () & READY); - STATE (SOLVING); - const int res = external->solve (preprocess_only); - if (res == 10) - STATE (SATISFIED); - else if (res == 20) - STATE (UNSATISFIED); - else - STATE (INCONCLUSIVE); -#if 0 // EXPENSIVE ALTERNATIVE ASSUMPTION CHECKING - // This checks that the set of failed assumptions form a core using the - // external 'copy (...)' function to copy the solver, which can be trusted - // less, since it involves copying the extension stack too. The - // 'External::check_assumptions_failing' is a better alternative and can - // be enabled by options too. We keep this code though to have an - // alternative failed assumption checking available for debugging. - // - if (res == 20 && !external->assumptions.empty ()) { - Solver checker; - // checking restored clauses does not work (because the clauses are not added) - checker.set("checkproof", 1); - checker.set("lrat", 0); - checker.prefix ("checker "); - copy (checker); - checker.set("log", 1); - for (const auto & lit : external->assumptions) - if (failed (lit)) - checker.add (lit), checker.add (0); - if (checker.solve () != 20) - FATAL ("copying assumption checker failed"); - } -#endif - if (!res) { - external->reset_assumptions (); - external->reset_constraint (); - external->reset_concluded (); - } - return res; -} - -int Solver::solve () { - TRACE ("solve"); - REQUIRE_READY_STATE (); - const int res = call_external_solve_and_check_results (false); - LOG_API_CALL_RETURNS ("solve", res); - if (tracing_nb_lidrup_env_var_method) - flush_proof_trace (true); - return res; -} - -int Solver::simplify (int rounds) { - TRACE ("simplify", rounds); - REQUIRE_READY_STATE (); - REQUIRE (rounds >= 0, "negative number of simplification rounds '%d'", - rounds); - internal->limit ("preprocessing", rounds); - const int res = call_external_solve_and_check_results (true); - LOG_API_CALL_RETURNS ("simplify", rounds, res); - return res; -} - -/*------------------------------------------------------------------------*/ - -int Solver::val (int lit) { - TRACE ("val", lit); - REQUIRE_VALID_STATE (); - REQUIRE_VALID_LIT (lit); - REQUIRE (state () == SATISFIED, "can only get value in satisfied state"); - if (!external->extended) - external->extend (); - external->conclude_sat (); - int res = external->ival (lit); - LOG_API_CALL_RETURNS ("val", lit, res); - CADICAL_assert (state () == SATISFIED); - CADICAL_assert (res == lit || res == -lit); - return res; -} - -bool Solver::flip (int lit) { - TRACE ("flip", lit); - REQUIRE_VALID_STATE (); - REQUIRE_VALID_LIT (lit); - REQUIRE (state () == SATISFIED, "can only flip value in satisfied state"); - REQUIRE (!external->propagator, - "can only flip when no external propagator is present"); - bool res = external->flip (lit); - LOG_API_CALL_RETURNS ("flip", lit, res); - CADICAL_assert (state () == SATISFIED); - return res; -} - -bool Solver::flippable (int lit) { - TRACE ("flippable", lit); - REQUIRE_VALID_STATE (); - REQUIRE_VALID_LIT (lit); - REQUIRE (state () == SATISFIED, "can only flip value in satisfied state"); - REQUIRE (!external->propagator, - "can only flip when no external propagator is present"); - bool res = external->flippable (lit); - LOG_API_CALL_RETURNS ("flippable", lit, res); - CADICAL_assert (state () == SATISFIED); - return res; -} - -bool Solver::failed (int lit) { - TRACE ("failed", lit); - REQUIRE_VALID_STATE (); - REQUIRE_VALID_LIT (lit); - REQUIRE (state () == UNSATISFIED, - "can only get failed assumptions in unsatisfied state"); - bool res = external->failed (lit); - LOG_API_CALL_RETURNS ("failed", lit, res); - CADICAL_assert (state () == UNSATISFIED); - return res; -} - -bool Solver::constraint_failed () { - TRACE ("constraint_failed"); - REQUIRE_VALID_STATE (); - REQUIRE (state () == UNSATISFIED, - "can only determine if constraint failed in unsatisfied state"); - bool res = external->failed_constraint (); - LOG_API_CALL_RETURNS ("constraint_failed", res); - CADICAL_assert (state () == UNSATISFIED); - return res; -} - -int Solver::fixed (int lit) const { - TRACE ("fixed", lit); - REQUIRE_VALID_STATE (); - REQUIRE_VALID_LIT (lit); - int res = external->fixed (lit); - LOG_API_CALL_RETURNS ("fixed", lit, res); - return res; -} - -void Solver::phase (int lit) { - TRACE ("phase", lit); - REQUIRE_VALID_OR_SOLVING_STATE (); - REQUIRE_VALID_LIT (lit); - external->phase (lit); - LOG_API_CALL_END ("phase", lit); -} - -void Solver::unphase (int lit) { - TRACE ("unphase", lit); - REQUIRE_VALID_OR_SOLVING_STATE (); - REQUIRE_VALID_LIT (lit); - external->unphase (lit); - LOG_API_CALL_END ("unphase", lit); -} - -/*------------------------------------------------------------------------*/ - -void Solver::terminate () { - LOG_API_CALL_BEGIN ("terminate"); - REQUIRE_VALID_OR_SOLVING_STATE (); - external->terminate (); - LOG_API_CALL_END ("terminate"); -} - -void Solver::connect_terminator (Terminator *terminator) { - LOG_API_CALL_BEGIN ("connect_terminator"); - REQUIRE_VALID_STATE (); - REQUIRE (terminator, "can not connect zero terminator"); -#ifdef LOGGING - if (external->terminator) - LOG ("connecting new terminator (disconnecting previous one)"); - else - LOG ("connecting new terminator (no previous one)"); -#endif - external->terminator = terminator; - LOG_API_CALL_END ("connect_terminator"); -} - -void Solver::disconnect_terminator () { - LOG_API_CALL_BEGIN ("disconnect_terminator"); - REQUIRE_VALID_STATE (); -#ifdef LOGGING - if (external->terminator) - LOG ("disconnecting previous terminator"); - else - LOG ("ignoring to disconnect terminator (no previous one)"); -#endif - external->terminator = 0; - LOG_API_CALL_END ("disconnect_terminator"); -} - -/*------------------------------------------------------------------------*/ - -void Solver::connect_learner (Learner *learner) { - LOG_API_CALL_BEGIN ("connect_learner"); - REQUIRE_VALID_STATE (); - REQUIRE (learner, "can not connect zero learner"); -#ifdef LOGGING - if (external->learner) - LOG ("connecting new learner (disconnecting previous one)"); - else - LOG ("connecting new learner (no previous one)"); -#endif - external->learner = learner; - LOG_API_CALL_END ("connect_learner"); -} - -void Solver::disconnect_learner () { - LOG_API_CALL_BEGIN ("disconnect_learner"); - REQUIRE_VALID_STATE (); -#ifdef LOGGING - if (external->learner) - LOG ("disconnecting previous learner"); - else - LOG ("ignoring to disconnect learner (no previous one)"); -#endif - external->learner = 0; - LOG_API_CALL_END ("disconnect_learner"); -} - -/*===== IPASIR END =======================================================*/ - -void Solver::connect_fixed_listener ( - FixedAssignmentListener *fixed_listener) { - LOG_API_CALL_BEGIN ("connect_fixed_listener"); - REQUIRE_VALID_STATE (); - REQUIRE (fixed_listener, "can not connect zero fixed listener"); - -#ifdef LOGGING - if (external->fixed_listener) - LOG ("connecting new listener of fixed assignments (disconnecting " - "previous one)"); - else - LOG ("connecting new listener of fixed assigments (no previous one)"); -#endif - if (external->fixed_listener) - disconnect_fixed_listener (); - external->fixed_listener = fixed_listener; - // Listeners are treated as real-time listeners, thus previously found - // fixed assignments are not sent out (would be rather expensive to - // recover it retrospect, see external_propagate.cpp/get_fixed_literals () - // function). - LOG_API_CALL_END ("connect_fixed_listener"); -} - -void Solver::disconnect_fixed_listener () { - LOG_API_CALL_BEGIN ("disconnect_fixed_listener"); - REQUIRE_VALID_STATE (); -#ifdef LOGGING - if (external->fixed_listener) - LOG ("disconnecting previous listener of fixed assignments"); - else - LOG ("ignoring to disconnect listener of fixed assignments (no " - "previous one)"); -#endif - external->fixed_listener = 0; - LOG_API_CALL_END ("disconnect_fixed_listener"); -} - -/*===== IPASIR-UP BEGIN ==================================================*/ - -void Solver::connect_external_propagator (ExternalPropagator *propagator) { - LOG_API_CALL_BEGIN ("connect_external_propagator"); - REQUIRE_VALID_STATE (); - REQUIRE (propagator, "can not connect zero propagator"); -#ifdef LOGGING - if (external->propagator) - LOG ("connecting new external propagator (disconnecting previous one)"); - else - LOG ("connecting new external propagator (no previous one)"); -#endif - if (external->propagator) - disconnect_external_propagator (); - - external->propagator = propagator; - internal->connect_propagator (); - internal->external_prop = true; - internal->external_prop_is_lazy = propagator->is_lazy; - LOG_API_CALL_END ("connect_external_propagator"); -} - -void Solver::disconnect_external_propagator () { - LOG_API_CALL_BEGIN ("disconnect_external_propagator"); - REQUIRE_VALID_STATE (); - -#ifdef LOGGING - if (external->propagator) - LOG ("disconnecting previous external propagator"); - else - LOG ("ignoring to disconnect external propagator (no previous one)"); -#endif - if (external->propagator) - external->reset_observed_vars (); - - external->propagator = 0; - internal->set_tainted_literal (); - internal->external_prop = false; - internal->external_prop_is_lazy = true; - LOG_API_CALL_END ("disconnect_external_propagator"); -} - -void Solver::add_observed_var (int idx) { - TRACE ("observe", idx); - REQUIRE_VALID_OR_SOLVING_STATE (); - REQUIRE_VALID_LIT (idx); - external->add_observed_var (idx); - LOG_API_CALL_END ("observe", idx); -} - -void Solver::remove_observed_var (int idx) { - TRACE ("unobserve", idx); - REQUIRE_VALID_STATE (); - REQUIRE_VALID_LIT (idx); - external->remove_observed_var (idx); - LOG_API_CALL_END ("unobserve", idx); -} - -void Solver::reset_observed_vars () { - TRACE ("reset_observed_vars"); - REQUIRE_VALID_OR_SOLVING_STATE (); - external->reset_observed_vars (); - LOG_API_CALL_END ("reset_observed_vars"); -} - -/*===== IPASIR-UP END ====================================================*/ - -int Solver::active () const { - TRACE ("active"); - REQUIRE_VALID_STATE (); - int res = internal->active (); - LOG_API_CALL_RETURNS ("active", res); - return res; -} - -int64_t Solver::redundant () const { - TRACE ("redundant"); - REQUIRE_VALID_STATE (); - int64_t res = internal->redundant (); - LOG_API_CALL_RETURNS ("redundant", res); - return res; -} - -int64_t Solver::irredundant () const { - TRACE ("irredundant"); - REQUIRE_VALID_STATE (); - int64_t res = internal->irredundant (); - LOG_API_CALL_RETURNS ("irredundant", res); - return res; -} - -/*------------------------------------------------------------------------*/ - -void Solver::freeze (int lit) { - TRACE ("freeze", lit); - REQUIRE_VALID_STATE (); - REQUIRE_VALID_LIT (lit); - external->freeze (lit); - LOG_API_CALL_END ("freeze", lit); -} - -void Solver::melt (int lit) { - TRACE ("melt", lit); - REQUIRE_VALID_STATE (); - REQUIRE_VALID_LIT (lit); - REQUIRE (external->frozen (lit), - "can not melt completely melted literal '%d'", lit); - external->melt (lit); - LOG_API_CALL_END ("melt", lit); -} - -bool Solver::frozen (int lit) const { - TRACE ("frozen", lit); - REQUIRE_VALID_STATE (); - REQUIRE_VALID_LIT (lit); - bool res = external->frozen (lit); - LOG_API_CALL_RETURNS ("frozen", lit, res); - return res; -} - -/*------------------------------------------------------------------------*/ - -bool Solver::trace_proof (FILE *external_file, const char *name) { - TRACE ("trace_proof", name); - REQUIRE_VALID_STATE (); - REQUIRE ( - state () == CONFIGURING, - "can only start proof tracing to '%s' right after initialization", - name); - File *internal_file = File::write (internal, external_file, name); - CADICAL_assert (internal_file); - internal->trace (internal_file); - LOG_API_CALL_RETURNS ("trace_proof", name, true); - return true; -} - -bool Solver::trace_proof (const char *path) { - TRACE ("trace_proof", path); - REQUIRE_VALID_STATE (); - REQUIRE ( - state () == CONFIGURING, - "can only start proof tracing to '%s' right after initialization", - path); - File *internal_file = File::write (internal, path); - bool res = (internal_file != 0); - internal->trace (internal_file); - LOG_API_CALL_RETURNS ("trace_proof", path, res); - return res; -} - -void Solver::flush_proof_trace (bool print_statistics_unless_quiet) { - TRACE ("flush_proof_trace"); - REQUIRE_VALID_STATE (); - REQUIRE (!internal->file_tracers.empty (), "proof is not traced"); - REQUIRE (!internal->file_tracers.back ()->closed (), - "proof trace already closed"); - internal->flush_trace (print_statistics_unless_quiet); - LOG_API_CALL_END ("flush_proof_trace"); -} - -void Solver::close_proof_trace (bool print_statistics_unless_quiet) { - TRACE ("close_proof_trace"); - REQUIRE_VALID_STATE (); - REQUIRE (!internal->file_tracers.empty (), "proof is not traced"); - REQUIRE (!internal->file_tracers.back ()->closed (), - "proof trace already closed"); - internal->close_trace (print_statistics_unless_quiet); - LOG_API_CALL_END ("close_proof_trace"); -} - -/*------------------------------------------------------------------------*/ - -void Solver::connect_proof_tracer (Tracer *tracer, bool antecedents, - bool finalize_clauses) { - LOG_API_CALL_BEGIN ("connect proof tracer"); - REQUIRE_VALID_STATE (); - REQUIRE (state () == CONFIGURING, - "can only start proof tracing to right after initialization"); - REQUIRE (tracer, "can not connect zero tracer"); - internal->connect_proof_tracer (tracer, antecedents, finalize_clauses); - LOG_API_CALL_END ("connect proof tracer"); -} - -void Solver::connect_proof_tracer (InternalTracer *tracer, bool antecedents, - bool finalize_clauses) { - LOG_API_CALL_BEGIN ("connect proof tracer"); - REQUIRE_VALID_STATE (); - REQUIRE (state () == CONFIGURING, - "can only start proof tracing to right after initialization"); - REQUIRE (tracer, "can not connect zero tracer"); - internal->connect_proof_tracer (tracer, antecedents, finalize_clauses); - LOG_API_CALL_END ("connect proof tracer"); -} - -void Solver::connect_proof_tracer (StatTracer *tracer, bool antecedents, - bool finalize_clauses) { - LOG_API_CALL_BEGIN ("connect proof tracer with stats"); - REQUIRE_VALID_STATE (); - REQUIRE (state () == CONFIGURING, - "can only start proof tracing to right after initialization"); - REQUIRE (tracer, "can not connect zero tracer"); - internal->connect_proof_tracer (tracer, antecedents, finalize_clauses); - LOG_API_CALL_END ("connect proof tracer with stats"); -} - -void Solver::connect_proof_tracer (FileTracer *tracer, bool antecedents, - bool finalize_clauses) { - LOG_API_CALL_BEGIN ("connect proof tracer with file"); - REQUIRE_VALID_STATE (); - REQUIRE (state () == CONFIGURING, - "can only start proof tracing right after initialization"); - REQUIRE (tracer, "can not connect zero tracer"); - internal->connect_proof_tracer (tracer, antecedents, finalize_clauses); - LOG_API_CALL_END ("connect proof tracer with file"); -} - -bool Solver::disconnect_proof_tracer (Tracer *tracer) { - LOG_API_CALL_BEGIN ("disconnect proof tracer"); - REQUIRE_VALID_STATE (); - REQUIRE (tracer, "can not disconnect zero tracer"); - bool res = internal->disconnect_proof_tracer (tracer); - LOG_API_CALL_RETURNS ("connect proof tracer", res); - return res; -} - -bool Solver::disconnect_proof_tracer (StatTracer *tracer) { - LOG_API_CALL_BEGIN ("disconnect proof tracer"); - REQUIRE_VALID_STATE (); - REQUIRE (tracer, "can not disconnect zero tracer"); - bool res = internal->disconnect_proof_tracer (tracer); - LOG_API_CALL_RETURNS ("disconnect proof tracer", res); - return res; -} - -bool Solver::disconnect_proof_tracer (FileTracer *tracer) { - LOG_API_CALL_BEGIN ("disconnect proof tracer"); - REQUIRE_VALID_STATE (); - REQUIRE (tracer, "can not disconnect zero tracer"); - bool res = internal->disconnect_proof_tracer (tracer); - LOG_API_CALL_RETURNS ("disconnect proof tracer", res); - return res; -} - -/*------------------------------------------------------------------------*/ - -void Solver::conclude () { - TRACE ("conclude"); - REQUIRE_VALID_STATE (); - REQUIRE (state () == UNSATISFIED || state () == SATISFIED || - state () == INCONCLUSIVE, - "can only conclude in satisfied, unsatisfied or inconclusive state"); - if (state () == UNSATISFIED) - internal->conclude_unsat (); - else if (state () == SATISFIED) - external->conclude_sat (); - else if (state () == INCONCLUSIVE) - external->conclude_unknown (); - CADICAL_assert (state () == UNSATISFIED || state () == SATISFIED || - state () == INCONCLUSIVE); - LOG_API_CALL_END ("conclude"); -} - -/*------------------------------------------------------------------------*/ - -void Solver::build (FILE *file, const char *prefix) { - - CADICAL_assert (file == stdout || file == stderr); - - Terminal *terminal; - - if (file == stdout) - terminal = &tout; - else if (file == stderr) - terminal = &terr; - else - terminal = 0; - - const char *v = CaDiCaL::version (); - const char *i = identifier (); - const char *c = compiler (); - const char *b = date (); - const char *f = flags (); - - CADICAL_assert (v); - - fputs (prefix, file); - if (terminal) - terminal->magenta (); - fputs ("Version ", file); - if (terminal) - terminal->normal (); - fputs (v, file); - if (i) { - if (terminal) - terminal->magenta (); - fputc (' ', file); - fputs (i, file); - if (terminal) - terminal->normal (); - } - fputc ('\n', file); - - if (c) { - fputs (prefix, file); - if (terminal) - terminal->magenta (); - fputs (c, file); - if (f) { - fputc (' ', file); - fputs (f, file); - } - if (terminal) - terminal->normal (); - fputc ('\n', file); - } - - if (b) { - fputs (prefix, file); - if (terminal) - terminal->magenta (); - fputs (b, file); - if (terminal) - terminal->normal (); - fputc ('\n', file); - } - - fflush (file); -} - -const char *Solver::version () { return CaDiCaL::version (); } - -const char *Solver::signature () { return CaDiCaL::signature (); } - -void Solver::options () { - REQUIRE_VALID_STATE (); - internal->opts.print (); -} - -void Solver::usage () { Options::usage (); } - -void Solver::configurations () { Config::usage (); } - -void Solver::statistics () { - if (state () == DELETING) - return; - TRACE ("stats"); - REQUIRE_VALID_OR_SOLVING_STATE (); - internal->print_statistics (); - LOG_API_CALL_END ("stats"); -} - -void Solver::resources () { - if (state () == DELETING) - return; - TRACE ("resources"); - REQUIRE_VALID_OR_SOLVING_STATE (); - internal->print_resource_usage (); - LOG_API_CALL_END ("resources"); -} - -/*------------------------------------------------------------------------*/ - -const char *Solver::read_dimacs (File *file, int &vars, int strict, - bool *incremental, vector *cubes) { - REQUIRE_VALID_STATE (); - REQUIRE (state () == CONFIGURING, - "can only read DIMACS file right after initialization"); - Parser *parser = new Parser (this, file, incremental, cubes); - const char *err = parser->parse_dimacs (vars, strict); - delete parser; - return err; -} - -const char *Solver::read_dimacs (FILE *external_file, const char *name, - int &vars, int strict) { - LOG_API_CALL_BEGIN ("read_dimacs", name); - REQUIRE_VALID_STATE (); - REQUIRE (state () == CONFIGURING, - "can only read DIMACS file right after initialization"); - File *file = File::read (internal, external_file, name); - CADICAL_assert (file); - const char *err = read_dimacs (file, vars, strict); - delete file; - LOG_API_CALL_RETURNS ("read_dimacs", name, err); - return err; -} - -const char *Solver::read_dimacs (const char *path, int &vars, int strict) { - LOG_API_CALL_BEGIN ("read_dimacs", path); - REQUIRE_VALID_STATE (); - REQUIRE (state () == CONFIGURING, - "can only read DIMACS file right after initialization"); - File *file = File::read (internal, path); - if (!file) - return internal->error_message.init ("failed to read DIMACS file '%s'", - path); - const char *err = read_dimacs (file, vars, strict); - delete file; - LOG_API_CALL_RETURNS ("read_dimacs", path, err); - return err; -} - -const char *Solver::read_dimacs (FILE *external_file, const char *name, - int &vars, int strict, bool &incremental, - vector &cubes) { - LOG_API_CALL_BEGIN ("read_dimacs", name); - REQUIRE_VALID_STATE (); - REQUIRE (state () == CONFIGURING, - "can only read DIMACS file right after initialization"); - File *file = File::read (internal, external_file, name); - CADICAL_assert (file); - const char *err = read_dimacs (file, vars, strict, &incremental, &cubes); - delete file; - LOG_API_CALL_RETURNS ("read_dimacs", name, err); - return err; -} - -const char *Solver::read_dimacs (const char *path, int &vars, int strict, - bool &incremental, vector &cubes) { - LOG_API_CALL_BEGIN ("read_dimacs", path); - REQUIRE_VALID_STATE (); - REQUIRE (state () == CONFIGURING, - "can only read DIMACS file right after initialization"); - File *file = File::read (internal, path); - if (!file) - return internal->error_message.init ("failed to read DIMACS file '%s'", - path); - const char *err = read_dimacs (file, vars, strict, &incremental, &cubes); - delete file; - LOG_API_CALL_RETURNS ("read_dimacs", path, err); - return err; -} - -const char *Solver::read_solution (const char *path) { - LOG_API_CALL_BEGIN ("solution", path); - REQUIRE_VALID_STATE (); - File *file = File::read (internal, path); - if (!file) - return internal->error_message.init ( - "failed to read solution file '%s'", path); - Parser *parser = new Parser (this, file, 0, 0); - const char *err = parser->parse_solution (); - delete parser; - delete file; - if (!err) - external->check_assignment (&External::sol); - LOG_API_CALL_RETURNS ("read_solution", path, err); - return err; -} - -/*------------------------------------------------------------------------*/ - -void Solver::dump_cnf () { - TRACE ("dump"); - REQUIRE_INITIALIZED (); - internal->dump (); - LOG_API_CALL_END ("dump"); -} - -/*------------------------------------------------------------------------*/ - -ExternalPropagator *Solver::get_propagator () { - return external->propagator; -} - -bool Solver::observed (int lit) { - TRACE ("observed", lit); - REQUIRE_VALID_OR_SOLVING_STATE (); - REQUIRE_VALID_LIT (lit); - bool res = external->observed (lit); - LOG_API_CALL_RETURNS ("observed", lit, res); - return res; -} - -bool Solver::is_witness (int lit) { - TRACE ("is_witness", lit); - REQUIRE_VALID_OR_SOLVING_STATE (); - REQUIRE_VALID_LIT (lit); - bool res = external->is_witness (lit); - LOG_API_CALL_RETURNS ("is_witness", lit, res); - return res; -} - -bool Solver::is_decision (int lit) { - TRACE ("is_decision", lit); - REQUIRE_VALID_OR_SOLVING_STATE (); - REQUIRE_VALID_LIT (lit); - bool res = external->is_decision (lit); - LOG_API_CALL_RETURNS ("is_decision", lit, res); - return res; -} - -void Solver::force_backtrack (size_t new_level) { - TRACE ("force_backtrack", new_level); - REQUIRE_VALID_OR_SOLVING_STATE (); - external->force_backtrack (new_level); -} - -/*------------------------------------------------------------------------*/ - -bool Solver::traverse_clauses (ClauseIterator &it) const { - LOG_API_CALL_BEGIN ("traverse_clauses"); - REQUIRE_VALID_STATE (); - bool res = external->traverse_all_frozen_units_as_clauses (it) && - internal->traverse_clauses (it) && - internal->traverse_constraint (it); - LOG_API_CALL_RETURNS ("traverse_clauses", res); - return res; -} - -bool Solver::traverse_witnesses_backward (WitnessIterator &it) const { - LOG_API_CALL_BEGIN ("traverse_witnesses_backward"); - REQUIRE_VALID_STATE (); - bool res = external->traverse_all_non_frozen_units_as_witnesses (it) && - external->traverse_witnesses_backward (it); - LOG_API_CALL_RETURNS ("traverse_witnesses_backward", res); - return res; -} - -bool Solver::traverse_witnesses_forward (WitnessIterator &it) const { - LOG_API_CALL_BEGIN ("traverse_witnesses_forward"); - REQUIRE_VALID_STATE (); - bool res = external->traverse_witnesses_forward (it) && - external->traverse_all_non_frozen_units_as_witnesses (it); - LOG_API_CALL_RETURNS ("traverse_witnesses_forward", res); - return res; -} - -/*------------------------------------------------------------------------*/ - -class ClauseCounter : public ClauseIterator { -public: - int vars; - int64_t clauses; - ClauseCounter () : vars (0), clauses (0) {} - bool clause (const vector &c) { - for (const auto &lit : c) { - CADICAL_assert (lit != INT_MIN); - int idx = abs (lit); - if (idx > vars) - vars = idx; - } - clauses++; - return true; - } -}; - -class ClauseWriter : public ClauseIterator { - File *file; - -public: - ClauseWriter (File *f) : file (f) {} - bool clause (const vector &c) { - for (const auto &lit : c) { - if (!file->put (lit)) - return false; - if (!file->put (' ')) - return false; - } - return file->put ("0\n"); - } -}; - -const char *Solver::write_dimacs (const char *path, int min_max_var) { - LOG_API_CALL_BEGIN ("write_dimacs", path, min_max_var); - REQUIRE_VALID_STATE (); -#ifndef CADICAL_QUIET - const double start = internal->time (); -#endif - internal->restore_clauses (); - ClauseCounter counter; - (void) traverse_clauses (counter); - LOG ("found maximal variable %d and %" PRId64 " clauses", counter.vars, - counter.clauses); - File *file = File::write (internal, path); - const char *res = 0; - if (file) { - int actual_max_vars = max (min_max_var, counter.vars); - MSG ("writing %s'p cnf %d %" PRId64 "'%s header", tout.green_code (), - actual_max_vars, counter.clauses, tout.normal_code ()); - file->put ("p cnf "); - file->put (actual_max_vars); - file->put (' '); - file->put (counter.clauses); - file->put ('\n'); - ClauseWriter writer (file); - if (!traverse_clauses (writer)) - res = internal->error_message.init ( - "writing to DIMACS file '%s' failed", path); - delete file; - } else - res = internal->error_message.init ( - "failed to open DIMACS file '%s' for writing", path); -#ifndef CADICAL_QUIET - if (!res) { - const double end = internal->time (); - MSG ("wrote %" PRId64 " clauses in %.2f seconds %s time", - counter.clauses, end - start, - internal->opts.realtime ? "real" : "process"); - } -#endif - LOG_API_CALL_RETURNS ("write_dimacs", path, min_max_var, res); - return res; -} - -/*------------------------------------------------------------------------*/ - -struct WitnessWriter : public WitnessIterator { - File *file; - int64_t witnesses; - WitnessWriter (File *f) : file (f), witnesses (0) {} - bool write (const vector &a) { - for (const auto &lit : a) { - if (!file->put (lit)) - return false; - if (!file->put (' ')) - return false; - } - return file->put ('0'); - } - bool witness (const vector &c, const vector &w, int64_t) { - if (!write (c)) - return false; - if (!file->put (' ')) - return false; - if (!write (w)) - return false; - if (!file->put ('\n')) - return false; - witnesses++; - return true; - } -}; - -const char *Solver::write_extension (const char *path) { - LOG_API_CALL_BEGIN ("write_extension", path); - REQUIRE_VALID_STATE (); - const char *res = 0; -#ifndef CADICAL_QUIET - const double start = internal->time (); -#endif - File *file = File::write (internal, path); - WitnessWriter writer (file); - if (file) { - if (!traverse_witnesses_backward (writer)) - res = internal->error_message.init ( - "writing to DIMACS file '%s' failed", path); - delete file; - } else - res = internal->error_message.init ( - "failed to open extension file '%s' for writing", path); -#ifndef CADICAL_QUIET - if (!res) { - const double end = internal->time (); - MSG ("wrote %" PRId64 " witnesses in %.2f seconds %s time", - writer.witnesses, end - start, - internal->opts.realtime ? "real" : "process"); - } -#endif - LOG_API_CALL_RETURNS ("write_extension", path, res); - return res; -} - -/*------------------------------------------------------------------------*/ - -struct ClauseCopier : public ClauseIterator { - Solver &dst; - -public: - ClauseCopier (Solver &d) : dst (d) {} - bool clause (const vector &c) { - for (const auto &lit : c) - dst.add (lit); - dst.add (0); - return true; - } -}; - -struct WitnessCopier : public WitnessIterator { - External *dst; - -public: - WitnessCopier (External *d) : dst (d) {} - bool witness (const vector &c, const vector &w, int64_t id) { - dst->push_external_clause_and_witness_on_extension_stack (c, w, id); - return true; - } -}; - -void Solver::copy (Solver &other) const { - REQUIRE_READY_STATE (); - REQUIRE (other.state () & CONFIGURING, "target solver already modified"); - internal->opts.copy (other.internal->opts); - ClauseCopier clause_copier (other); - traverse_clauses (clause_copier); - WitnessCopier witness_copier (other.external); - traverse_witnesses_forward (witness_copier); - external->copy_flags (*other.external); -} - -/*------------------------------------------------------------------------*/ - -void Solver::section (const char *title) { - if (state () == DELETING) - return; -#ifdef CADICAL_QUIET - (void) title; -#endif - REQUIRE_INITIALIZED (); - SECTION (title); -} - -void Solver::message (const char *fmt, ...) { - if (state () == DELETING) - return; -#ifdef CADICAL_QUIET - (void) fmt; -#else - REQUIRE_INITIALIZED (); - va_list ap; - va_start (ap, fmt); - internal->vmessage (fmt, ap); - va_end (ap); -#endif -} - -void Solver::message () { - if (state () == DELETING) - return; - REQUIRE_INITIALIZED (); -#ifndef CADICAL_QUIET - internal->message (); -#endif -} - -void Solver::verbose (int level, const char *fmt, ...) { - if (state () == DELETING) - return; - REQUIRE_VALID_OR_SOLVING_STATE (); -#ifdef CADICAL_QUIET - (void) level; - (void) fmt; -#else - va_list ap; - va_start (ap, fmt); - internal->vverbose (level, fmt, ap); - va_end (ap); -#endif -} - -void Solver::error (const char *fmt, ...) { - if (state () == DELETING) - return; - REQUIRE_INITIALIZED (); - va_list ap; - va_start (ap, fmt); - internal->verror (fmt, ap); - va_end (ap); -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_stable.cpp b/src/sat/cadical/cadical_stable.cpp deleted file mode 100644 index f177139ac..000000000 --- a/src/sat/cadical/cadical_stable.cpp +++ /dev/null @@ -1,39 +0,0 @@ -#include "global.h" - -#ifdef PROFILE_MODE - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -bool Internal::propagate_stable () { - CADICAL_assert (stable); - START (propstable); - bool res = propagate (); - STOP (propstable); - return res; -} - -void Internal::analyze_stable () { - CADICAL_assert (stable); - START (analyzestable); - analyze (); - STOP (analyzestable); -} - -int Internal::decide_stable () { - CADICAL_assert (stable); - return decide (); -} - -}; // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END - -#else -ABC_NAMESPACE_IMPL_START -int stable_if_not_profile_mode_dummy; -ABC_NAMESPACE_IMPL_END -#endif diff --git a/src/sat/cadical/cadical_stats.cpp b/src/sat/cadical/cadical_stats.cpp deleted file mode 100644 index 8b07745d6..000000000 --- a/src/sat/cadical/cadical_stats.cpp +++ /dev/null @@ -1,826 +0,0 @@ -// vim: set tw=300: set VIM text width to 300 characters for this file. -#include "global.h" - - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -/*------------------------------------------------------------------------*/ - -Stats::Stats () { - time.real = absolute_real_time (); - time.process = absolute_process_time (); - walk.minimum = LONG_MAX; - used.resize (2); - used[0].resize (127); - used[1].resize (127); -} - -/*------------------------------------------------------------------------*/ - -#define PRT(FMT, ...) \ - do { \ - if (FMT[0] == ' ' && !all) \ - break; \ - MSG (FMT, __VA_ARGS__); \ - } while (0) - -/*------------------------------------------------------------------------*/ - -void Stats::print (Internal *internal) { - -#ifdef CADICAL_QUIET - (void) internal; -#else - - Stats &stats = internal->stats; - - int all = internal->opts.verbose > 0 || internal->opts.stats; -#ifdef LOGGING - if (internal->opts.log) - all = true; -#endif // ifdef LOGGING - - if (internal->opts.profile) - internal->print_profile (); - - double t = internal->solve_time (); - - int64_t propagations = 0; - propagations += stats.propagations.cover; - propagations += stats.propagations.probe; - propagations += stats.propagations.search; - propagations += stats.propagations.transred; - propagations += stats.propagations.vivify; - propagations += stats.propagations.walk; - - int64_t vivified = stats.vivifysubs + stats.vivifystrs; - int64_t searchticks = stats.ticks.search[0] + stats.ticks.search[1]; - int64_t inprobeticks = stats.ticks.vivify + stats.ticks.probe + - stats.ticks.factor + stats.ticks.ternary + - stats.ticks.sweep; - int64_t totalticks = searchticks + inprobeticks; - - size_t extendbytes = internal->external->extension.size (); - extendbytes *= sizeof (int); - - SECTION ("statistics"); - - if (all || stats.blocked) { - PRT ("blocked: %15" PRId64 - " %10.2f %% of irredundant clauses", - stats.blocked, percent (stats.blocked, stats.added.irredundant)); - PRT (" blockings: %15" PRId64 " %10.2f internal", - stats.blockings, relative (stats.conflicts, stats.blockings)); - PRT (" candidates: %15" PRId64 " %10.2f per blocking ", - stats.blockcands, relative (stats.blockcands, stats.blockings)); - PRT (" blockres: %15" PRId64 " %10.2f per candidate", - stats.blockres, relative (stats.blockres, stats.blockcands)); - PRT (" pure: %15" PRId64 " %10.2f %% of all variables", - stats.all.pure, percent (stats.all.pure, stats.vars)); - PRT (" pureclauses: %15" PRId64 " %10.2f per pure literal", - stats.blockpured, relative (stats.blockpured, stats.all.pure)); - } - if (all || stats.chrono) - PRT ("chronological: %15" PRId64 " %10.2f %% of conflicts", - stats.chrono, percent (stats.chrono, stats.conflicts)); - if (all) - PRT ("compacts: %15" PRId64 " %10.2f interval", - stats.compacts, relative (stats.conflicts, stats.compacts)); - if (all || stats.conflicts) { - PRT ("conflicts: %15" PRId64 " %10.2f per second", - stats.conflicts, relative (stats.conflicts, t)); - PRT (" backtracked: %15" PRId64 " %10.2f %% of conflicts", - stats.backtracks, percent (stats.backtracks, stats.conflicts)); - } - if (all || stats.conditioned) { - PRT ("conditioned: %15" PRId64 - " %10.2f %% of irredundant clauses", - stats.conditioned, - percent (stats.conditioned, stats.added.irredundant)); - PRT (" conditionings: %15" PRId64 " %10.2f interval", - stats.conditionings, - relative (stats.conflicts, stats.conditionings)); - PRT (" condcands: %15" PRId64 " %10.2f candidate clauses", - stats.condcands, relative (stats.condcands, stats.conditionings)); - PRT (" condassinit: %17.1f %9.2f %% initial assigned", - relative (stats.condassinit, stats.conditionings), - percent (stats.condassinit, stats.condassvars)); - PRT (" condcondinit: %17.1f %9.2f %% initial condition", - relative (stats.condcondinit, stats.conditionings), - percent (stats.condcondinit, stats.condassinit)); - PRT (" condautinit: %17.1f %9.2f %% initial autarky", - relative (stats.condautinit, stats.conditionings), - percent (stats.condautinit, stats.condassinit)); - PRT (" condassrem: %17.1f %9.2f %% final assigned", - relative (stats.condassrem, stats.conditioned), - percent (stats.condassrem, stats.condassirem)); - PRT (" condcondrem: %19.3f %7.2f %% final conditional", - relative (stats.condcondrem, stats.conditioned), - percent (stats.condcondrem, stats.condassrem)); - PRT (" condautrem: %19.3f %7.2f %% final autarky", - relative (stats.condautrem, stats.conditioned), - percent (stats.condautrem, stats.condassrem)); - PRT (" condprops: %15" PRId64 " %10.2f per candidate", - stats.condprops, relative (stats.condprops, stats.condcands)); - } - if (all || stats.cover.total) { - PRT ("covered: %15" PRId64 - " %10.2f %% of irredundant clauses", - stats.cover.total, - percent (stats.cover.total, stats.added.irredundant)); - PRT (" coverings: %15" PRId64 " %10.2f interval", - stats.cover.count, relative (stats.conflicts, stats.cover.count)); - PRT (" asymmetric: %15" PRId64 " %10.2f %% of covered clauses", - stats.cover.asymmetric, - percent (stats.cover.asymmetric, stats.cover.total)); - PRT (" blocked: %15" PRId64 " %10.2f %% of covered clauses", - stats.cover.blocked, - percent (stats.cover.blocked, stats.cover.total)); - } - if (all || stats.decisions) { - PRT ("decisions: %15" PRId64 " %10.2f per second", - stats.decisions, relative (stats.decisions, t)); - PRT (" searched: %15" PRId64 " %10.2f per decision", - stats.searched, relative (stats.searched, stats.decisions)); - } - if (all || stats.all.eliminated) { - PRT ("eliminated: %15" PRId64 " %10.2f %% of all variables", - stats.all.eliminated, percent (stats.all.eliminated, stats.vars)); - PRT (" fastelim: %15" PRId64 " %10.2f %% of eliminated", - stats.all.fasteliminated, - percent (stats.all.fasteliminated, stats.all.eliminated)); - PRT (" elimphases: %15" PRId64 " %10.2f interval", - stats.elimphases, relative (stats.conflicts, stats.elimphases)); - PRT (" elimrounds: %15" PRId64 " %10.2f per phase", - stats.elimrounds, relative (stats.elimrounds, stats.elimphases)); - PRT (" elimtried: %15" PRId64 " %10.2f %% eliminated", - stats.elimtried, percent (stats.all.eliminated, stats.elimtried)); - PRT (" elimgates: %15" PRId64 " %10.2f %% gates per tried", - stats.elimgates, percent (stats.elimgates, stats.elimtried)); - PRT (" elimequivs: %15" PRId64 " %10.2f %% equivalence gates", - stats.elimequivs, percent (stats.elimequivs, stats.elimgates)); - PRT (" elimands: %15" PRId64 " %10.2f %% and gates", - stats.elimands, percent (stats.elimands, stats.elimgates)); - PRT (" elimites: %15" PRId64 " %10.2f %% if-then-else gates", - stats.elimites, percent (stats.elimites, stats.elimgates)); - PRT (" elimxors: %15" PRId64 " %10.2f %% xor gates", - stats.elimxors, percent (stats.elimxors, stats.elimgates)); - PRT (" elimdefs: %15" PRId64 " %10.2f %% definitions", - stats.definitions_extracted, - percent (stats.definitions_extracted, stats.elimgates)); - PRT (" elimsubst: %15" PRId64 " %10.2f %% substituted", - stats.elimsubst, percent (stats.elimsubst, stats.all.eliminated)); - PRT (" elimsubstequi: %15" PRId64 " %10.2f %% equivalence gates", - stats.eliminated_equi, - percent (stats.eliminated_equi, stats.elimsubst)); - PRT (" elimsubstands: %15" PRId64 " %10.2f %% and gates", - stats.eliminated_and, - percent (stats.eliminated_and, stats.elimsubst)); - PRT (" elimsubstites: %15" PRId64 " %10.2f %% if-then-else gates", - stats.eliminated_ite, - percent (stats.eliminated_ite, stats.elimsubst)); - PRT (" elimsubstxors: %15" PRId64 " %10.2f %% xor gates", - stats.eliminated_xor, - percent (stats.eliminated_xor, stats.elimsubst)); - PRT (" elimsubstdefs: %15" PRId64 " %10.2f %% definitions", - stats.eliminated_def, - percent (stats.eliminated_def, stats.elimsubst)); - PRT (" elimres: %15" PRId64 " %10.2f per eliminated", - stats.elimres, relative (stats.elimres, stats.all.eliminated)); - PRT (" elimrestried: %15" PRId64 " %10.2f %% per resolution", - stats.elimrestried, percent (stats.elimrestried, stats.elimres)); - PRT (" def checked: %15" PRId64 " %10.2f per phase", - stats.definitions_checked, - relative (stats.definitions_checked, stats.elimphases)); - PRT (" def extracted: %15" PRId64 " %10.2f %% per checked", - stats.definitions_extracted, - percent (stats.definitions_extracted, stats.definitions_checked)); - PRT (" def units: %15" PRId64 " %10.2f %% per checked", - stats.definition_units, - percent (stats.definition_units, stats.definitions_checked)); - } - if (all || stats.ext_prop.ext_cb) { - PRT ("ext.prop. calls: %15" PRId64 " %10.2f %% of queries", - stats.ext_prop.eprop_call, - percent (stats.ext_prop.eprop_call, stats.ext_prop.ext_cb)); - PRT (" propagating: %15" PRId64 " %10.2f %% per eprop-call", - stats.ext_prop.eprop_prop, - percent (stats.ext_prop.eprop_prop, stats.ext_prop.eprop_call)); - PRT (" explained: %15" PRId64 " %10.2f %% per eprop-call", - stats.ext_prop.eprop_expl, - percent (stats.ext_prop.eprop_expl, stats.ext_prop.eprop_call)); - PRT (" falsified: %15" PRId64 " %10.2f %% per eprop-call", - stats.ext_prop.eprop_conf, - percent (stats.ext_prop.eprop_conf, stats.ext_prop.eprop_call)); - PRT ("ext.clause calls:%15" PRId64 " %10.2f %% of queries", - stats.ext_prop.elearn_call, - percent (stats.ext_prop.elearn_call, stats.ext_prop.ext_cb)); - PRT (" learned: %15" PRId64 " %10.2f %% per called", - stats.ext_prop.elearned, - percent (stats.ext_prop.elearned, stats.ext_prop.elearn_call)); - PRT (" conflicting: %15" PRId64 " %10.2f %% per learned", - stats.ext_prop.elearn_conf, - percent (stats.ext_prop.elearn_conf, stats.ext_prop.elearned)); - PRT (" propagating: %15" PRId64 " %10.2f %% per learned", - stats.ext_prop.elearn_prop, - percent (stats.ext_prop.elearn_prop, stats.ext_prop.elearned)); - PRT ("ext.final check: %15" PRId64 " %10.2f %% of queries", - stats.ext_prop.echeck_call, - percent (stats.ext_prop.echeck_call, stats.ext_prop.ext_cb)); - } - if (all || stats.factored) { - PRT ("factored: %15" PRId64 " %10.2f %% of variables", - stats.factored, percent (stats.factored, internal->max_var)); - PRT (" factor: %15" PRId64 " %10.2f conflict interval", - stats.factor, relative (stats.conflicts, stats.factor)); - PRT (" cls factored: %15" PRId64 " %10.2f per factored", - stats.factor_added, relative (stats.factor_added, factored)); - PRT (" lits factored: %15" PRId64 " %10.2f per factored", - stats.literals_factored, - relative (stats.literals_factored, factored)); - PRT (" cls unfactored:%15" PRId64 " %10.2f per factored", - stats.clauses_unfactored, - relative (stats.clauses_unfactored, factored)); - PRT (" lits unfactored:%14" PRId64 " %10.2f per factored", - stats.literals_unfactored, - relative (stats.literals_unfactored, factored)); - } - if (all || stats.all.fixed) { - PRT ("fixed: %15" PRId64 " %10.2f %% of all variables", - stats.all.fixed, percent (stats.all.fixed, stats.vars)); - PRT (" failed: %15" PRId64 " %10.2f %% of all variables", - stats.failed, percent (stats.failed, stats.vars)); - PRT (" probefailed: %15" PRId64 " %10.2f %% per failed", - stats.probefailed, percent (stats.probefailed, stats.failed)); - PRT (" transredunits: %15" PRId64 " %10.2f %% per failed", - stats.transredunits, percent (stats.transredunits, stats.failed)); - PRT (" inprobephases: %15" PRId64 " %10.2f interval", - stats.inprobingphases, - relative (stats.conflicts, stats.inprobingphases)); - PRT (" inprobesuccess:%15" PRId64 " %10.2f %% phases", - stats.inprobesuccess, - percent (stats.inprobesuccess, stats.inprobingphases)); - PRT (" probingrounds: %15" PRId64 " %10.2f per phase", - stats.probingrounds, - relative (stats.probingrounds, stats.inprobingphases)); - PRT (" probed: %15" PRId64 " %10.2f per failed", - stats.probed, relative (stats.probed, stats.failed)); - PRT (" hbrs: %15" PRId64 " %10.2f per probed", - stats.hbrs, relative (stats.hbrs, stats.probed)); - PRT (" hbrsizes: %15" PRId64 " %10.2f per hbr", - stats.hbrsizes, relative (stats.hbrsizes, stats.hbrs)); - PRT (" hbreds: %15" PRId64 " %10.2f %% per hbr", - stats.hbreds, percent (stats.hbreds, stats.hbrs)); - PRT (" hbrsubs: %15" PRId64 " %10.2f %% per hbr", - stats.hbrsubs, percent (stats.hbrsubs, stats.hbrs)); - } - PRT (" units: %15" PRId64 " %10.2f interval", stats.units, - relative (stats.conflicts, stats.units)); - PRT (" binaries: %15" PRId64 " %10.2f interval", - stats.binaries, relative (stats.conflicts, stats.binaries)); - if (all || stats.flush.learned) { - PRT ("flushed: %15" PRId64 " %10.2f %% per conflict", - stats.flush.learned, - percent (stats.flush.learned, stats.conflicts)); - PRT (" hyper: %15" PRId64 " %10.2f %% per conflict", - stats.flush.hyper, relative (stats.flush.hyper, stats.conflicts)); - PRT (" flushings: %15" PRId64 " %10.2f interval", - stats.flush.count, relative (stats.conflicts, stats.flush.count)); - } - if (all || stats.instantiated) { - PRT ("instantiated: %15" PRId64 " %10.2f %% of tried", - stats.instantiated, percent (stats.instantiated, stats.instried)); - PRT (" instrounds: %15" PRId64 " %10.2f %% of elimrounds", - stats.instrounds, percent (stats.instrounds, stats.elimrounds)); - } - if (all || stats.conflicts) { - PRT ("learned: %15" PRId64 " %10.2f %% per conflict", - stats.learned.clauses, - percent (stats.learned.clauses, stats.conflicts)); - PRT ("@ bumped: %15" PRId64 " %10.2f per learned", - stats.bumped, relative (stats.bumped, stats.learned.clauses)); - PRT (" recomputed: %15" PRId64 " %10.2f %% per learned", - stats.recomputed, - percent (stats.recomputed, stats.learned.clauses)); - PRT (" promoted1: %15" PRId64 " %10.2f %% per learned", - stats.promoted1, percent (stats.promoted1, stats.learned.clauses)); - PRT (" promoted2: %15" PRId64 " %10.2f %% per learned", - stats.promoted2, percent (stats.promoted2, stats.learned.clauses)); - PRT (" improvedglue: %15" PRId64 " %10.2f %% per learned", - stats.improvedglue, - percent (stats.improvedglue, stats.learned.clauses)); - } - if (all || stats.lucky.succeeded) { - PRT ("lucky: %15" PRId64 " %10.2f %% of tried", - stats.lucky.succeeded, - percent (stats.lucky.succeeded, stats.lucky.tried)); - PRT (" constantzero %15" PRId64 " %10.2f %% of tried", - stats.lucky.constant.zero, - percent (stats.lucky.constant.zero, stats.lucky.tried)); - PRT (" constantone %15" PRId64 " %10.2f %% of tried", - stats.lucky.constant.one, - percent (stats.lucky.constant.one, stats.lucky.tried)); - PRT (" backwardone %15" PRId64 " %10.2f %% of tried", - stats.lucky.backward.one, - percent (stats.lucky.backward.one, stats.lucky.tried)); - PRT (" backwardzero %15" PRId64 " %10.2f %% of tried", - stats.lucky.backward.zero, - percent (stats.lucky.backward.zero, stats.lucky.tried)); - PRT (" forwardone %15" PRId64 " %10.2f %% of tried", - stats.lucky.forward.one, - percent (stats.lucky.forward.one, stats.lucky.tried)); - PRT (" forwardzero %15" PRId64 " %10.2f %% of tried", - stats.lucky.forward.zero, - percent (stats.lucky.forward.zero, stats.lucky.tried)); - PRT (" positivehorn %15" PRId64 " %10.2f %% of tried", - stats.lucky.horn.positive, - percent (stats.lucky.horn.positive, stats.lucky.tried)); - PRT (" negativehorn %15" PRId64 " %10.2f %% of tried", - stats.lucky.horn.negative, - percent (stats.lucky.horn.negative, stats.lucky.tried)); - } - PRT (" extendbytes: %15zd %10.2f bytes and MB", extendbytes, - extendbytes / (double) (1l << 20)); - if (all || stats.learned.clauses) - PRT ("learned_lits: %15" PRId64 " %10.2f %% learned literals", - stats.learned.literals, - percent (stats.learned.literals, stats.learned.literals)); - PRT ("minimized: %15" PRId64 " %10.2f %% learned literals", - stats.minimized, percent (stats.minimized, stats.learned.literals)); - PRT ("shrunken: %15" PRId64 " %10.2f %% learned literals", - stats.shrunken, percent (stats.shrunken, stats.learned.literals)); - PRT ("minishrunken: %15" PRId64 " %10.2f %% learned literals", - stats.minishrunken, - percent (stats.minishrunken, stats.learned.literals)); - - if (all || stats.conflicts) { - PRT ("otfs: %15" PRId64 " %10.2f %% of conflict", - stats.otfs.subsumed + stats.otfs.strengthened, - percent (stats.otfs.subsumed + stats.otfs.strengthened, - stats.conflicts)); - PRT (" subsumed %15" PRId64 " %10.2f %% of conflict", - stats.otfs.subsumed, - percent (stats.otfs.subsumed, stats.conflicts)); - PRT (" strengthened %15" PRId64 " %10.2f %% of conflict", - stats.otfs.strengthened, - percent (stats.otfs.strengthened, stats.conflicts)); - } - - PRT ("propagations: %15" PRId64 " %10.2f M per second", - propagations, relative (propagations / 1e6, t)); - PRT (" coverprops: %15" PRId64 " %10.2f %% of propagations", - stats.propagations.cover, - percent (stats.propagations.cover, propagations)); - PRT (" probeprops: %15" PRId64 " %10.2f %% of propagations", - stats.propagations.probe, - percent (stats.propagations.probe, propagations)); - PRT (" searchprops: %15" PRId64 " %10.2f %% of propagations", - stats.propagations.search, - percent (stats.propagations.search, propagations)); - PRT (" transredprops: %15" PRId64 " %10.2f %% of propagations", - stats.propagations.transred, - percent (stats.propagations.transred, propagations)); - PRT (" vivifyprops: %15" PRId64 " %10.2f %% of propagations", - stats.propagations.vivify, - percent (stats.propagations.vivify, propagations)); - PRT (" walkprops: %15" PRId64 " %10.2f %% of propagations", - stats.propagations.walk, - percent (stats.propagations.walk, propagations)); - if (all || stats.reactivated) { - PRT ("reactivated: %15" PRId64 " %10.2f %% of all variables", - stats.reactivated, percent (stats.reactivated, stats.vars)); - } - if (all || stats.reduced) { - PRT ("reduced: %15" PRId64 " %10.2f %% per conflict", - stats.reduced, percent (stats.reduced, stats.conflicts)); - PRT (" reductions: %15" PRId64 " %10.2f interval", - stats.reductions, relative (stats.conflicts, stats.reductions)); - PRT (" sqrt scheme: %15" PRId64 " %10.2f %% reductions", - stats.reduced_sqrt, - relative (stats.reduced_sqrt, stats.reductions)); - PRT (" prct scheme: %15" PRId64 " %10.2f %% reductions", - stats.reduced_prct, - relative (stats.reduced_prct, stats.reductions)); - PRT (" collections: %15" PRId64 " %10.2f interval", - stats.collections, relative (stats.conflicts, stats.collections)); - } - if (all || stats.rephased.total) { - PRT ("rephased: %15" PRId64 " %10.2f interval", - stats.rephased.total, - relative (stats.conflicts, stats.rephased.total)); - PRT (" rephasedbest: %15" PRId64 " %10.2f %% rephased best", - stats.rephased.best, - percent (stats.rephased.best, stats.rephased.total)); - PRT (" rephasedflip: %15" PRId64 " %10.2f %% rephased flipping", - stats.rephased.flipped, - percent (stats.rephased.flipped, stats.rephased.total)); - PRT (" rephasedinv: %15" PRId64 " %10.2f %% rephased inverted", - stats.rephased.inverted, - percent (stats.rephased.inverted, stats.rephased.total)); - PRT (" rephasedorig: %15" PRId64 " %10.2f %% rephased original", - stats.rephased.original, - percent (stats.rephased.original, stats.rephased.total)); - PRT (" rephasedrand: %15" PRId64 " %10.2f %% rephased random", - stats.rephased.random, - percent (stats.rephased.random, stats.rephased.total)); - PRT (" rephasedwalk: %15" PRId64 " %10.2f %% rephased walk", - stats.rephased.walk, - percent (stats.rephased.walk, stats.rephased.total)); - } - if (all) - PRT ("rescored: %15" PRId64 " %10.2f interval", - stats.rescored, relative (stats.conflicts, stats.rescored)); - if (all || stats.restarts) { - PRT ("restarts: %15" PRId64 " %10.2f interval", - stats.restarts, relative (stats.conflicts, stats.restarts)); - PRT (" reused: %15" PRId64 " %10.2f %% per restart", - stats.reused, percent (stats.reused, stats.restarts)); - PRT (" reusedlevels: %15" PRId64 " %10.2f %% per restart levels", - stats.reusedlevels, - percent (stats.reusedlevels, stats.restartlevels)); - } - if (all || stats.restored) { - PRT ("restored: %15" PRId64 " %10.2f %% per weakened", - stats.restored, percent (stats.restored, stats.weakened)); - PRT (" restorations: %15" PRId64 " %10.2f %% per extension", - stats.restorations, - percent (stats.restorations, stats.extensions)); - PRT (" literals: %15" PRId64 " %10.2f per restored clause", - stats.restoredlits, relative (stats.restoredlits, stats.restored)); - } - if (all || stats.stabphases) { - PRT ("stabilizing: %15" PRId64 " %10.2f %% of conflicts", - stats.stabphases, percent (stats.stabconflicts, stats.conflicts)); - PRT (" restartstab: %15" PRId64 " %10.2f %% of all restarts", - stats.restartstable, - percent (stats.restartstable, stats.restarts)); - PRT (" reusedstab: %15" PRId64 " %10.2f %% per stable restarts", - stats.reusedstable, - percent (stats.reusedstable, stats.restartstable)); - } - if (all || stats.all.substituted) { - PRT ("substituted: %15" PRId64 " %10.2f %% of all variables", - stats.all.substituted, - percent (stats.all.substituted, stats.vars)); - PRT (" decompositions:%15" PRId64 " %10.2f per phase", - stats.decompositions, - relative (stats.decompositions, stats.inprobingphases)); - } - if (all || stats.sweep_equivalences) { - PRT ("sweep equivs: %15" PRId64 " %10.2f %% of swept variables", - stats.sweep_equivalences, - percent (stats.sweep_equivalences, stats.sweep_variables)); - PRT (" sweepings: %15" PRId64 " %10.2f vars per sweeping", - stats.sweep, relative (stats.sweep_variables, stats.sweep)); - PRT (" swept vars: %15" PRId64 " %10.2f %% of all variables", - stats.sweep_variables, - percent (stats.sweep_variables, stats.vars)); - PRT (" sweep units: %15" PRId64 " %10.2f %% of all variables", - stats.sweep_units, percent (stats.sweep_units, stats.vars)); - PRT (" solved: %15" PRId64 " %10.2f per swept variable", - stats.sweep_solved, - relative (stats.sweep_solved, stats.sweep_variables)); - PRT (" sat: %15" PRId64 " %10.2f %% solved", - stats.sweep_sat, percent (stats.sweep_sat, stats.sweep_solved)); - PRT (" unsat: %15" PRId64 " %10.2f %% solved", - stats.sweep_unsat, - percent (stats.sweep_unsat, stats.sweep_solved)); - PRT (" backbone solved:%14" PRId64 " %10.2f %% solved", - stats.sweep_solved_backbone, - percent (stats.sweep_solved_backbone, stats.sweep_solved)); - PRT (" sat: %15" PRId64 " %10.2f %% backbone solved", - stats.sweep_sat_backbone, - percent (stats.sweep_sat_backbone, stats.sweep_solved_backbone)); - PRT (" unsat: %15" PRId64 " %10.2f %% backbone solved", - stats.sweep_unsat_backbone, - percent (stats.sweep_unsat_backbone, stats.sweep_solved_backbone)); - PRT (" unknown: %15" PRId64 " %10.2f %% backbone solved", - stats.sweep_unknown_backbone, - percent (stats.sweep_unknown_backbone, - stats.sweep_solved_backbone)); - PRT (" fixed: %15" PRId64 " %10.2f per swept variable", - stats.sweep_fixed_backbone, - relative (stats.sweep_fixed_backbone, stats.sweep_variables)); - PRT (" flip: %15" PRId64 " %10.2f per swept variable", - stats.sweep_flip_backbone, - relative (stats.sweep_flip_backbone, stats.sweep_variables)); - PRT (" flipped: %15" PRId64 " %10.2f %% of backbone flip", - stats.sweep_flipped_backbone, - percent (stats.sweep_flipped_backbone, stats.sweep_flip_backbone)); - PRT (" equiv solved: %15" PRId64 " %10.2f %% solved", - stats.sweep_solved_equivalences, - percent (stats.sweep_solved_equivalences, stats.sweep_solved)); - PRT (" sat: %15" PRId64 " %10.2f %% equiv solved", - stats.sweep_sat_equivalences, - percent (stats.sweep_sat_equivalences, - stats.sweep_solved_equivalences)); - PRT (" unsat: %15" PRId64 " %10.2f %% equiv solved", - stats.sweep_unsat_equivalences, - percent (stats.sweep_unsat_equivalences, - stats.sweep_solved_equivalences)); - PRT (" unknown: %15" PRId64 " %10.2f %% equiv solved", - stats.sweep_unknown_equivalences, - percent (stats.sweep_unknown_equivalences, - stats.sweep_solved_equivalences)); - PRT (" flip: %15" PRId64 " %10.2f per swept variable", - stats.sweep_flip_equivalences, - relative (stats.sweep_flip_equivalences, stats.sweep_variables)); - PRT (" flipped: %15" PRId64 " %10.2f %% of equiv flip", - stats.sweep_flipped_equivalences, - percent (stats.sweep_flipped_equivalences, - stats.sweep_flip_equivalences)); - PRT (" depth: %15" PRId64 " %10.2f per swept variable", - stats.sweep_depth, - relative (stats.sweep_depth, stats.sweep_variables)); - PRT (" environment: %15" PRId64 " %10.2f per swept variable", - stats.sweep_environment, - relative (stats.sweep_environment, stats.sweep_variables)); - PRT (" clauses: %15" PRId64 " %10.2f per swept variable", - stats.sweep_clauses, - relative (stats.sweep_clauses, stats.sweep_variables)); - PRT (" completed: %15" PRId64 " %10.2f sweeps to complete", - stats.sweep_completed, - relative (stats.sweep, stats.sweep_completed)); - } - if (all || stats.subsumed) { - PRT ("subsumed: %15" PRId64 " %10.2f %% of all clauses", - stats.subsumed, percent (stats.subsumed, stats.added.total)); - PRT (" subsumephases: %15" PRId64 " %10.2f interval", - stats.subsumephases, - relative (stats.conflicts, stats.subsumephases)); - PRT (" subsumerounds: %15" PRId64 " %10.2f per phase", - stats.subsumerounds, - relative (stats.subsumerounds, stats.subsumephases)); - PRT (" deduplicated: %15" PRId64 " %10.2f %% per subsumed", - stats.deduplicated, percent (stats.deduplicated, stats.subsumed)); - PRT (" transreds: %15" PRId64 " %10.2f interval", - stats.transreds, relative (stats.conflicts, stats.transreds)); - PRT (" transitive: %15" PRId64 " %10.2f %% per subsumed", - stats.transitive, percent (stats.transitive, stats.subsumed)); - PRT (" subirr: %15" PRId64 " %10.2f %% of subsumed", - stats.subirr, percent (stats.subirr, stats.subsumed)); - PRT (" subred: %15" PRId64 " %10.2f %% of subsumed", - stats.subred, percent (stats.subred, stats.subsumed)); - PRT (" subtried: %15" PRId64 " %10.2f tried per subsumed", - stats.subtried, relative (stats.subtried, stats.subsumed)); - PRT (" subchecks: %15" PRId64 " %10.2f per tried", - stats.subchecks, relative (stats.subchecks, stats.subtried)); - PRT (" subchecks2: %15" PRId64 " %10.2f %% per subcheck", - stats.subchecks2, percent (stats.subchecks2, stats.subchecks)); - PRT (" elimotfsub: %15" PRId64 " %10.2f %% of subsumed", - stats.elimotfsub, percent (stats.elimotfsub, stats.subsumed)); - PRT (" elimbwsub: %15" PRId64 " %10.2f %% of subsumed", - stats.elimbwsub, percent (stats.elimbwsub, stats.subsumed)); - PRT (" eagersub: %15" PRId64 " %10.2f %% of subsumed", - stats.eagersub, percent (stats.eagersub, stats.subsumed)); - PRT (" eagertried: %15" PRId64 " %10.2f tried per eagersub", - stats.eagertried, relative (stats.eagertried, stats.eagersub)); - } - if (all || stats.strengthened) { - PRT ("strengthened: %15" PRId64 " %10.2f %% of all clauses", - stats.strengthened, - percent (stats.strengthened, stats.added.total)); - PRT (" elimotfstr: %15" PRId64 " %10.2f %% of strengthened", - stats.elimotfstr, percent (stats.elimotfstr, stats.strengthened)); - PRT (" elimbwstr: %15" PRId64 " %10.2f %% of strengthened", - stats.elimbwstr, percent (stats.elimbwstr, stats.strengthened)); - } - if (all || stats.htrs) { - PRT ("ternary: %15" PRId64 " %10.2f %% of resolved", - stats.htrs, percent (stats.htrs, stats.ternres)); - PRT (" phases: %15" PRId64 " %10.2f interval", - stats.ternary, relative (stats.conflicts, stats.ternary)); - PRT (" htr3: %15" PRId64 - " %10.2f %% ternary hyper ternres", - stats.htrs3, percent (stats.htrs3, stats.htrs)); - PRT (" htr2: %15" PRId64 " %10.2f %% binary hyper ternres", - stats.htrs2, percent (stats.htrs2, stats.htrs)); - } - PRT ("ticks: %15" PRId64 " %10.2f propagation", totalticks, - relative (totalticks, stats.propagations.search)); - PRT (" searchticks: %15" PRId64 " %10.2f %% totalticks", - searchticks, percent (searchticks, totalticks)); - PRT (" stableticks: %15" PRId64 " %10.2f %% searchticks", - stats.ticks.search[1], percent (stats.ticks.search[1], searchticks)); - PRT (" unstableticks:%15" PRId64 " %10.2f %% searchticks", - stats.ticks.search[0], percent (stats.ticks.search[0], searchticks)); - PRT (" inprobeticks: %15" PRId64 " %10.2f %% totalticks", - inprobeticks, percent (inprobeticks, totalticks)); - PRT (" factorticks: %15" PRId64 " %10.2f %% searchticks", - stats.ticks.factor, percent (stats.ticks.factor, searchticks)); - PRT (" probeticks: %15" PRId64 " %10.2f %% searchticks", - stats.ticks.probe, percent (stats.ticks.probe, searchticks)); - PRT (" sweepticks: %15" PRId64 " %10.2f %% searchticks", - stats.ticks.sweep, percent (stats.ticks.sweep, searchticks)); - PRT (" ternaryticks: %15" PRId64 " %10.2f %% searchticks", - stats.ticks.ternary, percent (stats.ticks.ternary, searchticks)); - PRT (" vivifyticks: %15" PRId64 " %10.2f %% searchticks", - stats.ticks.vivify, percent (stats.ticks.vivify, searchticks)); - if (all) { - PRT ("tier recomputed: %15" PRId64 " %10.2f interval", - stats.tierecomputed, - relative (stats.conflicts, stats.tierecomputed)); - } - if (all || stats.ilbtriggers) { - PRT ("trail reuses: %15" PRId64 " %10.2f %% of incremental calls", - stats.ilbsuccess, percent (stats.ilbsuccess, stats.ilbtriggers)); - PRT (" levels: %15" PRId64 " %10.2f per reuse", - stats.levelsreused, - relative (stats.levelsreused, stats.ilbsuccess)); - PRT (" literals: %15" PRId64 " %10.2f per reuse", - stats.literalsreused, - relative (stats.literalsreused, stats.ilbsuccess)); - PRT (" assumptions: %15" PRId64 " %10.2f per reuse", - stats.assumptionsreused, - relative (stats.assumptionsreused, stats.ilbsuccess)); - } - if (all || vivified) { - PRT ("vivified: %15" PRId64 " %10.2f %% of all clauses", - vivified, percent (vivified, stats.added.total)); - PRT (" vivifications: %15" PRId64 " %10.2f interval", - stats.vivifications, - relative (stats.conflicts, stats.vivifications)); - PRT (" vivifychecks: %15" PRId64 " %10.2f %% per conflict", - stats.vivifychecks, percent (stats.vivifychecks, stats.conflicts)); - PRT (" vivifysched: %15" PRId64 " %10.2f %% checks per scheduled", - stats.vivifysched, - percent (stats.vivifychecks, stats.vivifysched)); - PRT (" vivifyunits: %15" PRId64 " %10.2f %% per vivify check", - stats.vivifyunits, - percent (stats.vivifyunits, stats.vivifychecks)); - PRT (" vivifyinst: %15" PRId64 " %10.2f %% per vivify check", - stats.vivifyinst, percent (stats.vivifyinst, stats.vivifychecks)); - PRT (" vivifysubs: %15" PRId64 " %10.2f %% per subsumed", - stats.vivifysubs, percent (stats.vivifysubs, stats.subsumed)); - PRT (" vivifysubred: %15" PRId64 " %10.2f %% per subs", - stats.vivifysubred, - percent (stats.vivifysubred, stats.vivifysubs)); - PRT (" vivifysubirr: %15" PRId64 " %10.2f %% per subs", - stats.vivifysubirr, - percent (stats.vivifysubirr, stats.vivifysubs)); - PRT (" vivifystrs: %15" PRId64 " %10.2f %% per strengthened", - stats.vivifystrs, percent (stats.vivifystrs, stats.strengthened)); - PRT (" vivifystrirr: %15" PRId64 " %10.2f %% per vivifystrs", - stats.vivifystrirr, - percent (stats.vivifystrirr, stats.vivifystrs)); - PRT (" vivifystred1: %15" PRId64 " %10.2f %% per vivifystrs", - stats.vivifystred1, - percent (stats.vivifystred1, stats.vivifystrs)); - PRT (" vivifystred2: %15" PRId64 " %10.2f %% per viviyfstrs", - stats.vivifystred2, - percent (stats.vivifystred2, stats.vivifystrs)); - PRT (" vivifystred3: %15" PRId64 " %10.2f %% per vivifystrs", - stats.vivifystred3, - percent (stats.vivifystred3, stats.vivifystrs)); - PRT (" vivifydemote: %15" PRId64 " %10.2f %% per vivifystrs", - stats.vivifydemote, - percent (stats.vivifydemote, stats.vivifystrs)); - PRT (" vivifydecs: %15" PRId64 " %10.2f per checks", - stats.vivifydecs, relative (stats.vivifydecs, stats.vivifychecks)); - PRT (" vivifyreused: %15" PRId64 " %10.2f %% per decision", - stats.vivifyreused, - percent (stats.vivifyreused, stats.vivifydecs)); - } - if (all || stats.walk.count) { - PRT ("walked: %15" PRId64 " %10.2f interval", - stats.walk.count, relative (stats.conflicts, stats.walk.count)); -#ifndef CADICAL_QUIET - if (internal->profiles.walk.value > 0) - PRT (" flips: %15" PRId64 " %10.2f M per second", - stats.walk.flips, - relative (1e-6 * stats.walk.flips, - internal->profiles.walk.value)); - else -#endif - PRT (" flips: %15" PRId64 " %10.2f per walk", - stats.walk.flips, relative (stats.walk.flips, stats.walk.count)); - if (stats.walk.minimum < LONG_MAX) - PRT (" minimum: %15" PRId64 " %10.2f %% clauses", - stats.walk.minimum, - percent (stats.walk.minimum, stats.added.irredundant)); - PRT (" broken: %15" PRId64 " %10.2f per flip", - stats.walk.broken, relative (stats.walk.broken, stats.walk.flips)); - } - if (all || stats.weakened) { - PRT ("weakened: %15" PRId64 " %10.2f average size", - stats.weakened, relative (stats.weakenedlen, stats.weakened)); - PRT (" extensions: %15" PRId64 " %10.2f interval", - stats.extensions, relative (stats.conflicts, stats.extensions)); - PRT (" flipped: %15" PRId64 " %10.2f per weakened", - stats.extended, relative (stats.extended, stats.weakened)); - } - - if (all || stats.congruence.gates) { - PRT ("congruence: %15" PRId64 " %10.2f interval", - stats.congruence.rounds, - relative (stats.conflicts, stats.congruence.rounds)); - PRT (" units: %15" PRId64 " %10.2f per congruent", - stats.congruence.units, - relative (stats.congruence.units, stats.congruence.congruent)); - PRT (" cong-and: %15" PRId64 " %10.2f per found gates", - stats.congruence.ands, - relative (stats.congruence.ands, stats.congruence.gates)); - PRT (" cong-ite: %15" PRId64 " %10.2f per found gates", - stats.congruence.ites, - relative (stats.congruence.ites, stats.congruence.gates)); - PRT (" cong-xor: %15" PRId64 " %10.2f per found gates", - stats.congruence.xors, - relative (stats.congruence.xors, stats.congruence.gates)); - PRT (" congruent: %15" PRId64 " %10.2f per round", - stats.congruence.congruent, - relative (stats.congruence.rounds, stats.congruence.congruent)); - PRT (" unaries: %15" PRId64 " %10.2f per round", - stats.congruence.unaries, - relative (stats.congruence.rounds, stats.congruence.unaries)); - PRT (" rewri.-ands: %15" PRId64 " %10.2f per round", - stats.congruence.rewritten_ands, - relative (stats.congruence.rounds, - stats.congruence.rewritten_ands)); - PRT (" subsumed: %15" PRId64 " %10.2f per round", - stats.congruence.subsumed, - relative (stats.congruence.rounds, stats.congruence.subsumed)); - } - - LINE (); - MSG ("%sseconds are measured in %s time for solving%s", - tout.magenta_code (), internal->opts.realtime ? "real" : "process", - tout.normal_code ()); - -#endif // ifndef CADICAL_QUIET -} - -void Internal::print_resource_usage () { -#ifndef CADICAL_QUIET - SECTION ("resources"); - uint64_t m = maximum_resident_set_size (); - MSG ("total process time since initialization: %12.2f seconds", - internal->process_time ()); - MSG ("total real time since initialization: %12.2f seconds", - internal->real_time ()); - MSG ("maximum resident set size of process: %12.2f MB", - m / (double) (1l << 20)); -#endif -} - -/*------------------------------------------------------------------------*/ - -void Checker::print_stats () { - - if (!stats.added && !stats.deleted) - return; - - SECTION ("checker statistics"); - - MSG ("checks: %15" PRId64 "", stats.checks); - MSG ("assumptions: %15" PRId64 " %10.2f per check", - stats.assumptions, relative (stats.assumptions, stats.checks)); - MSG ("propagations: %15" PRId64 " %10.2f per check", - stats.propagations, relative (stats.propagations, stats.checks)); - MSG ("original: %15" PRId64 " %10.2f %% of all clauses", - stats.original, percent (stats.original, stats.added)); - MSG ("derived: %15" PRId64 " %10.2f %% of all clauses", - stats.derived, percent (stats.derived, stats.added)); - MSG ("deleted: %15" PRId64 " %10.2f %% of all clauses", - stats.deleted, percent (stats.deleted, stats.added)); - MSG ("insertions: %15" PRId64 " %10.2f %% of all clauses", - stats.insertions, percent (stats.insertions, stats.added)); - MSG ("collections: %15" PRId64 " %10.2f deleted per collection", - stats.collections, relative (stats.collections, stats.deleted)); - MSG ("collisions: %15" PRId64 " %10.2f per search", - stats.collisions, relative (stats.collisions, stats.searches)); - MSG ("searches: %15" PRId64 "", stats.searches); - MSG ("units: %15" PRId64 "", stats.units); -} - -void LratChecker::print_stats () { - - if (!stats.added && !stats.deleted) - return; - - SECTION ("lrat checker statistics"); - - MSG ("checks: %15" PRId64 "", stats.checks); - MSG ("insertions: %15" PRId64 " %10.2f %% of all clauses", - stats.insertions, percent (stats.insertions, stats.added)); - MSG ("original: %15" PRId64 " %10.2f %% of all clauses", - stats.original, percent (stats.original, stats.added)); - MSG ("derived: %15" PRId64 " %10.2f %% of all clauses", - stats.derived, percent (stats.derived, stats.added)); - MSG ("deleted: %15" PRId64 " %10.2f %% of all clauses", - stats.deleted, percent (stats.deleted, stats.added)); - MSG ("finalized: %15" PRId64 " %10.2f %% of all clauses", - stats.finalized, percent (stats.finalized, stats.added)); - MSG ("collections: %15" PRId64 " %10.2f deleted per collection", - stats.collections, relative (stats.collections, stats.deleted)); - MSG ("collisions: %15" PRId64 " %10.2f per search", - stats.collisions, relative (stats.collisions, stats.searches)); - MSG ("searches: %15" PRId64 "", stats.searches); -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_subsume.cpp b/src/sat/cadical/cadical_subsume.cpp deleted file mode 100644 index b75040ca8..000000000 --- a/src/sat/cadical/cadical_subsume.cpp +++ /dev/null @@ -1,652 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -/*------------------------------------------------------------------------*/ - -// This file implements a global forward subsumption algorithm, which is run -// frequently during search. It works both on original (irredundant) -// clauses and on 'sticky' learned clauses which are likely to be kept. -// This is abstracted away in the 'likely_to_be_kept_clause' function, which -// implicitly relies on 'opts.reducetier1glue' (glucose level of clauses -// which are not reduced) as well as dynamically determined size and glucose -// level ('lim.keptglue' and 'lim.keptsize') of clauses kept in 'reduce'. -// -// Note, that 'forward' means that the clause from which the subsumption -// check is started is checked for being subsumed by other (smaller or equal -// size) clauses. Since 'vivification' is an extended version of subsume, -// more powerful, but also slower, we schedule 'vivify' right after -// 'subsume', which in contrast to 'subsume' is not run until to completion. -// -// This implementation is inspired by Bayardo's SDM'11 analysis of our -// subsumption algorithm in our SATeLite preprocessor in the context of -// finding extremal sets in data mining and his suggested improvements. - -// Our original subsumption algorithm in 'Quantor' and 'SATeLite' (and in -// MiniSAT and descendants) is based on backward subsumption. It uses the -// observation that only the occurrence list of one literal of a clause has -// to be traversed in order to find all potential clauses which are subsumed -// by the candidate. Thus the literal with the smallest number of -// occurrences is used. However, that scheme requires to connect all -// literals of surviving clauses, while forward algorithms only need to -// connect one literal. On the other hand forward checking requires to -// traverse the occurrence lists of all literals of the candidate clause to -// find subsuming clauses. During connecting the single literal (similar to -// the one-watch scheme by Lintao Zhang) one can connect a literal with a -// minimal number of occurrence so far, which implicitly also reduces future -// occurrence list traversal time. - -// Also the actual subsumption check is cheaper since during backward -// checking the short subsuming candidate clause is marked and all the -// literals in the larger subsume candidate clauses have to be traversed, -// while for our forward approach the long subsumed candidate clause is only -// marked once, while the literals of the shorter subsuming clauses have to -// be checked. We also use a fixed special more cache friendly data -// structure for binary clauses, to avoid traversing them directly. - -// In our forward scheme it is still possible to skip occurrence lists of -// literals which were not added since the last subsumption round, since -// only those can contain subsuming candidates. Actually, clauses which -// contain at least one literal, which was not added since the last -// subsumption round do not have to be connected at all, even though they -// might still be subsumed them self. - -// Bayardo suggests to sort the literals in clauses and perform some kind of -// partial merge-sort, while we mark literals, but do sort literals during -// connecting a clause w.r.t. the number of occurrences, in order to find -// literals which do not occur in the subsumed candidate fast with high -// probability (less occurring literals have a higher chance). - -// This is the actual subsumption and strengthening check. We assume that -// all the literals of the candidate clause to be subsumed or strengthened -// are marked, so we only have to check that all the literals of the -// argument clause 'subsuming', which is checked for subsuming the candidate -// clause 'subsumed', has all its literals marked (in the correct phase). -// If exactly one is in the opposite phase we can still strengthen the -// candidate clause by this single literal which occurs in opposite phase. -// -// The result is INT_MIN if all literals are marked and thus the candidate -// clause can be subsumed. It is zero if neither subsumption nor -// strengthening is possible. Otherwise the candidate clause can be -// strengthened and as a result the negation of the literal which can be -// removed is returned. - -inline int Internal::subsume_check (Clause *subsuming, Clause *subsumed) { -#ifdef CADICAL_NDEBUG - (void) subsumed; -#endif - // Only use 'subsumed' for these following CADICAL_assertion checks. Otherwise we - // only require that 'subsumed' has all its literals marked. - // - CADICAL_assert (!subsumed->garbage); - CADICAL_assert (!subsuming->garbage); - CADICAL_assert (subsuming != subsumed); - CADICAL_assert (subsuming->size <= subsumed->size); - - stats.subchecks++; - if (subsuming->size == 2) - stats.subchecks2++; - - int flipped = 0, prev = 0; - bool failed = false; - const auto eoc = subsuming->end (); - for (auto i = subsuming->begin (); !failed && i != eoc; i++) { - int lit = *i; - *i = prev; - prev = lit; - const int tmp = marked (lit); - if (!tmp) - failed = true; - else if (tmp > 0) - continue; - else if (flipped) - failed = true; - else - flipped = lit; - } - CADICAL_assert (prev); - CADICAL_assert (!subsuming->literals[0]); - subsuming->literals[0] = prev; - if (failed) - return 0; - - if (!flipped) - return INT_MIN; // subsumed!! - else if (!opts.subsumestr) - return 0; - else - return flipped; // strengthen!! -} - -/*------------------------------------------------------------------------*/ - -// Candidate clause 'subsumed' is subsumed by 'subsuming'. - -inline void Internal::subsume_clause (Clause *subsuming, Clause *subsumed) { - stats.subsumed++; - CADICAL_assert (subsuming->size <= subsumed->size); - LOG (subsumed, "subsumed"); - if (subsumed->redundant) - stats.subred++; - else - stats.subirr++; - if (subsumed->redundant || !subsuming->redundant) { - mark_garbage (subsumed); - return; - } - LOG ("turning redundant subsuming clause into irredundant clause"); - subsuming->redundant = false; - if (proof) - proof->strengthen (subsuming->id); - mark_garbage (subsumed); - stats.current.irredundant++; - stats.added.irredundant++; - stats.irrlits += subsuming->size; - CADICAL_assert (stats.current.redundant > 0); - stats.current.redundant--; - CADICAL_assert (stats.added.redundant > 0); - stats.added.redundant--; - // ... and keep 'stats.added.total'. -} - -/*------------------------------------------------------------------------*/ - -// Candidate clause 'c' is strengthened by removing 'lit'. - -void Internal::strengthen_clause (Clause *c, int lit) { - if (opts.check && is_external_forgettable (c->id)) - mark_garbage_external_forgettable (c->id); - stats.strengthened++; - CADICAL_assert (c->size > 2); - LOG (c, "removing %d in", lit); - if (proof) { - LOG (lrat_chain, "strengthening clause with chain"); - proof->strengthen_clause (c, lit, lrat_chain); - } - if (!c->redundant) - mark_removed (lit); - auto new_end = remove (c->begin (), c->end (), lit); - CADICAL_assert (new_end + 1 == c->end ()), (void) new_end; - (void) shrink_clause (c, c->size - 1); - // bump_clause2 (c); - LOG (c, "strengthened"); - external->check_shrunken_clause (c); -} - -/*------------------------------------------------------------------------*/ - -// Find clauses connected in the occurrence lists 'occs' which subsume the -// candidate clause 'c' given as first argument. If this is the case the -// clause is subsumed and the result is positive. If the clause was -// strengthened the result is negative. Otherwise the candidate clause -// can not be subsumed nor strengthened and zero is returned. - -inline int Internal::try_to_subsume_clause (Clause *c, - vector &shrunken) { - - stats.subtried++; - CADICAL_assert (!level); - LOG (c, "trying to subsume"); - - mark (c); // signed! - - Clause *d = 0; - int flipped = 0; - - for (const auto &lit : *c) { - - // Only clauses which have a variable which has recently been added are - // checked for being subsumed. The idea is that all these newly added - // clauses are candidates for subsuming the clause. Then we also only - // need to check occurrences of these variables. The occurrence lists - // of other literal do not have to be checked. - // - if (!flags (lit).subsume) - continue; - - for (int sign = -1; !d && sign <= 1; sign += 2) { - - // First we check against all binary clauses. The other literals of - // all binary clauses of 'sign*lit' are stored in one consecutive - // array, which is way faster than storing clause pointers and - // dereferencing them. Since this binary clause array is also not - // shrunken, we also can bail out earlier if subsumption or - // strengthening is determined. - - // In both cases the (self-)subsuming clause is stored in 'd', which - // makes it nonzero and forces aborting both the outer and inner loop. - // If the binary clause can strengthen the candidate clause 'c' - // (through self-subsuming resolution), then 'filled' is set to the - // literal which can be removed in 'c', otherwise to 'INT_MIN' which - // is a non-valid literal. - - for (const auto &bin : bins (sign * lit)) { - const auto &other = bin.lit; - const int tmp = marked (other); - if (!tmp) - continue; - if (tmp < 0 && sign < 0) - continue; - if (tmp < 0) { - if (sign < 0) - continue; // tautological resolvent - dummy_binary->literals[0] = lit; - dummy_binary->literals[1] = other; - flipped = other; - } else { - dummy_binary->literals[0] = sign * lit; - dummy_binary->literals[1] = other; - flipped = (sign < 0) ? -lit : INT_MIN; - } - - // This dummy binary clauses is initialized in 'Internal::Internal' - // and only changes it literals in the lines above. By using such - // a faked binary clause we can simply reuse 'subsume_clause' as - // well as the code around 'strengthen_clause' uniform for both real - // clauses and this special case for binary clauses - - dummy_binary->id = bin.id; - d = dummy_binary; - - break; - } - - if (d) - break; - - // In this second loop we check for larger than binary clauses to - // subsume or strengthen the candidate clause. This is more costly, - // and needs a call to 'subsume_check'. Otherwise the same contract - // as above for communicating 'subsumption' or 'strengthening' to the - // code after the loop is used. - // - const Occs &os = occs (sign * lit); - for (const auto &e : os) { - CADICAL_assert (!e->garbage); // sanity check - if (e->garbage) - continue; // defensive: not needed - flipped = subsume_check (e, c); - if (!flipped) - continue; - d = e; // leave also outer loop - break; - } - } - - if (d) - break; - } - - unmark (c); - - if (flipped == INT_MIN) { - LOG (d, "subsuming"); - subsume_clause (d, c); - return 1; - } - - if (flipped) { - LOG (d, "strengthening"); - if (lrat) { - CADICAL_assert (lrat_chain.empty ()); - lrat_chain.push_back (c->id); - lrat_chain.push_back (d->id); - } - if (d->used > c->used) - c->used = d->used; - strengthen_clause (c, -flipped); - lrat_chain.clear (); - CADICAL_assert (likely_to_be_kept_clause (c)); - shrunken.push_back (c); - return -1; - } - - return 0; -} - - -struct subsume_less_noccs { - Internal *internal; - subsume_less_noccs (Internal *i) : internal (i) {} - bool operator() (int a, int b) { - const signed char u = internal->val (a), v = internal->val (b); - if (!u && v) - return true; - if (u && !v) - return false; - const int64_t m = internal->noccs (a), n = internal->noccs (b); - if (m < n) - return true; - if (m > n) - return false; - return abs (a) < abs (b); - } -}; - -/*------------------------------------------------------------------------*/ - -// Usually called from 'subsume' below if 'subsuming' triggered it. Then -// the idea is to subsume both redundant and irredundant clauses. It is also -// called in the elimination loop in 'elim' in which case we focus on -// irredundant clauses only to help bounded variable elimination. The -// function returns true of an irredundant clause was removed or -// strengthened, which might then in the second usage scenario trigger new -// variable eliminations. - -bool Internal::subsume_round () { - - if (!opts.subsume) - return false; - if (unsat) - return false; - if (terminated_asynchronously ()) - return false; - if (!stats.current.redundant && !stats.current.irredundant) - return false; - - START_SIMPLIFIER (subsume, SUBSUME); - stats.subsumerounds++; - - int64_t check_limit; - if (opts.subsumelimited) { - int64_t delta = stats.propagations.search; - delta *= 1e-3 * opts.subsumeeffort; - if (delta < opts.subsumemineff) - delta = opts.subsumemineff; - if (delta > opts.subsumemaxeff) - delta = opts.subsumemaxeff; - delta = max (delta, (int64_t) 2l * active ()); - - PHASE ("subsume-round", stats.subsumerounds, - "limit of %" PRId64 " subsumption checks", delta); - - check_limit = stats.subchecks + delta; - } else { - PHASE ("subsume-round", stats.subsumerounds, - "unlimited subsumption checks"); - check_limit = LONG_MAX; - } - - int old_marked_candidate_variables_for_elimination = stats.mark.elim; - - CADICAL_assert (!level); - - // Allocate schedule and occurrence lists. - // - vector schedule; - init_noccs (); - - // Determine candidate clauses and sort them by size. - // - int64_t left_over_from_last_subsumption_round = 0; - - for (auto c : clauses) { - - if (c->garbage) - continue; - if (c->size > opts.subsumeclslim) - continue; - if (!likely_to_be_kept_clause (c)) - continue; - - bool fixed = false; - int subsume = 0; - for (const auto &lit : *c) - if (val (lit)) - fixed = true; - else if (flags (lit).subsume) - subsume++; - - // If the clause contains a root level assigned (fixed) literal we will - // not work on it. This simplifies the code substantially since we do - // not have to care about assignments at all. Strengthening becomes - // much simpler too. - // - if (fixed) { - LOG (c, "skipping (fixed literal)"); - continue; - } - - // Further, if less than two variables in the clause were added since - // the last subsumption round, the clause is ignored too. - // - if (subsume < 2) { - LOG (c, "skipping (only %d added literals)", subsume); - continue; - } - - if (c->subsume) - left_over_from_last_subsumption_round++; - schedule.push_back (ClauseSize (c->size, c)); - for (const auto &lit : *c) - noccs (lit)++; - } - shrink_vector (schedule); - - // Smaller clauses are checked and connected first. - // - rsort (schedule.begin (), schedule.end (), smaller_clause_size_rank ()); - - if (!left_over_from_last_subsumption_round) - for (auto cs : schedule) - if (cs.clause->size > 2) - cs.clause->subsume = true; - -#ifndef CADICAL_QUIET - int64_t scheduled = schedule.size (); - int64_t total = stats.current.irredundant + stats.current.redundant; - PHASE ("subsume-round", stats.subsumerounds, - "scheduled %" PRId64 " clauses %.0f%% out of %" PRId64 " clauses", - scheduled, percent (scheduled, total), total); -#endif - - // Now go over the scheduled clauses in the order of increasing size and - // try to forward subsume and strengthen them. Forward subsumption tries - // to find smaller or same size clauses which subsume or might strengthen - // the candidate. After the candidate has been processed connect one - // of its literals (with smallest number of occurrences at this point) in - // a one-watched scheme. - - int64_t subsumed = 0, strengthened = 0, checked = 0; - - vector shrunken; - init_occs (); - init_bins (); - - for (const auto &s : schedule) { - - if (terminated_asynchronously ()) - break; - if (stats.subchecks >= check_limit) - break; - - Clause *c = s.clause; - CADICAL_assert (!c->garbage); - - checked++; - - // First try to subsume or strengthen this candidate clause. For binary - // clauses this could be done much faster by hashing and is costly due - // to a usually large number of binary clauses. There is further the - // issue, that strengthening binary clauses (through double - // self-subsuming resolution) would produce units, which needs much more - // care. In the same (lazy) spirit we also ignore clauses with fixed - // literals (false or true). - // - if (c->size > 2 && c->subsume) { - c->subsume = false; - const int tmp = try_to_subsume_clause (c, shrunken); - if (tmp > 0) { - subsumed++; - continue; - } - if (tmp < 0) - strengthened++; - } - - // If not subsumed connect smallest occurring literal, where occurring - // means the number of times it was used to connect (as a one-watch) a - // previous smaller or equal sized clause. This minimizes the length of - // the occurrence lists traversed during 'try_to_subsume_clause'. Also - // note that this number is usually way smaller than the number of - // occurrences computed before and stored in 'noccs'. - // - int minlit = 0; - int64_t minoccs = 0; - size_t minsize = 0; - bool subsume = true; - bool binary = (c->size == 2 && !c->redundant); - - for (const auto &lit : *c) { - - if (!flags (lit).subsume) - subsume = false; - const size_t size = binary ? bins (lit).size () : occs (lit).size (); - if (minlit && minsize <= size) - continue; - const int64_t tmp = noccs (lit); - if (minlit && minsize == size && tmp <= minoccs) - continue; - minlit = lit, minsize = size, minoccs = tmp; - } - - // If there is a variable in a clause different from is not 'subsume' - // (has been added since the last subsumption round), then this clause - // can not serve to strengthen or subsume another clause, since all - // shrunken or added clauses mark all their variables as 'subsume'. - // - if (!subsume) - continue; - - if (!binary) { - - // If smallest occurring literal occurs too often do not connect. - // - if (minsize > (size_t) opts.subsumeocclim) - continue; - - LOG (c, - "watching %d with %zd current and total %" PRId64 " occurrences", - minlit, minsize, minoccs); - - occs (minlit).push_back (c); - - // This sorting should give faster failures for assumption checks - // since the less occurring variables are put first in a clause and - // thus will make it more likely to be found as witness for a clause - // not to be subsuming. One could in principle (see also the - // discussion on 'subsumption' in our 'Splatz' solver) replace marking - // by a kind of merge sort, as also suggested by Bayardo. It would - // avoid 'marked' calls and thus might be slightly faster but could - // not take benefit of this sorting optimization. - // - sort (c->begin (), c->end (), subsume_less_noccs (this)); - - } else { - - // If smallest occurring literal occurs too often do not connect. - // - if (minsize > (size_t) opts.subsumebinlim) - continue; - - LOG (c, - "watching %d with %zd current binary and total %" PRId64 - " occurrences", - minlit, minsize, minoccs); - - const int minlit_pos = (c->literals[1] == minlit); - const int other = c->literals[!minlit_pos]; - bins (minlit).push_back (Bin{other, c->id}); - } - } - - PHASE ("subsume-round", stats.subsumerounds, - "subsumed %" PRId64 " and strengthened %" PRId64 " out of %" PRId64 - " clauses %.0f%%", - subsumed, strengthened, scheduled, - percent (subsumed + strengthened, scheduled)); - - const int64_t remain = schedule.size () - checked; - const bool completed = !remain; - - if (completed) - PHASE ("subsume-round", stats.subsumerounds, - "checked all %" PRId64 " scheduled clauses", checked); - else - PHASE ("subsume-round", stats.subsumerounds, - "checked %" PRId64 " clauses %.0f%% of scheduled (%" PRId64 - " remain)", - checked, percent (checked, scheduled), remain); - - // Release occurrence lists and schedule. - // - erase_vector (schedule); - reset_noccs (); - reset_occs (); - reset_bins (); - - // Reset all old 'added' flags and mark variables in shrunken - // clauses as 'added' for the next subsumption round. - // - if (completed) - reset_subsume_bits (); - - for (const auto &c : shrunken) - mark_added (c); - erase_vector (shrunken); - - report ('s', !opts.reportall && !(subsumed + strengthened)); - - STOP_SIMPLIFIER (subsume, SUBSUME); - - return old_marked_candidate_variables_for_elimination < stats.mark.elim; -} - -/*------------------------------------------------------------------------*/ - -void Internal::subsume () { - - if (!stats.current.redundant && !stats.current.irredundant) - return; - - if (unsat) - return; - - backtrack (); - if (!propagate ()) { - learn_empty_clause (); - return; - } - - stats.subsumephases++; - - if (external_prop) { - CADICAL_assert (!level); - private_steps = true; - } - - if (opts.subsume) { - reset_watches (); - subsume_round (); - init_watches (); - connect_watches (); - if (!unsat && !propagate ()) { - LOG ("propagation after subsume rounds results in inconsistency"); - learn_empty_clause (); - } - } - - transred (); - if (external_prop) { - CADICAL_assert (!level); - private_steps = false; - } -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_sweep.cpp b/src/sat/cadical/cadical_sweep.cpp deleted file mode 100644 index 4dca2b4bc..000000000 --- a/src/sat/cadical/cadical_sweep.cpp +++ /dev/null @@ -1,1959 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -Sweeper::Sweeper (Internal *i) - : internal (i), random (internal->opts.seed) { - random += internal->stats.sweep; // different seed every time - internal->init_sweeper (*this); -} - -Sweeper::~Sweeper () { - // this is already called actively - // internal->release_sweeper (this); - return; -} - -#define INVALID64 INT64_MAX -#define INVALID UINT_MAX - -int Internal::sweep_solve () { - START (sweepsolve); - cadical_kitten_randomize_phases (citten); - stats.sweep_solved++; - int res = cadical_kitten_solve (citten); - if (res == 10) - stats.sweep_sat++; - if (res == 20) - stats.sweep_unsat++; - STOP (sweepsolve); - return res; -} - -bool Internal::sweep_flip (int lit) { - START (sweepflip); - bool res = cadical_kitten_flip_signed_literal (citten, lit); - STOP (sweepflip); - return res; -} - -int Internal::sweep_flip_and_implicant (int lit) { - START (sweepimplicant); - int res = cadical_kitten_flip_and_implicant_for_signed_literal (citten, lit); - STOP (sweepimplicant); - return res; -} - -void Internal::sweep_set_cadical_kitten_ticks_limit (Sweeper &sweeper) { - uint64_t remaining = 0; - const uint64_t current = sweeper.current_ticks; - if (current < sweeper.limit.ticks) - remaining = sweeper.limit.ticks - current; - LOG ("'cadical_kitten_ticks' remaining %" PRIu64, remaining); - cadical_kitten_set_ticks_limit (citten, remaining); -} - -void Internal::sweep_update_noccs (Clause *c) { - if (c->redundant) - return; - for (const auto &lit : *c) { - noccs (lit)--; - } -} - -bool Internal::can_sweep_clause (Clause *c) { - if (c->garbage) - return false; - if (!c->redundant) - return true; - return c->size == 2; // && !c->hyper; // could ignore hyper -} - -// essentially do full occurence list as in elim.cpp -void Internal::sweep_dense_mode_and_watch_irredundant () { - reset_watches (); - - init_noccs (); - - // mark satisfied irredundant clauses as garbage - for (const auto &c : clauses) { - if (!can_sweep_clause (c)) - continue; - bool satisfied = false; - for (const auto &lit : *c) { - const signed char tmp = val (lit); - if (tmp <= 0) - continue; - if (tmp > 0) { - satisfied = true; - break; - } - } - if (satisfied) - mark_garbage (c); // forces more precise counts - else { - for (const auto &lit : *c) - noccs (lit)++; - } - } - - init_occs (); - - // Connect irredundant clauses. - // - for (const auto &c : clauses) { - if (!c->garbage) { - for (const auto &lit : *c) - if (active (lit)) - occs (lit).push_back (c); - } else if (c->size == 2) { - if (!c->flushed) { - if (proof) { - c->flushed = true; - proof->delete_clause (c); - } - } - } - } -} - -// go back to two watch scheme -void Internal::sweep_sparse_mode () { - reset_occs (); - reset_noccs (); - init_watches (); - connect_watches (); -} - -// propagate without watches but full occurence list -void Internal::sweep_dense_propagate (Sweeper &sweeper) { - vector &work = sweeper.propagate; - size_t i = 0; - uint64_t &ticks = sweeper.current_ticks; - while (i < work.size ()) { - int lit = work[i++]; - LOG ("sweeping propagation of %d", lit); - CADICAL_assert (val (lit) > 0); - ticks += 1 + cache_lines (occs (-lit).size (), sizeof (Clause *)); - const Occs &ns = occs (-lit); - for (const auto &c : ns) { - ticks++; - if (!can_sweep_clause (c)) - continue; - int unit = 0, satisfied = 0; - for (const auto &other : *c) { - const signed char tmp = val (other); - if (tmp < 0) - continue; - if (tmp > 0) { - satisfied = other; - break; - } - if (unit) - unit = INT_MIN; - else - unit = other; - } - if (satisfied) { - LOG (c, "sweeping propagation of %d finds %d satisfied", lit, - satisfied); - mark_garbage (c); - sweep_update_noccs (c); - } else if (!unit) { - LOG ("empty clause during sweeping propagation of %d", lit); - // need to set conflict = c for lrat - conflict = c; - learn_empty_clause (); - conflict = 0; - break; - } else if (unit != INT_MIN) { - LOG ("new unit %d during sweeping propagation of %d", unit, lit); - build_chain_for_units (unit, c, 0); - assign_unit (unit); - work.push_back (unit); - ticks++; - } - } - if (unsat) - break; - - // not necessary but should help - ticks += 1 + cache_lines (occs (lit).size (), sizeof (Clause *)); - const Occs &ps = occs (lit); - for (const auto &c : ps) { - ticks++; - if (c->garbage) - continue; - // if (c->redundant) // TODO I assume it does not hurt to mark - // everything here continue; - LOG (c, "sweeping propagation of %d produces satisfied", lit); - mark_garbage (c); - sweep_update_noccs (c); - } - } - work.clear (); -} - -bool Internal::cadical_kitten_ticks_limit_hit (Sweeper &sweeper, const char *when) { - const uint64_t current = - cadical_kitten_current_ticks (citten) + sweeper.current_ticks; - if (current >= sweeper.limit.ticks) { - LOG ("'cadical_kitten_ticks' limit of %" PRIu64 " ticks hit after %" PRIu64 - " ticks during %s", - sweeper.limit.ticks, current, when); - return true; - } -#ifndef LOGGING - (void) when; -#endif - return false; -} - -void Internal::init_sweeper (Sweeper &sweeper) { - sweeper.encoded = 0; - enlarge_zero (sweeper.depths, max_var + 1); - sweeper.reprs = new int[2 * max_var + 1]; - sweeper.reprs += max_var; - enlarge_zero (sweeper.prev, max_var + 1); - enlarge_zero (sweeper.next, max_var + 1); - for (const auto &lit : lits) - sweeper.reprs[lit] = lit; - sweeper.first = sweeper.last = 0; - sweeper.current_ticks = - 2 * - clauses - .size (); // initialize with the cost of building full occ list. - sweeper.current_ticks += - 2 + 2 * cache_lines (clauses.size (), sizeof (Clause *)); - CADICAL_assert (!citten); - citten = cadical_kitten_init (); - citten_clear_track_log_terminate (); - - sweep_dense_mode_and_watch_irredundant (); // full occurence list - - if (lrat) { - sweeper.prev_units.push_back (0); - for (const auto &idx : vars) { - sweeper.prev_units.push_back (val (idx) != 0); - } - } - - unsigned completed = stats.sweep_completed; - const unsigned max_completed = 32; - if (completed > max_completed) - completed = max_completed; - - uint64_t vars_limit = opts.sweepvars; - vars_limit <<= completed; - const unsigned max_vars_limit = opts.sweepmaxvars; - if (vars_limit > max_vars_limit) - vars_limit = max_vars_limit; - sweeper.limit.vars = vars_limit; - VERBOSE (3, "sweeper variable limit %u", sweeper.limit.vars); - - uint64_t depth_limit = stats.sweep_completed; - depth_limit += opts.sweepdepth; - const unsigned max_depth = opts.sweepmaxdepth; - if (depth_limit > max_depth) - depth_limit = max_depth; - sweeper.limit.depth = depth_limit; - VERBOSE (3, "sweeper depth limit %u", sweeper.limit.depth); - - uint64_t clause_limit = opts.sweepclauses; - clause_limit <<= completed; - const unsigned max_clause_limit = opts.sweepmaxclauses; - if (clause_limit > max_clause_limit) - clause_limit = max_clause_limit; - sweeper.limit.clauses = clause_limit; - VERBOSE (3, "sweeper clause limit %u", sweeper.limit.clauses); -} - -void Internal::release_sweeper (Sweeper &sweeper) { - - sweeper.reprs -= max_var; - delete[] sweeper.reprs; - - erase_vector (sweeper.depths); - erase_vector (sweeper.prev); - erase_vector (sweeper.next); - erase_vector (sweeper.vars); - erase_vector (sweeper.clause); - erase_vector (sweeper.backbone); - erase_vector (sweeper.partition); - erase_vector (sweeper.prev_units); - for (unsigned i = 0; i < 2; i++) - erase_vector (sweeper.core[i]); - - cadical_kitten_release (citten); - citten = 0; - stats.ticks.sweep += sweeper.current_ticks; - sweep_sparse_mode (); - return; -} - -void Internal::clear_sweeper (Sweeper &sweeper) { - LOG ("clearing sweeping environment"); - sweeper.current_ticks += cadical_kitten_current_ticks (citten); - - citten_clear_track_log_terminate (); - for (auto &idx : sweeper.vars) { - CADICAL_assert (sweeper.depths[idx]); - sweeper.depths[idx] = 0; - } - sweeper.vars.clear (); - for (auto c : sweeper.clauses) { - CADICAL_assert (c->swept); - c->swept = false; - } - sweeper.clauses.clear (); - sweeper.backbone.clear (); - sweeper.partition.clear (); - sweeper.encoded = 0; - sweep_set_cadical_kitten_ticks_limit (sweeper); -} - -int Internal::sweep_repr (Sweeper &sweeper, int lit) { - int res; - { - int prev = lit; - while ((res = sweeper.reprs[prev]) != prev) - prev = res; - } - if (res == lit) - return res; - LOG ("sweeping repr[%d] = %d", lit, res); - { - const int not_res = -res; - int next, prev = lit; - while ((next = sweeper.reprs[prev]) != res) { - const int not_prev = -prev; - sweeper.reprs[not_prev] = not_res; - sweeper.reprs[prev] = res; - prev = next; - } - CADICAL_assert (sweeper.reprs[-prev] == not_res); - } - return res; -} - -void Internal::add_literal_to_environment (Sweeper &sweeper, unsigned depth, - int lit) { - const int repr = sweep_repr (sweeper, lit); - if (repr != lit) - return; - const int idx = abs (lit); - if (sweeper.depths[idx]) - return; - CADICAL_assert (depth < UINT_MAX); - sweeper.depths[idx] = depth + 1; - CADICAL_assert (idx); - sweeper.vars.push_back (idx); - LOG ("sweeping[%u] adding literal %d", depth, lit); -} - -void Internal::sweep_add_clause (Sweeper &sweeper, unsigned depth) { - // TODO: CADICAL_assertion fails, check if this an issue or can be avoided - // CADICAL_assert (sweeper.clause.size () > 1); - for (const auto &lit : sweeper.clause) - add_literal_to_environment (sweeper, depth, lit); - citten_clause_with_id (citten, sweeper.clauses.size (), - sweeper.clause.size (), sweeper.clause.data ()); - sweeper.clause.clear (); - if (opts.sweepcountbinary || sweeper.clause.size () > 2) - sweeper.encoded++; -} - -void Internal::sweep_clause (Sweeper &sweeper, unsigned depth, Clause *c) { - if (c->swept) - return; - CADICAL_assert (can_sweep_clause (c)); - LOG (c, "sweeping[%u]", depth); - CADICAL_assert (sweeper.clause.empty ()); - for (const auto &lit : *c) { - const signed char tmp = val (lit); - if (tmp > 0) { - mark_garbage (c); - sweep_update_noccs (c); - sweeper.clause.clear (); - return; - } - if (tmp < 0) { - if (lrat) - sweeper.prev_units[abs (lit)] = true; - continue; - } - sweeper.clause.push_back (lit); - } - c->swept = true; - sweep_add_clause (sweeper, depth); - sweeper.clauses.push_back (c); -} - -extern "C" { -static void save_core_clause (void *state, unsigned id, bool learned, - size_t size, const unsigned *lits) { - Sweeper *sweeper = (Sweeper *) state; - Internal *internal = sweeper->internal; - if (internal->unsat) - return; - vector &core = sweeper->core[sweeper->save]; - sweep_proof_clause pc; - if (learned) { - pc.sweep_id = INVALID; // necessary - pc.cad_id = INVALID64; // delay giving ids - } else { - pc.sweep_id = id; // necessary - CADICAL_assert (id < sweeper->clauses.size ()); - pc.cad_id = sweeper->clauses[id]->id; - } - pc.kit_id = 0; - pc.learned = learned; - const unsigned *end = lits + size; - for (const unsigned *p = lits; p != end; p++) { - pc.literals.push_back (internal->citten2lit (*p)); // conversion - } -#ifdef LOGGING - LOG (pc.literals, "traced %s", - pc.learned == true ? "learned" : "original"); -#endif - core.push_back (pc); -} - -static void save_core_clause_with_lrat (void *state, unsigned cid, - unsigned id, bool learned, - size_t size, const unsigned *lits, - size_t chain_size, - const unsigned *chain) { - Sweeper *sweeper = (Sweeper *) state; - Internal *internal = sweeper->internal; - if (internal->unsat) - return; - vector &core = sweeper->core[sweeper->save]; - vector &clauses = sweeper->clauses; - sweep_proof_clause pc; - pc.kit_id = cid; - pc.learned = learned; - pc.sweep_id = INVALID; - pc.cad_id = INVALID64; - if (!learned) { - CADICAL_assert (size); - CADICAL_assert (!chain_size); - CADICAL_assert (id < clauses.size ()); - pc.sweep_id = id; - CADICAL_assert (id < clauses.size ()); - pc.cad_id = clauses[id]->id; - for (const auto &lit : *clauses[id]) { - pc.literals.push_back (lit); - } - } else { - CADICAL_assert (chain_size); - pc.sweep_id = INVALID; - pc.cad_id = INVALID64; // delay giving ids - const unsigned *end = lits + size; - for (const unsigned *p = lits; p != end; p++) { - pc.literals.push_back (internal->citten2lit (*p)); // conversion - } - for (const unsigned *p = chain + chain_size; p != chain; p--) { - pc.chain.push_back (*(p - 1)); - } - } -#ifdef LOGGING - if (learned) - LOG (pc.literals, "traced %s", - pc.learned == true ? "learned" : "original"); - else { - CADICAL_assert (id < clauses.size ()); - LOG (clauses[id], "traced"); - } -#endif - core.push_back (pc); -} - -static int citten_terminate (void *data) { - return ((Internal *) data)->terminated_asynchronously (); -} - -} // end extern C - -void Internal::citten_clear_track_log_terminate () { - CADICAL_assert (citten); - cadical_kitten_clear (citten); - cadical_kitten_track_antecedents (citten); - if (external->terminator) - cadical_kitten_set_terminator (citten, internal, citten_terminate); -#ifdef LOGGING - if (opts.log) - cadical_kitten_set_logging (citten); -#endif -} - -void Internal::add_core (Sweeper &sweeper, unsigned core_idx) { - if (unsat) - return; - LOG ("check and add extracted core[%u] lemmas to proof", core_idx); - CADICAL_assert (core_idx == 0 || core_idx == 1); - vector &core = sweeper.core[core_idx]; - - CADICAL_assert (!lrat || proof); - - unsigned unsat_size = 0; - for (auto &pc : core) { - unsat_size++; - - if (!pc.learned) { - LOG (pc.literals, - "not adding already present core[%u] cadical_kitten[%u] clause", - core_idx, pc.kit_id); - continue; - } - - LOG (pc.literals, "adding extracted core[%u] cadical_kitten[%u] lemma", - core_idx, pc.kit_id); - - const unsigned new_size = pc.literals.size (); - - if (lrat) { - CADICAL_assert (pc.cad_id == INVALID64); - for (auto &cid : pc.chain) { - int64_t id = 0; - for (const auto &cpc : core) { - if (cpc.kit_id == cid) { - if (cpc.learned) - id = cpc.cad_id; - else { - id = cpc.cad_id; - CADICAL_assert (cpc.cad_id == sweeper.clauses[cpc.sweep_id]->id); - CADICAL_assert (!sweeper.clauses[cpc.sweep_id]->garbage); - // avoid duplicate ids of units with seen flags - for (const auto &lit : cpc.literals) { - if (val (lit) >= 0) - continue; - if (flags (lit).seen) - continue; - const int idx = abs (lit); - if (sweeper.prev_units[idx]) { - int64_t uid = unit_id (-lit); - lrat_chain.push_back (uid); - analyzed.push_back (lit); - flags (lit).seen = true; - } - } - } - break; - } - } - CADICAL_assert (id); - if (id != INVALID64) - lrat_chain.push_back (id); - } - clear_analyzed_literals (); - } - - if (!new_size) { - LOG ("sweeping produced empty clause"); - learn_empty_clause (); - core.resize (unsat_size); - return; - } - - if (new_size == 1) { - int unit = pc.literals[0]; - if (val (unit) > 0) { - LOG ("already assigned sweeping unit %d", unit); - lrat_chain.clear (); - } else if (val (unit) < 0) { - LOG ("falsified sweeping unit %d leads to empty clause", unit); - if (lrat) { - int64_t id = unit_id (-unit); - lrat_chain.push_back (id); - } - learn_empty_clause (); - core.resize (unsat_size); - return; - } else { - LOG ("sweeping produced unit %d", unit); - assign_unit (unit); - stats.sweep_units++; - sweeper.propagate.push_back (unit); - } - if (proof && lrat) - pc.cad_id = unit_id (unit); - continue; - } - - CADICAL_assert (new_size > 1); - CADICAL_assert (pc.learned); - - if (proof) { - pc.cad_id = ++clause_id; - proof->add_derived_clause (pc.cad_id, true, pc.literals, lrat_chain); - lrat_chain.clear (); - } - } -} - -void Internal::save_core (Sweeper &sweeper, unsigned core) { - LOG ("saving extracted core[%u] lemmas", core); - CADICAL_assert (core == 0 || core == 1); - CADICAL_assert (sweeper.core[core].empty ()); - sweeper.save = core; - cadical_kitten_compute_clausal_core (citten, 0); - if (lrat) - cadical_kitten_trace_core (citten, &sweeper, save_core_clause_with_lrat); - else - cadical_kitten_traverse_core_clauses_with_id (citten, &sweeper, - save_core_clause); -} - -void Internal::clear_core (Sweeper &sweeper, unsigned core_idx) { - CADICAL_assert (core_idx == 0 || core_idx == 1); - LOG ("clearing core[%u] lemmas", core_idx); - vector &core = sweeper.core[core_idx]; - if (proof) { - LOG ("deleting sub-solver core clauses"); - for (auto &pc : core) { - if (pc.learned && pc.literals.size () > 1) - proof->delete_clause (pc.cad_id, true, pc.literals); - } - } - core.clear (); -} - -void Internal::save_add_clear_core (Sweeper &sweeper) { - save_core (sweeper, 0); - add_core (sweeper, 0); - clear_core (sweeper, 0); -} - -void Internal::init_backbone_and_partition (Sweeper &sweeper) { - LOG ("initializing backbone and equivalent literals candidates"); - sweeper.backbone.clear (); - sweeper.partition.clear (); - for (const auto &idx : sweeper.vars) { - if (!active (idx)) - continue; - CADICAL_assert (idx > 0); - const int lit = idx; - const int not_lit = -lit; - const signed char tmp = cadical_kitten_signed_value (citten, lit); - const int candidate = (tmp < 0) ? not_lit : lit; - LOG ("sweeping candidate %d", candidate); - sweeper.backbone.push_back (candidate); - sweeper.partition.push_back (candidate); - } - sweeper.partition.push_back (0); - - LOG (sweeper.backbone, "initialized backbone candidates"); - LOG (sweeper.partition, "initialized equivalence candidates"); -} - -void Internal::sweep_empty_clause (Sweeper &sweeper) { - CADICAL_assert (!unsat); - save_add_clear_core (sweeper); - CADICAL_assert (unsat); -} - -void Internal::sweep_refine_partition (Sweeper &sweeper) { - LOG ("refining partition"); - vector &old_partition = sweeper.partition; - vector new_partition; - auto old_begin = old_partition.begin (); - const auto old_end = old_partition.end (); -#ifdef LOGGING - unsigned old_classes = 0; - unsigned new_classes = 0; -#endif - for (auto p = old_begin, q = p; p != old_end; p = q + 1) { - unsigned assigned_true = 0; - int other; - for (q = p; (other = *q) != 0; q++) { - if (sweep_repr (sweeper, other) != other) - continue; - if (val (other)) - continue; - signed char value = cadical_kitten_signed_value (citten, other); - if (!value) - LOG ("dropping sub-solver unassigned %d", other); - else if (value > 0) { - new_partition.push_back (other); - assigned_true++; - } - } -#ifdef LOGGING - LOG ("refining class %u of size %zu", old_classes, (size_t) (q - p)); - old_classes++; -#endif - if (assigned_true == 0) - LOG ("no positive literal in class"); - else if (assigned_true == 1) { -#ifdef LOGGING - other = -#else - (void) -#endif - new_partition.back (); - new_partition.pop_back (); - LOG ("dropping singleton class %d", other); - } else { - LOG ("%u positive literal in class", assigned_true); - new_partition.push_back (0); -#ifdef LOGGING - new_classes++; -#endif - } - - unsigned assigned_false = 0; - for (q = p; (other = *q) != 0; q++) { - if (sweep_repr (sweeper, other) != other) - continue; - if (val (other)) - continue; - signed char value = cadical_kitten_signed_value (citten, other); - if (value < 0) { - new_partition.push_back (other); - assigned_false++; - } - } - - if (assigned_false == 0) - LOG ("no negative literal in class"); - else if (assigned_false == 1) { -#ifdef LOGGING - other = -#else - (void) -#endif - new_partition.back (); - new_partition.pop_back (); - LOG ("dropping singleton class %d", other); - } else { - LOG ("%u negative literal in class", assigned_false); - new_partition.push_back (0); -#ifdef LOGGING - new_classes++; -#endif - } - } - old_partition.swap (new_partition); - LOG ("refined %u classes into %u", old_classes, new_classes); -} - -void Internal::sweep_refine_backbone (Sweeper &sweeper) { - LOG ("refining backbone candidates"); - const auto end = sweeper.backbone.end (); - auto q = sweeper.backbone.begin (); - for (auto p = q; p != end; p++) { - const int lit = *p; - if (val (lit)) - continue; - signed char value = cadical_kitten_signed_value (citten, lit); - if (!value) - LOG ("dropping sub-solver unassigned %d", lit); - else if (value > 0) - *q++ = lit; - } - sweeper.backbone.resize (q - sweeper.backbone.begin ()); -} - -void Internal::sweep_refine (Sweeper &sweeper) { - CADICAL_assert (cadical_kitten_status (citten) == 10); - if (sweeper.backbone.empty ()) - LOG ("no need to refine empty backbone candidates"); - else - sweep_refine_backbone (sweeper); - if (sweeper.partition.empty ()) - LOG ("no need to refine empty partition candidates"); - else - sweep_refine_partition (sweeper); -} - -void Internal::flip_backbone_literals (Sweeper &sweeper) { - const unsigned max_rounds = opts.sweepfliprounds; - if (!max_rounds) - return; - CADICAL_assert (sweeper.backbone.size ()); - if (cadical_kitten_status (citten) != 10) - return; -#ifdef LOGGING - unsigned total_flipped = 0; -#endif - unsigned flipped, round = 0; - do { - round++; - flipped = 0; - bool refine = false; - auto begin = sweeper.backbone.begin (), q = begin, p = q; - const auto end = sweeper.backbone.end (); - bool limit_hit = false; - while (p != end) { - const int lit = *p++; - stats.sweep_flip_backbone++; - if (limit_hit || terminated_asynchronously ()) { - break; - } else if (sweep_flip (lit)) { - LOG ("flipping backbone candidate %d succeeded", lit); -#ifdef LOGGING - total_flipped++; -#endif - stats.sweep_flipped_backbone++; - flipped++; - } else { - LOG ("flipping backbone candidate %d failed", lit); - *q++ = lit; - } - } - while (p != end) - *q++ = *p++; - sweeper.backbone.resize (q - sweeper.backbone.begin ()); - LOG ("flipped %u backbone candidates in round %u", flipped, round); - - if (limit_hit) - break; - if (terminated_asynchronously ()) - break; - if (cadical_kitten_ticks_limit_hit (sweeper, "backbone flipping")) - break; - if (refine) - sweep_refine (sweeper); - } while (flipped && round < max_rounds); - LOG ("flipped %u backbone candidates in total in %u rounds", - total_flipped, round); -} - -bool Internal::sweep_extract_fixed (Sweeper &sweeper, int lit) { - const int not_lit = -lit; - stats.sweep_solved_backbone++; - cadical_kitten_assume_signed (citten, not_lit); - int res = sweep_solve (); - if (!res) { - stats.sweep_unknown_backbone++; - return false; - } - CADICAL_assert (res == 20); - LOG ("sweep unit %d", lit); - save_add_clear_core (sweeper); - stats.sweep_unsat_backbone++; - return true; -} - -bool Internal::sweep_backbone_candidate (Sweeper &sweeper, int lit) { - LOG ("trying backbone candidate %d", lit); - signed char value = cadical_kitten_fixed_signed (citten, lit); - if (value) { - stats.sweep_fixed_backbone++; - CADICAL_assert (value > 0); - if (val (lit) <= 0) { - return sweep_extract_fixed (sweeper, lit); - } else - LOG ("literal %d already fixed", lit); - return false; - } - - int res = cadical_kitten_status (citten); - if (res != 10) { - LOG ("not flipping due to status %d != 10", res); - } - stats.sweep_flip_backbone++; - if (res == 10 && sweep_flip (lit)) { - stats.sweep_flipped_backbone++; - LOG ("flipping %d succeeded", lit); - // LOGBACKBONE ("refined backbone candidates"); - return false; - } - - LOG ("flipping %d failed", lit); - const int not_lit = -lit; - stats.sweep_solved_backbone++; - cadical_kitten_assume_signed (citten, not_lit); - res = sweep_solve (); - if (res == 10) { - LOG ("sweeping backbone candidate %d failed", lit); - sweep_refine (sweeper); - stats.sweep_sat_backbone++; - return false; - } - - if (res == 20) { - LOG ("sweep unit %d", lit); - save_add_clear_core (sweeper); - CADICAL_assert (val (lit)); - stats.sweep_unsat_backbone++; - return true; - } - - stats.sweep_unknown_backbone++; - - LOG ("sweeping backbone candidate %d failed", lit); - return false; -} - -// at this point the binary (lit or other) is already present -// in the proof via 'add_core'. -// We just copy it as an irredundant clause, call weaken minus -// and push it on the extension stack. -// -int64_t Internal::add_sweep_binary (sweep_proof_clause pc, int lit, - int other) { - CADICAL_assert (!unsat); - if (unsat) - return 0; // sanity check, should be fuzzed - - CADICAL_assert (!val (lit) && !val (other)); - if (val (lit) || val (other)) - return 0; - - if (lrat) { - for (const auto &plit : pc.literals) { - if (val (plit)) { - int64_t id = unit_id (-plit); - lrat_chain.push_back (id); - } - } - lrat_chain.push_back (pc.cad_id); - } - clause.push_back (lit); - clause.push_back (other); - const int64_t id = ++clause_id; - if (proof) { - proof->add_derived_clause (id, false, clause, lrat_chain); - proof->weaken_minus (id, clause); - } - external->push_binary_clause_on_extension_stack (id, lit, other); - clause.clear (); - lrat_chain.clear (); - return id; -} - -void Internal::delete_sweep_binary (const sweep_binary &sb) { - if (unsat) - return; - if (!proof) - return; - vector bin; - bin.push_back (sb.lit); - bin.push_back (sb.other); - proof->delete_clause (sb.id, false, bin); -} - -bool Internal::scheduled_variable (Sweeper &sweeper, int idx) { - return sweeper.prev[idx] != 0 || sweeper.first == idx; -} - -void Internal::schedule_inner (Sweeper &sweeper, int idx) { - CADICAL_assert (idx); - if (!active (idx)) - return; - const int next = sweeper.next[idx]; - if (next != 0) { - LOG ("rescheduling inner %d as last", idx); - const unsigned prev = sweeper.prev[idx]; - CADICAL_assert (sweeper.prev[next] == idx); - sweeper.prev[next] = prev; - if (prev == 0) { - CADICAL_assert (sweeper.first == idx); - sweeper.first = next; - } else { - CADICAL_assert (sweeper.next[prev] == idx); - sweeper.next[prev] = next; - } - const unsigned last = sweeper.last; - if (last == 0) { - CADICAL_assert (sweeper.first == 0); - sweeper.first = idx; - } else { - CADICAL_assert (sweeper.next[last] == 0); - sweeper.next[last] = idx; - } - sweeper.prev[idx] = last; - sweeper.next[idx] = 0; - sweeper.last = idx; - } else if (sweeper.last != idx) { - LOG ("scheduling inner %d as last", idx); - const unsigned last = sweeper.last; - if (last == 0) { - CADICAL_assert (sweeper.first == 0); - sweeper.first = idx; - } else { - CADICAL_assert (sweeper.next[last] == 0); - sweeper.next[last] = idx; - } - CADICAL_assert (sweeper.next[idx] == 0); - sweeper.prev[idx] = last; - sweeper.last = idx; - } else - LOG ("keeping inner %d scheduled as last", idx); -} - -void Internal::schedule_outer (Sweeper &sweeper, int idx) { - CADICAL_assert (!scheduled_variable (sweeper, idx)); - CADICAL_assert (active (idx)); - const int first = sweeper.first; - if (first == 0) { - CADICAL_assert (sweeper.last == 0); - sweeper.last = idx; - } else { - CADICAL_assert (sweeper.prev[first] == 0); - sweeper.prev[first] = idx; - } - CADICAL_assert (sweeper.prev[idx] == 0); - sweeper.next[idx] = first; - sweeper.first = idx; - LOG ("scheduling outer %d as first", idx); -} - -int Internal::next_scheduled (Sweeper &sweeper) { - int res = sweeper.last; - if (res == 0) { - LOG ("no more scheduled variables left"); - return 0; - } - CADICAL_assert (res > 0); - LOG ("dequeuing next scheduled %d", res); - const unsigned prev = sweeper.prev[res]; - CADICAL_assert (sweeper.next[res] == 0); - sweeper.prev[res] = 0; - if (prev == 0) { - CADICAL_assert (sweeper.first == res); - sweeper.first = 0; - } else { - CADICAL_assert (sweeper.next[prev] == res); - sweeper.next[prev] = 0; - } - sweeper.last = prev; - return res; -} - -void Internal::sweep_substitute_lrat (Clause *c, int64_t id) { - if (!lrat) - return; - for (const auto &lit : *c) { - CADICAL_assert (val (lit) <= 0); - if (val (lit) < 0) { - int64_t id = unit_id (-lit); - lrat_chain.push_back (id); - } - } - lrat_chain.push_back (id); - lrat_chain.push_back (c->id); -} - -#define all_scheduled(IDX) \ - int IDX = sweeper.first, NEXT_##IDX; \ - IDX != 0 && (NEXT_##IDX = sweeper.next[IDX], true); \ - IDX = NEXT_##IDX - -// Substitute equivalences in clauses (see -// 'sweep_substitute_new_equivalences' for explanation) -void Internal::substitute_connected_clauses (Sweeper &sweeper, int lit, - int repr, int64_t id) { - if (unsat) - return; - if (val (lit)) - return; - if (val (repr)) - return; - LOG ("substituting %d with %d in all irredundant clauses", lit, repr); - - CADICAL_assert (lit != repr); - CADICAL_assert (lit != -repr); - - CADICAL_assert (active (lit)); - CADICAL_assert (active (repr)); - - uint64_t &ticks = sweeper.current_ticks; - - { - ticks += 1 + cache_lines (occs (lit).size (), sizeof (Clause *)); - Occs &ns = occs (lit); - auto const begin = ns.begin (); - const auto end = ns.end (); - auto q = begin; - auto p = q; - while (p != end) { - Clause *c = *q++ = *p++; - ticks++; - if (c->garbage) - continue; - CADICAL_assert (clause.empty ()); - bool satisfied = false; - bool repr_already_watched = false; - const int not_repr = -repr; -#ifndef CADICAL_NDEBUG - bool found = false; -#endif - for (const auto &other : *c) { - if (other == lit) { -#ifndef CADICAL_NDEBUG - CADICAL_assert (!found); - found = true; -#endif - clause.push_back (repr); - continue; - } - CADICAL_assert (other != -lit); - if (other == repr) { - CADICAL_assert (!repr_already_watched); - repr_already_watched = true; - continue; - } - if (other == not_repr) { - satisfied = true; - break; - } - const signed char tmp = val (other); - if (tmp < 0) - continue; - if (tmp > 0) { - satisfied = true; - break; - } - clause.push_back (other); - } - if (satisfied) { - clause.clear (); - mark_garbage (c); - sweep_update_noccs (c); - continue; - } - CADICAL_assert (found); - const unsigned new_size = clause.size (); - sweep_substitute_lrat (c, id); - if (new_size == 0) { - LOG (c, "substituted empty clause"); - CADICAL_assert (!unsat); - learn_empty_clause (); - break; - } - ticks++; - if (new_size == 1) { - LOG (c, "reduces to unit"); - const int unit = clause[0]; - clause.clear (); - assign_unit (unit); - sweeper.propagate.push_back (unit); - mark_garbage (c); - sweep_update_noccs (c); - stats.sweep_units++; - break; - } - CADICAL_assert (c->size >= 2); - if (!c->redundant) - mark_removed (c); - uint64_t new_id = ++clause_id; - if (proof) { - proof->add_derived_clause (new_id, c->redundant, clause, - lrat_chain); - proof->delete_clause (c); - } - c->id = new_id; - lrat_chain.clear (); - size_t l; - int *literals = c->literals; - for (l = 0; l < clause.size (); l++) - literals[l] = clause[l]; - int flushed = c->size - (int) l; - if (flushed) { - LOG ("flushed %d literals", flushed); - (void) shrink_clause (c, l); - } else if (likely_to_be_kept_clause (c)) - mark_added (c); - LOG (c, "substituted"); - if (!repr_already_watched) { - occs (repr).push_back (c); - noccs (repr)++; - } - clause.clear (); - q--; - } - while (p != end) - *q++ = *p++; - ns.resize (q - ns.begin ()); - } -} - -// In contrast to kissat we substitute the equivalences explicitely after -// every successful round of sweeping. This is necessary in order to extract -// valid LRAT proofs for subsequent rounds of sweeping. -void Internal::sweep_substitute_new_equivalences (Sweeper &sweeper) { - if (unsat) - return; - - unsigned count = 0; - CADICAL_assert (lrat_chain.empty ()); - - for (const auto &sb : sweeper.binaries) { - count++; - const auto lit = sb.lit; - const auto other = sb.other; - if (abs (lit) < abs (other)) { - substitute_connected_clauses (sweeper, -other, lit, sb.id); - } else { - substitute_connected_clauses (sweeper, -lit, other, sb.id); - } - CADICAL_assert (lrat_chain.empty ()); - if (val (lit) < 0) { - if (lrat) { - const int64_t lid = unit_id (-lit); - lrat_chain.push_back (lid); - } - if (!val (other)) { - if (lrat) - lrat_chain.push_back (sb.id); - assign_unit (other); - } else if (val (other) < 0) { - if (lrat) { - const int64_t oid = unit_id (-other); - lrat_chain.push_back (oid); - lrat_chain.push_back (sb.id); - } - learn_empty_clause (); - return; - } - } else if (val (other) < 0) { - if (!val (lit)) { - if (lrat) { - const int64_t oid = unit_id (-other); - lrat_chain.push_back (oid); - lrat_chain.push_back (sb.id); - } - assign_unit (lit); - } else - CADICAL_assert (val (lit) > 0); - } - lrat_chain.clear (); - delete_sweep_binary (sb); - if (count == 2) { - if (!val (lit) && !val (other)) { - const auto idx = abs (lit) < abs (other) ? abs (other) : abs (lit); - if (!flags (idx).fixed ()) - mark_substituted (idx); - } - count = 0; - } - CADICAL_assert (lrat_chain.empty ()); - } - sweeper.binaries.clear (); -} - -void Internal::sweep_remove (Sweeper &sweeper, int lit) { - CADICAL_assert (sweeper.reprs[lit] != lit); - vector &partition = sweeper.partition; - const auto begin_partition = partition.begin (); - auto p = begin_partition; - const auto end_partition = partition.end (); - for (; *p != lit; p++) - CADICAL_assert (p + 1 != end_partition); - auto begin_class = p; - while (begin_class != begin_partition && begin_class[-1] != 0) - begin_class--; - auto end_class = p; - while (*end_class != 0) - end_class++; - const unsigned size = end_class - begin_class; - LOG ("removing non-representative %d from equivalence class of size %u", - lit, size); - CADICAL_assert (size > 1); - auto q = begin_class; - if (size == 2) { - LOG ("completely squashing equivalence class of %d", lit); - for (auto r = end_class + 1; r != end_partition; r++) - *q++ = *r; - } else { - for (auto r = begin_class; r != end_partition; r++) - if (r != p) - *q++ = *r; - } - partition.resize (q - partition.begin ()); -} - -void Internal::flip_partition_literals (Sweeper &sweeper) { - const unsigned max_rounds = opts.sweepfliprounds; - if (!max_rounds) - return; - CADICAL_assert (sweeper.partition.size ()); - if (cadical_kitten_status (citten) != 10) - return; -#ifdef LOGGING - unsigned total_flipped = 0; -#endif - unsigned flipped, round = 0; - do { - round++; - flipped = 0; - bool refine = false; - bool limit_hit = false; - auto begin = sweeper.partition.begin (), dst = begin, src = dst; - const auto end = sweeper.partition.end (); - while (src != end) { - auto end_src = src; - while (CADICAL_assert (end_src != end), *end_src != 0) - end_src++; - unsigned size = end_src - src; - CADICAL_assert (size > 1); - auto q = dst; - for (auto p = src; p != end_src; p++) { - const int lit = *p; - if (limit_hit) { - *q++ = lit; - continue; - } else if (cadical_kitten_ticks_limit_hit (sweeper, "partition flipping")) { - *q++ = lit; - limit_hit = true; - continue; - } else if (sweep_flip (lit)) { - LOG ("flipping equivalence candidate %d succeeded", lit); -#ifdef LOGGING - total_flipped++; -#endif - flipped++; - if (--size < 2) - break; - } else { - LOG ("flipping equivalence candidate %d failed", lit); - *q++ = lit; - } - stats.sweep_flip_equivalences++; - } - if (size > 1) { - *q++ = 0; - dst = q; - } - src = end_src + 1; - } - stats.sweep_flipped_equivalences += flipped; - sweeper.partition.resize (dst - sweeper.partition.begin ()); - LOG ("flipped %u equivalence candidates in round %u", flipped, round); - if (terminated_asynchronously ()) - break; - if (cadical_kitten_ticks_limit_hit (sweeper, "partition flipping")) - break; - if (refine) - sweep_refine (sweeper); - } while (flipped && round < max_rounds); - LOG ("flipped %u equivalence candidates in total in %u rounds", - total_flipped, round); -} - -bool Internal::sweep_equivalence_candidates (Sweeper &sweeper, int lit, - int other) { - LOG ("trying equivalence candidates %d = %d", lit, other); - const auto begin = sweeper.partition.begin (); - auto const end = sweeper.partition.end (); - CADICAL_assert (begin + 3 <= end); - CADICAL_assert (end[-3] == lit); - CADICAL_assert (end[-2] == other); - const int third = (end - begin == 3) ? 0 : end[-4]; - int res = cadical_kitten_status (citten); - if (res == 10) { - stats.sweep_flip_equivalences++; - if (sweep_flip (lit)) { - stats.sweep_flipped_equivalences++; - LOG ("flipping %d succeeded", lit); - if (third == 0) { - LOG ("squashing equivalence class of %d", lit); - sweeper.partition.resize (sweeper.partition.size () - 3); - } else { - LOG ("removing %d from equivalence class of %d", lit, other); - end[-3] = other; - end[-2] = 0; - sweeper.partition.resize (sweeper.partition.size () - 1); - } - return false; - } - stats.sweep_flip_equivalences++; - if (sweep_flip (other)) { - stats.sweep_flipped_equivalences++; - LOG ("flipping %d succeeded", other); - if (third == 0) { - LOG ("squashing equivalence class of %d", lit); - sweeper.partition.resize (sweeper.partition.size () - 3); - } else { - LOG ("removing %d from equivalence class of %d", other, lit); - end[-2] = 0; - sweeper.partition.resize (sweeper.partition.size () - 1); - } - return false; - } - } - // frozen variables are not allowed to be eliminated. - // It might still be beneficial to learn the binaries, if they - // really are equivalent, but we avoid the issue by not trying - // for equivalence at all if the non-representative is frozen. - // i.e., the higher absolute value - if (abs (lit) > abs (other) && frozen (lit)) { - if (third == 0) { - LOG ("squashing equivalence class of %d", lit); - sweeper.partition.resize (sweeper.partition.size () - 3); - } else { - LOG ("removing %d from equivalence class of %d", lit, other); - end[-3] = other; - end[-2] = 0; - sweeper.partition.resize (sweeper.partition.size () - 1); - } - return false; - } else if (abs (other) > abs (lit) && frozen (other)) { - if (third == 0) { - LOG ("squashing equivalence class of %d", lit); - sweeper.partition.resize (sweeper.partition.size () - 3); - } else { - LOG ("removing %d from equivalence class of %d", lit, other); - end[-2] = 0; - sweeper.partition.resize (sweeper.partition.size () - 1); - } - return false; - } - - const int not_other = -other; - const int not_lit = -lit; - LOG ("flipping %d and %d both failed", lit, other); - cadical_kitten_assume_signed (citten, not_lit); - cadical_kitten_assume_signed (citten, other); - stats.sweep_solved_equivalences++; - res = sweep_solve (); - if (res == 10) { - stats.sweep_sat_equivalences++; - LOG ("first sweeping implication %d -> %d failed", other, lit); - sweep_refine (sweeper); - } else if (!res) { - stats.sweep_unknown_equivalences++; - LOG ("first sweeping implication %d -> %d hit ticks limit", other, lit); - } - - if (res != 20) - return false; - - stats.sweep_unsat_equivalences++; - LOG ("first sweeping implication %d -> %d succeeded", other, lit); - - save_core (sweeper, 0); - - cadical_kitten_assume_signed (citten, lit); - cadical_kitten_assume_signed (citten, not_other); - res = sweep_solve (); - stats.sweep_solved_equivalences++; - if (res == 10) { - stats.sweep_sat_equivalences++; - LOG ("second sweeping implication %d <- %d failed", other, lit); - sweep_refine (sweeper); - } else if (!res) { - stats.sweep_unknown_equivalences++; - LOG ("second sweeping implication %d <- %d hit ticks limit", other, - lit); - } - - if (res != 20) { - sweeper.core[0].clear (); - return false; - } - - CADICAL_assert (res == 20); - - stats.sweep_unsat_equivalences++; - LOG ("second sweeping implication %d <- %d succeeded too", other, lit); - - save_core (sweeper, 1); - - LOG ("sweep equivalence %d = %d", lit, other); - - // If cadical_kitten behaves as expected, the two binaries of the equivalence - // should be stored at sweeper.core[i].back () for i in {0, 1}. - // We pick the smaller absolute valued literal as representative and - // store the equivalence . - add_core (sweeper, 0); - add_core (sweeper, 1); - if (!val (lit) && !val (other)) { - CADICAL_assert (sweeper.core[0].size ()); - CADICAL_assert (sweeper.core[1].size ()); - stats.sweep_equivalences++; - sweep_binary bin1; - sweep_binary bin2; - if (abs (lit) > abs (other)) { - bin1.lit = lit; - bin1.other = not_other; - bin2.lit = not_lit; - bin2.other = other; - bin1.id = add_sweep_binary (sweeper.core[0].back (), lit, not_other); - bin2.id = add_sweep_binary (sweeper.core[1].back (), not_lit, other); - } else { - bin1.lit = not_other; - bin1.other = lit; - bin2.lit = other; - bin2.other = not_lit; - bin1.id = add_sweep_binary (sweeper.core[0].back (), not_other, lit); - bin2.id = add_sweep_binary (sweeper.core[1].back (), other, not_lit); - } - if (bin1.id && bin2.id) { - sweeper.binaries.push_back (bin1); - sweeper.binaries.push_back (bin2); - } - } - - int repr; - if (abs (lit) < abs (other)) { - repr = sweeper.reprs[other] = lit; - sweeper.reprs[not_other] = not_lit; - sweep_remove (sweeper, other); - } else { - repr = sweeper.reprs[lit] = other; - sweeper.reprs[not_lit] = not_other; - sweep_remove (sweeper, lit); - } - clear_core (sweeper, 0); - clear_core (sweeper, 1); - - const int repr_idx = abs (repr); - schedule_inner (sweeper, repr_idx); - - return true; -} - -const char *Internal::sweep_variable (Sweeper &sweeper, int idx) { - CADICAL_assert (!unsat); - if (!active (idx)) - return "inactive variable"; - const int start = idx; - if (sweeper.reprs[start] != start) - return "non-representative variable"; - CADICAL_assert (sweeper.vars.empty ()); - CADICAL_assert (sweeper.clauses.empty ()); - CADICAL_assert (sweeper.backbone.empty ()); - CADICAL_assert (sweeper.partition.empty ()); - CADICAL_assert (!sweeper.encoded); - - stats.sweep_variables++; - - LOG ("sweeping %d", idx); - CADICAL_assert (!val (start)); - LOG ("starting sweeping[0]"); - add_literal_to_environment (sweeper, 0, start); - LOG ("finished sweeping[0]"); - LOG ("starting sweeping[1]"); - - bool limit_reached = false; - size_t expand = 0, next = 1; - bool success = false; - unsigned depth = 1; - - uint64_t &ticks = sweeper.current_ticks; - while (!limit_reached) { - if (sweeper.encoded >= sweeper.limit.clauses) { - LOG ("environment clause limit reached"); - limit_reached = true; - break; - } - if (expand == next) { - LOG ("finished sweeping[%u]", depth); - if (depth >= sweeper.limit.depth) { - LOG ("environment depth limit reached"); - break; - } - next = sweeper.vars.size (); - if (expand == next) { - LOG ("completely copied all clauses"); - break; - } - depth++; - LOG ("starting sweeping[%u]", depth); - } - const unsigned choices = next - expand; - if (opts.sweeprand && choices > 1) { - const unsigned swaps = sweeper.random.pick_int (0, choices - 1); - if (swaps) { - CADICAL_assert (expand + swaps < sweeper.vars.size ()); - swap (sweeper.vars[expand], sweeper.vars[expand + swaps]); - } - } - const int idx = sweeper.vars[expand]; - LOG ("traversing and adding clauses of %d", idx); - for (unsigned sign = 0; sign < 2; sign++) { - const int lit = sign ? -idx : idx; - ticks += 1 + cache_lines (occs (lit).size (), sizeof (Clause *)); - Occs &ns = occs (lit); - for (auto c : ns) { - ticks++; - if (!can_sweep_clause (c)) - continue; - sweep_clause (sweeper, depth, c); - if (sweeper.vars.size () >= sweeper.limit.vars) { - LOG ("environment variable limit reached"); - limit_reached = true; - break; - } - } - if (limit_reached) - break; - } - expand++; - } - stats.sweep_depth += depth; - stats.sweep_clauses += sweeper.encoded; - stats.sweep_environment += sweeper.vars.size (); - VERBOSE (3, - "sweeping variable %d environment of " - "%zu variables %u clauses depth %u", - externalize (idx), sweeper.vars.size (), sweeper.encoded, depth); - - int res; - if (sweeper.vars.size () == 1) { - LOG ("not sweeping literal %d with environment size 1", idx); - goto DONE; - } - res = sweep_solve (); - LOG ("sub-solver returns '%d'", res); - if (res == 10) { - init_backbone_and_partition (sweeper); -#ifndef CADICAL_QUIET - uint64_t units = stats.sweep_units; - uint64_t solved = stats.sweep_solved; -#endif - START (sweepbackbone); - while (sweeper.backbone.size ()) { - if (unsat || terminated_asynchronously () || - cadical_kitten_ticks_limit_hit (sweeper, "backbone refinement")) { - limit_reached = true; - STOP_SWEEP_BACKBONE: - STOP (sweepbackbone); - goto DONE; - } - flip_backbone_literals (sweeper); - if (terminated_asynchronously () || - cadical_kitten_ticks_limit_hit (sweeper, "backbone refinement")) { - limit_reached = true; - goto STOP_SWEEP_BACKBONE; - } - if (sweeper.backbone.empty ()) - break; - const int lit = sweeper.backbone.back (); - sweeper.backbone.pop_back (); - if (!active (lit)) - continue; - if (sweep_backbone_candidate (sweeper, lit)) - success = true; - } - STOP (sweepbackbone); -#ifndef CADICAL_QUIET - units = stats.sweep_units - units; - solved = stats.sweep_solved - solved; -#endif - VERBOSE (3, - "complete swept variable %d backbone with %" PRIu64 - " units in %" PRIu64 " solver calls", - externalize (idx), units, solved); - CADICAL_assert (sweeper.backbone.empty ()); -#ifndef CADICAL_QUIET - uint64_t equivalences = stats.sweep_equivalences; - solved = stats.sweep_solved; -#endif - START (sweepequivalences); - while (sweeper.partition.size ()) { - if (unsat || terminated_asynchronously () || - cadical_kitten_ticks_limit_hit (sweeper, "partition refinement")) { - limit_reached = true; - STOP_SWEEP_EQUIVALENCES: - STOP (sweepequivalences); - goto DONE; - } - flip_partition_literals (sweeper); - if (terminated_asynchronously () || - cadical_kitten_ticks_limit_hit (sweeper, "backbone refinement")) { - limit_reached = true; - goto STOP_SWEEP_EQUIVALENCES; - } - if (sweeper.partition.empty ()) - break; - if (sweeper.partition.size () > 2) { - const auto end = sweeper.partition.end (); - CADICAL_assert (end[-1] == 0); - int lit = end[-3]; - int other = end[-2]; - if (sweep_equivalence_candidates (sweeper, lit, other)) - success = true; - } else - sweeper.partition.clear (); - } - STOP (sweepequivalences); -#ifndef CADICAL_QUIET - equivalences = stats.sweep_equivalences - equivalences; - solved = stats.sweep_solved - solved; - if (equivalences) - VERBOSE (3, - "complete swept variable %d partition with %" PRIu64 - " equivalences in %" PRIu64 " solver calls", - externalize (idx), equivalences, solved); -#endif - } else if (res == 20) - sweep_empty_clause (sweeper); - -DONE: - clear_sweeper (sweeper); - - if (!unsat) - sweep_substitute_new_equivalences (sweeper); - if (!unsat) - sweep_dense_propagate (sweeper); - - if (success && limit_reached) - return "successfully despite reaching limit"; - if (!success && !limit_reached) - return "unsuccessfully without reaching limit"; - else if (success && !limit_reached) - return "successfully without reaching limit"; - CADICAL_assert (!success && limit_reached); - return "unsuccessfully and reached limit"; -} - -struct sweep_candidate { - unsigned rank; - int idx; -}; - -struct rank_sweep_candidate { - bool operator() (sweep_candidate a, sweep_candidate b) const { - CADICAL_assert (a.rank && b.rank); - CADICAL_assert (a.idx > 0 && b.idx > 0); - if (a.rank < b.rank) - return true; - if (b.rank < a.rank) - return false; - return a.idx < b.idx; - } -}; - -bool Internal::scheduable_variable (Sweeper &sweeper, int idx, - size_t *occ_ptr) { - const int lit = idx; - const size_t pos = noccs (lit); - if (!pos) - return false; - const unsigned max_occurrences = sweeper.limit.clauses; - if (pos > max_occurrences) - return false; - const int not_lit = -lit; - const size_t neg = noccs (not_lit); - if (!neg) - return false; - if (neg > max_occurrences) - return false; - *occ_ptr = pos + neg; - return true; -} - -unsigned Internal::schedule_all_other_not_scheduled_yet (Sweeper &sweeper) { - vector fresh; - for (const auto &idx : vars) { - Flags &f = flags (idx); - if (!f.active ()) - continue; - if (sweep_incomplete && !f.sweep) - continue; - if (scheduled_variable (sweeper, idx)) - continue; - size_t occ; - if (!scheduable_variable (sweeper, idx, &occ)) { - f.sweep = false; - continue; - } - sweep_candidate cand; - cand.rank = occ; - cand.idx = idx; - fresh.push_back (cand); - } - const size_t size = fresh.size (); - CADICAL_assert (size <= UINT_MAX); - sort (fresh.begin (), fresh.end (), rank_sweep_candidate ()); - for (auto &cand : fresh) - schedule_outer (sweeper, cand.idx); - return size; -} - -unsigned Internal::reschedule_previously_remaining (Sweeper &sweeper) { - unsigned rescheduled = 0; - for (const auto &idx : sweep_schedule) { - Flags &f = flags (idx); - if (!f.active ()) - continue; - if (scheduled_variable (sweeper, idx)) - continue; - size_t occ; - if (!scheduable_variable (sweeper, idx, &occ)) { - f.sweep = false; - continue; - } - schedule_inner (sweeper, idx); - rescheduled++; - } - sweep_schedule.clear (); - return rescheduled; -} - -unsigned Internal::incomplete_variables () { - unsigned res = 0; - for (const auto &idx : vars) { - Flags &f = flags (idx); - if (!f.active ()) - continue; - if (f.sweep) - res++; - } - return res; -} - -void Internal::mark_incomplete (Sweeper &sweeper) { - unsigned marked = 0; - for (all_scheduled (idx)) { - if (!flags (idx).sweep) { - flags (idx).sweep = true; - marked++; - } - } - sweep_incomplete = true; -#ifndef CADICAL_QUIET - VERBOSE (2, "marked %u scheduled sweeping variables as incomplete", - marked); -#else - (void) marked; -#endif -} - -unsigned Internal::schedule_sweeping (Sweeper &sweeper) { - const unsigned rescheduled = reschedule_previously_remaining (sweeper); - const unsigned fresh = schedule_all_other_not_scheduled_yet (sweeper); - const unsigned scheduled = fresh + rescheduled; - const unsigned incomplete = incomplete_variables (); -#ifndef CADICAL_QUIET - PHASE ("sweep", stats.sweep, - "scheduled %u variables %.0f%% " - "(%u rescheduled %.0f%%, %u incomplete %.0f%%)", - scheduled, percent (scheduled, active ()), rescheduled, - percent (rescheduled, scheduled), incomplete, - percent (incomplete, scheduled)); -#endif - if (incomplete) - CADICAL_assert (sweep_incomplete); - else { - if (sweep_incomplete) - stats.sweep_completed++; - mark_incomplete (sweeper); - } - return scheduled; -} - -void Internal::unschedule_sweeping (Sweeper &sweeper, unsigned swept, - unsigned scheduled) { -#ifdef CADICAL_QUIET - (void) scheduled, (void) swept; -#endif - CADICAL_assert (sweep_schedule.empty ()); - CADICAL_assert (sweep_incomplete); - for (all_scheduled (idx)) - if (active (idx)) { - sweep_schedule.push_back (idx); - LOG ("untried scheduled %d", idx); - } -#ifndef CADICAL_QUIET - const unsigned retained = sweep_schedule.size (); -#endif - VERBOSE (3, "retained %u variables %.0f%% to be swept next time", - retained, percent (retained, active ())); - const unsigned incomplete = incomplete_variables (); - if (incomplete) - VERBOSE (3, "need to sweep %u more variables %.0f%% for completion", - incomplete, percent (incomplete, active ())); - else { - VERBOSE (3, "no more variables needed to complete sweep"); - sweep_incomplete = false; - stats.sweep_completed++; - } - PHASE ("sweep", stats.sweep, "swept %u variables (%u remain %.0f%%)", - swept, incomplete, percent (incomplete, scheduled)); -} - -bool Internal::sweep () { - if (!opts.sweep) - return false; - if (unsat) - return false; - if (terminated_asynchronously ()) - return false; - if (delaying_sweep.bumpreasons.delay ()) { // TODO need to fix Delay - last.sweep.ticks = stats.ticks.search[0] + stats.ticks.search[1]; - return false; - } - delaying_sweep.bumpreasons.bypass_delay (); - SET_EFFORT_LIMIT (tickslimit, sweep, !opts.sweepcomplete); - delaying_sweep.bumpreasons.unbypass_delay (); - - CADICAL_assert (!level); - START_SIMPLIFIER (sweep, SWEEP); - stats.sweep++; - uint64_t equivalences = stats.sweep_equivalences; - uint64_t units = stats.sweep_units; - Sweeper sweeper = Sweeper (this); - if (opts.sweepcomplete) - sweeper.limit.ticks = INT64_MAX; - else - sweeper.limit.ticks = tickslimit - stats.ticks.sweep; - sweep_set_cadical_kitten_ticks_limit (sweeper); - const unsigned scheduled = schedule_sweeping (sweeper); - uint64_t swept = 0, limit = 10; - for (;;) { - if (unsat) - break; - if (terminated_asynchronously ()) - break; - if (cadical_kitten_ticks_limit_hit (sweeper, "sweeping loop")) - break; - int idx = next_scheduled (sweeper); - if (idx == 0) - break; - flags (idx).sweep = false; -#ifndef CADICAL_QUIET - const char *res = -#endif - sweep_variable (sweeper, idx); - VERBOSE (2, "swept[%" PRIu64 "] external variable %d %s", swept, - externalize (idx), res); - if (++swept == limit) { - VERBOSE (2, - "found %" PRIu64 " equivalences and %" PRIu64 - " units after sweeping %" PRIu64 " variables ", - stats.sweep_equivalences - equivalences, - stats.sweep_units - units, swept); - limit *= 10; - } - } - VERBOSE (2, "swept %" PRIu64 " variables", swept); - equivalences = stats.sweep_equivalences - equivalences, - units = stats.sweep_units - units; - PHASE ("sweep", stats.sweep, - "found %" PRIu64 " equivalences and %" PRIu64 " units", - equivalences, units); - unschedule_sweeping (sweeper, swept, scheduled); - release_sweeper (sweeper); - - if (!unsat) { - propagated = 0; - if (!propagate ()) { - learn_empty_clause (); - } - } - - uint64_t eliminated = equivalences + units; - report ('=', !eliminated); - - if (relative (eliminated, swept) < 0.001) { - delaying_sweep.bumpreasons.bump_delay (); - } else { - delaying_sweep.bumpreasons.reduce_delay (); - } - STOP_SIMPLIFIER (sweep, SWEEP); - return eliminated; -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_terminal.cpp b/src/sat/cadical/cadical_terminal.cpp deleted file mode 100644 index c8aeea2ab..000000000 --- a/src/sat/cadical/cadical_terminal.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -#ifdef WIN32 -#include -#define isatty _isatty -#endif - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -Terminal::Terminal (FILE *f) : file (f), reset_on_exit (false) { - CADICAL_assert (file); - int fd = fileno (f); - CADICAL_assert (fd == 1 || fd == 2); - use_colors = connected = isatty (fd); -} - -void Terminal::force_colors () { use_colors = connected = true; } -void Terminal::force_no_colors () { use_colors = false; } -void Terminal::force_reset_on_exit () { reset_on_exit = true; } - -void Terminal::reset () { - if (!connected) - return; - erase_until_end_of_line (); - cursor (true); - normal (); - fflush (file); -} - -void Terminal::disable () { - reset (); - connected = use_colors = false; -} - -Terminal::~Terminal () { - if (reset_on_exit) - reset (); -} - -Terminal tout (stdout); -Terminal terr (stderr); - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_ternary.cpp b/src/sat/cadical/cadical_ternary.cpp deleted file mode 100644 index 9f99e2279..000000000 --- a/src/sat/cadical/cadical_ternary.cpp +++ /dev/null @@ -1,456 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -/*------------------------------------------------------------------------*/ - -// This procedure can be used to produce all possible hyper ternary -// resolvents from ternary clauses. In contrast to hyper binary resolution -// we would only try to produce ternary clauses from ternary clauses, i.e., -// do not consider quaternary clauses as antecedents. Of course if a binary -// clause is generated we keep it too. In any case we have to make sure -// though that we do not add clauses which are already in the formula or are -// subsumed by a binary clause in the formula. This procedure simulates -// structural hashing for multiplexer (if-then-else) and binary XOR gates in -// combination with equivalent literal substitution ('decompose') if run -// until to completion (which in the current implementation is too costly -// though and would need to be interleaved more eagerly with equivalent -// literal substitution). For more information see our CPAIOR'13 paper. - -/*------------------------------------------------------------------------*/ - -// Check whether a binary clause consisting of the permutation of the given -// literals already exists. - -bool Internal::ternary_find_binary_clause (int a, int b) { - CADICAL_assert (occurring ()); - CADICAL_assert (active (a)); - CADICAL_assert (active (b)); - size_t s = occs (a).size (); - size_t t = occs (b).size (); - int lit = s < t ? a : b; - if (opts.ternaryocclim < (int) occs (lit).size ()) - return true; - for (const auto &c : occs (lit)) { - if (c->size != 2) - continue; - const int *lits = c->literals; - if (lits[0] == a && lits[1] == b) - return true; - if (lits[0] == b && lits[1] == a) - return true; - } - return false; -} - -/*------------------------------------------------------------------------*/ - -// Check whether a ternary clause consisting of the permutation of the given -// literals already exists or is subsumed by an existing binary clause. - -bool Internal::ternary_find_ternary_clause (int a, int b, int c) { - CADICAL_assert (occurring ()); - CADICAL_assert (active (a)); - CADICAL_assert (active (b)); - CADICAL_assert (active (c)); - size_t r = occs (a).size (); - size_t s = occs (b).size (); - size_t t = occs (c).size (); - int lit; - if (r < s) - lit = (t < r) ? c : a; - else - lit = (t < s) ? c : b; - if (opts.ternaryocclim < (int) occs (lit).size ()) - return true; - for (const auto &d : occs (lit)) { - const int *lits = d->literals; - if (d->size == 2) { - if (lits[0] == a && lits[1] == b) - return true; - if (lits[0] == b && lits[1] == a) - return true; - if (lits[0] == a && lits[1] == c) - return true; - if (lits[0] == c && lits[1] == a) - return true; - if (lits[0] == b && lits[1] == c) - return true; - if (lits[0] == c && lits[1] == b) - return true; - } else { - CADICAL_assert (d->size == 3); - if (lits[0] == a && lits[1] == b && lits[2] == c) - return true; - if (lits[0] == a && lits[1] == c && lits[2] == b) - return true; - if (lits[0] == b && lits[1] == a && lits[2] == c) - return true; - if (lits[0] == b && lits[1] == c && lits[2] == a) - return true; - if (lits[0] == c && lits[1] == a && lits[2] == b) - return true; - if (lits[0] == c && lits[1] == b && lits[2] == a) - return true; - } - } - return false; -} - -/*------------------------------------------------------------------------*/ - -// Try to resolve the two ternary clauses on the given pivot (assumed to -// occur positively in the first clause, negatively in the second). If the -// resolvent has four literals, is tautological, already exists or in the -// case of a ternary resolvent is subsumed by an existing binary clause then -// 'false' is returned. The global 'clause' contains the resolvent and -// needs to be cleared in any case. - -bool Internal::hyper_ternary_resolve (Clause *c, int pivot, Clause *d) { - LOG ("hyper binary resolving on pivot %d", pivot); - LOG (c, "1st antecedent"); - LOG (d, "2nd antecedent"); - stats.ternres++; - CADICAL_assert (c->size == 3); - CADICAL_assert (d->size == 3); - CADICAL_assert (clause.empty ()); - for (const auto &lit : *c) - if (lit != pivot) - clause.push_back (lit); - for (const auto &lit : *d) { - if (lit == -pivot) - continue; - if (lit == clause[0]) - continue; - if (lit == -clause[0]) - return false; - if (lit == clause[1]) - continue; - if (lit == -clause[1]) - return false; - clause.push_back (lit); - } - size_t size = clause.size (); - if (size > 3) - return false; - if (size == 2 && ternary_find_binary_clause (clause[0], clause[1])) - return false; - if (size == 3 && - ternary_find_ternary_clause (clause[0], clause[1], clause[2])) - return false; - return true; -} - -/*------------------------------------------------------------------------*/ - -// Produce all ternary resolvents on literal 'pivot' and increment the -// 'steps' counter by the number of clauses containing 'pivot' which are -// used during this process. The reason for choosing this metric to measure -// the effort spent in 'ternary' is that it should be similar to one -// propagation step during search. - -void Internal::ternary_lit (int pivot, int64_t &steps, int64_t &htrs) { - LOG ("starting hyper ternary resolutions on pivot %d", pivot); - steps -= 1 + cache_lines (occs (pivot).size (), sizeof (Clause *)); - for (const auto &c : occs (pivot)) { - if (steps < 0) - break; - if (htrs < 0) - break; - if (c->garbage) - continue; - if (c->size != 3) { - CADICAL_assert (c->size == 2); - continue; - } - if (--steps < 0) - break; - bool assigned = false; - for (const auto &lit : *c) - if (val (lit)) { - assigned = true; - break; - } - if (assigned) - continue; - steps -= 1 + cache_lines (occs (-pivot).size (), sizeof (Clause *)); - for (const auto &d : occs (-pivot)) { - if (htrs < 0) - break; - if (--steps < 0) - break; - if (d->garbage) - continue; - if (d->size != 3) { - CADICAL_assert (d->size == 2); - continue; - } - for (const auto &lit : *d) - if (val (lit)) { - assigned = true; - break; - } - if (assigned) - continue; - CADICAL_assert (clause.empty ()); - htrs--; - if (hyper_ternary_resolve (c, pivot, d)) { - size_t size = clause.size (); - bool red = (size == 3 || (c->redundant && d->redundant)); - if (lrat) { - CADICAL_assert (lrat_chain.empty ()); - lrat_chain.push_back (c->id); - lrat_chain.push_back (d->id); - } - Clause *r = new_hyper_ternary_resolved_clause (red); - if (red) - r->hyper = true; - lrat_chain.clear (); - clause.clear (); - LOG (r, "hyper ternary resolved"); - stats.htrs++; - for (const auto &lit : *r) - occs (lit).push_back (r); - if (size == 2) { - LOG ("hyper ternary resolvent subsumes both antecedents"); - mark_garbage (c); - mark_garbage (d); - stats.htrs2++; - break; - } else { - CADICAL_assert (r->size == 3); - stats.htrs3++; - } - } else { - LOG (clause, "ignoring size %zd resolvent", clause.size ()); - clause.clear (); - } - } - } -} - -/*------------------------------------------------------------------------*/ - -// Same as 'ternary_lit' but pick the phase of the variable based on the -// number of positive and negative occurrence. - -void Internal::ternary_idx (int idx, int64_t &steps, int64_t &htrs) { - CADICAL_assert (0 < idx); - CADICAL_assert (idx <= max_var); - steps -= 3; - if (!active (idx)) - return; - if (!flags (idx).ternary) - return; - int pos = occs (idx).size (); - int neg = occs (-idx).size (); - if (pos <= opts.ternaryocclim && neg <= opts.ternaryocclim) { - LOG ("index %d has %zd positive and %zd negative occurrences", idx, - occs (idx).size (), occs (-idx).size ()); - int pivot = (neg < pos ? -idx : idx); - ternary_lit (pivot, steps, htrs); - } - flags (idx).ternary = false; -} - -/*------------------------------------------------------------------------*/ - -// One round of ternary resolution over all variables. As in 'block' and -// 'elim' we maintain a persistent global flag 'ternary' for each variable, -// which records, whether a ternary clause containing it was added. Then we -// can focus on those variables for which we have not tried ternary -// resolution before and nothing changed for them since then. This works -// across multiple calls to 'ternary' as well as 'ternary_round' since this -// 'ternary' variable flag is updated during adding (ternary) resolvents. -// This function goes over each variable just once. - -bool Internal::ternary_round (int64_t &steps_limit, int64_t &htrs_limit) { - - CADICAL_assert (!unsat); - -#ifndef CADICAL_QUIET - int64_t bincon = 0; - int64_t terncon = 0; -#endif - - init_occs (); - - steps_limit -= 1 + cache_lines (clauses.size (), sizeof (Clause *)); - for (const auto &c : clauses) { - steps_limit--; - if (c->garbage) - continue; - if (c->size > 3) - continue; - bool assigned = false, marked = false; - for (const auto &lit : *c) { - if (val (lit)) { - assigned = true; - break; - } - if (flags (lit).ternary) - marked = true; - } - if (assigned) - continue; - if (c->size == 2) { -#ifndef CADICAL_QUIET - bincon++; -#endif - } else { - CADICAL_assert (c->size == 3); - if (!marked) - continue; -#ifndef CADICAL_QUIET - terncon++; -#endif - } - - for (const auto &lit : *c) - occs (lit).push_back (c); - } - - PHASE ("ternary", stats.ternary, - "connected %" PRId64 " ternary %.0f%% " - "and %" PRId64 " binary clauses %.0f%%", - terncon, percent (terncon, clauses.size ()), bincon, - percent (bincon, clauses.size ())); - - // Try ternary resolution on all variables once. - // - for (auto idx : vars) { - if (terminated_asynchronously ()) - break; - if (steps_limit < 0) - break; - if (htrs_limit < 0) - break; - ternary_idx (idx, steps_limit, htrs_limit); - } - - // Gather some statistics for the verbose messages below and also - // determine whether new variables have been marked and it would make - // sense to run another round of ternary resolution over those variables. - // - int remain = 0; - for (auto idx : vars) { - if (!active (idx)) - continue; - if (!flags (idx).ternary) - continue; - remain++; - } - if (remain) - PHASE ("ternary", stats.ternary, "%d variables remain %.0f%%", remain, - percent (remain, max_var)); - else - PHASE ("ternary", stats.ternary, "completed hyper ternary resolution"); - - reset_occs (); - CADICAL_assert (!unsat); - - return remain; // Are there variables that should be tried again? -} - -/*------------------------------------------------------------------------*/ - -bool Internal::ternary () { - - if (!opts.ternary) - return false; - if (unsat) - return false; - if (terminated_asynchronously ()) - return false; - - // No new ternary clauses added since last time? - // - if (last.ternary.marked == stats.mark.ternary) - return false; - - SET_EFFORT_LIMIT (limit, ternary, true); - - START_SIMPLIFIER (ternary, TERNARY); - stats.ternary++; - - CADICAL_assert (!level); - - CADICAL_assert (!unsat); - if (watching ()) - reset_watches (); - - // The number of clauses derived through ternary resolution can grow - // substantially, particularly for random formulas. Thus we limit the - // number of added clauses too (actually the number of 'htrs'). - // - int64_t htrs_limit = stats.current.redundant + stats.current.irredundant; - htrs_limit *= opts.ternarymaxadd; - htrs_limit /= 100; - - // approximation of ternary ticks. - // TODO: count with ternary.ticks directly. - int64_t steps_limit = stats.ticks.ternary - limit; - stats.ticks.ternary = limit; - - // With 'stats.ternary' we actually count the number of calls to - // 'ternary_round' and not the number of calls to 'ternary'. But before - // the first round we want to show the limit on the number of steps and - // thus we increase counter for the first round here and skip increasing - // it in the loop below. - // - PHASE ("ternary", stats.ternary, - "will run a maximum of %d rounds " - "limited to %" PRId64 " steps and %" PRId64 " clauses", - opts.ternaryrounds, steps_limit, htrs_limit); - - bool resolved_binary_clause = false; - bool completed = false; - - for (int round = 0; - !terminated_asynchronously () && round < opts.ternaryrounds; - round++) { - if (htrs_limit < 0) - break; - if (steps_limit < 0) - break; - if (round) - stats.ternary++; - int old_htrs2 = stats.htrs2; - int old_htrs3 = stats.htrs3; - completed = ternary_round (steps_limit, htrs_limit); - int delta_htrs2 = stats.htrs2 - old_htrs2; - int delta_htrs3 = stats.htrs3 - old_htrs3; - PHASE ("ternary", stats.ternary, - "derived %d ternary and %d binary resolvents", delta_htrs3, - delta_htrs2); - report ('3', !opts.reportall && !(delta_htrs2 + delta_htrs2)); - if (delta_htrs2) - resolved_binary_clause = true; - if (!delta_htrs3) - break; - } - - CADICAL_assert (!occurring ()); - CADICAL_assert (!unsat); - init_watches (); - connect_watches (); - if (!propagate ()) { - LOG ("propagation after connecting watches results in inconsistency"); - learn_empty_clause (); - } - - if (completed) - last.ternary.marked = stats.mark.ternary; - - STOP_SIMPLIFIER (ternary, TERNARY); - - return resolved_binary_clause; -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_tier.cpp b/src/sat/cadical/cadical_tier.cpp deleted file mode 100644 index 92faf507f..000000000 --- a/src/sat/cadical/cadical_tier.cpp +++ /dev/null @@ -1,59 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -void Internal::recompute_tier () { - if (!opts.recomputetier) - return; - - ++stats.tierecomputed; - const int64_t delta = - stats.tierecomputed >= 16 ? 1u << 16 : (1u << stats.tierecomputed); - lim.recompute_tier = stats.conflicts + delta; - LOG ("rescheduling in %zd at %zd (conflicts at %zd)", delta, - lim.recompute_tier, stats.conflicts); -#ifndef CADICAL_NDEBUG - uint64_t total_used = 0; - for (auto u : stats.used[stable]) - total_used += u; - CADICAL_assert (total_used == stats.bump_used[stable]); -#endif - - if (!stats.bump_used[stable]) { - tier1[stable] = opts.reducetier1glue; - tier2[stable] = opts.reducetier2glue; - LOG ("tier1 limit = %d", tier1[stable]); - LOG ("tier2 limit = %d", tier2[stable]); - return; - } else { - uint64_t accumulated_tier1_limit = - stats.bump_used[stable] * opts.tier1limit / 100; - uint64_t accumulated_tier2_limit = - stats.bump_used[stable] * opts.tier2limit / 100; - uint64_t accumulated_used = 0; - for (size_t glue = 0; glue < stats.used[stable].size (); ++glue) { - const uint64_t u = stats.used[stable][glue]; - accumulated_used += u; - if (accumulated_used <= accumulated_tier1_limit) { - tier1[stable] = glue; - } - if (accumulated_used >= accumulated_tier2_limit) { - tier2[stable] = glue; - break; - } - } - } - - LOG ("tier1 limit = %d in %s mode", tier1[stable], - stable ? "stable" : "focused"); - LOG ("tier2 limit = %d in %s mode", tier2[stable], - stable ? "stable" : "focused"); -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_transred.cpp b/src/sat/cadical/cadical_transred.cpp deleted file mode 100644 index 82a961dee..000000000 --- a/src/sat/cadical/cadical_transred.cpp +++ /dev/null @@ -1,259 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -// Implement transitive reduction in the binary implication graph. This is -// important for hyper binary resolution, which has the risk to produce too -// many hyper binary resolvents otherwise. This algorithm only works on -// binary clauses and is usually pretty fast. It will also find some failed -// literals (in the binary implication graph). - -void Internal::transred () { - if (!opts.transred) - return; - if (unsat) - return; - if (terminated_asynchronously ()) - return; - if (!stats.current.redundant && !stats.current.irredundant) - return; - - CADICAL_assert (opts.transred); - CADICAL_assert (!level); - - START_SIMPLIFIER (transred, TRANSRED); - stats.transreds++; - - // Transitive reduction can not be run to completion for larger formulas - // with many binary clauses. We bound it in the same way as 'probe_core'. - // - int64_t limit = stats.propagations.search; - limit -= last.transred.propagations; - limit *= 1e-3 * opts.transredeffort; - if (limit < opts.transredmineff) - limit = opts.transredmineff; - if (limit > opts.transredmaxeff) - limit = opts.transredmaxeff; - - PHASE ("transred", stats.transreds, - "transitive reduction limit of %" PRId64 " propagations", limit); - - const auto end = clauses.end (); - auto i = clauses.begin (); - - // Find first clause not checked for being transitive yet. - // - for (; i != end; i++) { - Clause *c = *i; - if (c->garbage) - continue; - if (c->size != 2) - continue; - if (c->redundant && c->hyper) - continue; - if (!c->transred) - break; - } - - // If all candidate clauses have been checked reschedule all. - // - if (i == end) { - - PHASE ("transred", stats.transreds, - "rescheduling all clauses since no clauses to check left"); - for (i = clauses.begin (); i != end; i++) { - Clause *c = *i; - if (c->transred) - c->transred = false; - } - i = clauses.begin (); - } - - // Move watches of binary clauses to the front. Thus we can stop iterating - // watches as soon a long clause is found during watch traversal. - // - sort_watches (); - - // This working stack plays the same role as the 'trail' during standard - // propagation. - // - vector work; - - int64_t propagations = 0, units = 0, removed = 0; - - while (!unsat && i != end && !terminated_asynchronously () && - propagations < limit) { - Clause *c = *i++; - - // A clause is a candidate for being transitive if it is binary, and not - // the result of hyper binary resolution. The reason for excluding - // those, is that they come in large numbers, most of them are reduced - // away anyhow and further are non-transitive at the point they are - // added (see the code in 'hyper_binary_resolve' in 'prope.cpp' and - // also check out our CPAIOR paper on tree-based look ahead). - // - if (c->garbage) - continue; - if (c->size != 2) - continue; - if (c->redundant && c->hyper) - continue; - if (c->transred) - continue; // checked before? - c->transred = true; // marked as checked - - LOG (c, "checking transitive reduction of"); - - // Find a different path from 'src' to 'dst' in the binary implication - // graph, not using 'c'. Since this is the same as checking whether - // there is a path from '-dst' to '-src', we can do the reverse search - // if the number of watches of '-dst' is larger than those of 'src'. - // - int src = -c->literals[0]; - int dst = c->literals[1]; - if (val (src) || val (dst)) - continue; - if (watches (-src).size () < watches (dst).size ()) { - int tmp = dst; - dst = -src; - src = -tmp; - } - - LOG ("searching path from %d to %d", src, dst); - - // If the candidate clause is irredundant then we can not use redundant - // binary clauses in the implication graph. See our inprocessing rules - // paper, why this restriction is required. - // - const bool irredundant = !c->redundant; - - CADICAL_assert (work.empty ()); - mark (src); - work.push_back (src); - LOG ("transred assign %d", src); - - bool transitive = false; // found path from 'src' to 'dst'? - bool failed = false; // 'src' failed literal? - - size_t j = 0; // 'propagated' in BFS - - CADICAL_assert (lrat_chain.empty ()); - CADICAL_assert (mini_chain.empty ()); - vector parents; - - while (!transitive && !failed && j < work.size ()) { - const int lit = work[j++]; - CADICAL_assert (marked (lit) > 0); - LOG ("transred propagating %d", lit); - propagations++; - const Watches &ws = watches (-lit); - const const_watch_iterator eow = ws.end (); - const_watch_iterator k; - for (k = ws.begin (); !transitive && !failed && k != eow; k++) { - const Watch &w = *k; - if (!w.binary ()) - break; // since we sorted watches above - Clause *d = w.clause; - if (d == c) - continue; - if (irredundant && d->redundant) - continue; - if (d->garbage) - continue; - const int other = w.blit; - if (other == dst) - transitive = true; // 'dst' reached - else { - const int tmp = marked (other); - if (tmp > 0) - continue; - else if (tmp < 0) { - if (lrat) { - parents.push_back (lit); - mini_chain.push_back (d->id); - work.push_back (other); - } - LOG ("found both %d and %d reachable", -other, other); - failed = true; - } else { - if (lrat) { - parents.push_back (lit); - mini_chain.push_back (d->id); - } - mark (other); - work.push_back (other); - LOG ("transred assign %d", other); - } - } - } - } - - int failed_lit = work.back (); - int next_pos = 0; - int next_neg = 0; - - // Unassign all assigned literals (same as '[bp]acktrack'). - // - while (!work.empty ()) { - const int lit = work.back (); - work.pop_back (); - if (lrat && failed && !work.empty ()) { - CADICAL_assert (!parents.empty () && !mini_chain.empty ()); - LOG ("transred LRAT current lit %d next pos %d next neg %d", lit, - next_pos, next_neg); - if (lit == failed_lit || lit == next_pos) { - lrat_chain.push_back (mini_chain.back ()); - next_pos = parents.back (); - } else if (lit == -failed_lit || lit == next_neg) { - lrat_chain.push_back (mini_chain.back ()); - next_neg = parents.back (); - } - parents.pop_back (); - mini_chain.pop_back (); - } - unmark (lit); - } - mini_chain.clear (); - CADICAL_assert (mini_chain.empty ()); - if (lrat && failed) { - reverse (lrat_chain.begin (), lrat_chain.end ()); - } - - if (transitive) { - removed++; - stats.transitive++; - LOG (c, "transitive redundant"); - mark_garbage (c); - } else if (failed) { - units++; - LOG ("found failed literal %d during transitive reduction", src); - stats.failed++; - stats.transredunits++; - assign_unit (-src); - if (!propagate ()) { - VERBOSE (1, "propagating new unit results in conflict"); - learn_empty_clause (); - } - } - lrat_chain.clear (); - } - - last.transred.propagations = stats.propagations.search; - stats.propagations.transred += propagations; - erase_vector (work); - - PHASE ("transred", stats.transreds, - "removed %" PRId64 " transitive clauses, found %" PRId64 " units", - removed, units); - - STOP_SIMPLIFIER (transred, TRANSRED); - report ('t', !opts.reportall && !(removed + units)); -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_unstable.cpp b/src/sat/cadical/cadical_unstable.cpp deleted file mode 100644 index c3162d70a..000000000 --- a/src/sat/cadical/cadical_unstable.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include "global.h" - -#ifdef PROFILE_MODE -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -bool Internal::propagate_unstable () { - CADICAL_assert (!stable); - START (propunstable); - bool res = propagate (); - STOP (propunstable); - return res; -} - -void Internal::analyze_unstable () { - CADICAL_assert (!stable); - START (analyzeunstable); - analyze (); - STOP (analyzeunstable); -} - -int Internal::decide_unstable () { - CADICAL_assert (!stable); - return decide (); -} - -}; // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END - -#else -ABC_NAMESPACE_IMPL_START -int unstable_if_no_profile_mode; -ABC_NAMESPACE_IMPL_END -#endif diff --git a/src/sat/cadical/cadical_util.cpp b/src/sat/cadical/cadical_util.cpp deleted file mode 100644 index fd9b5b29d..000000000 --- a/src/sat/cadical/cadical_util.cpp +++ /dev/null @@ -1,135 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -/*------------------------------------------------------------------------*/ - -bool parse_int_str (const char *val_str, int &val) { - if (!strcmp (val_str, "true")) - val = 1; - else if (!strcmp (val_str, "false")) - val = 0; - else { - const char *p = val_str; - int sign; - - if (*p == '-') - sign = -1, p++; - else - sign = 1; - - int ch; - if (!isdigit ((ch = *p++))) - return false; - - const int64_t bound = -(int64_t) INT_MIN; - int64_t mantissa = ch - '0'; - - while (isdigit (ch = *p++)) { - if (bound / 10 < mantissa) - mantissa = bound; - else - mantissa *= 10; - const int digit = ch - '0'; - if (bound - digit < mantissa) - mantissa = bound; - else - mantissa += digit; - } - - int exponent = 0; - if (ch == 'e') { - while (isdigit ((ch = *p++))) - exponent = exponent ? 10 : ch - '0'; - if (ch) - return false; - } else if (ch) - return false; - - CADICAL_assert (exponent <= 10); - int64_t val64 = mantissa; - for (int i = 0; i < exponent; i++) - val64 *= 10; - - if (sign < 0) { - val64 = -val64; - if (val64 < INT_MIN) - val64 = INT_MIN; - } else { - if (val64 > INT_MAX) - val64 = INT_MAX; - } - - CADICAL_assert (INT_MIN <= val64); - CADICAL_assert (val64 <= INT_MAX); - - val = val64; - } - return true; -} - -/*------------------------------------------------------------------------*/ - -bool has_suffix (const char *str, const char *suffix) { - size_t k = strlen (str), l = strlen (suffix); - return k > l && !strcmp (str + k - l, suffix); -} - -bool has_prefix (const char *str, const char *prefix) { - for (const char *p = str, *q = prefix; *q; q++, p++) - if (*q != *p) - return false; - return true; -} - -/*------------------------------------------------------------------------*/ - -bool is_color_option (const char *arg) { - return !strcmp (arg, "--color") || !strcmp (arg, "--colors") || - !strcmp (arg, "--colour") || !strcmp (arg, "--colours") || - !strcmp (arg, "--color=1") || !strcmp (arg, "--colors=1") || - !strcmp (arg, "--colour=1") || !strcmp (arg, "--colours=1") || - !strcmp (arg, "--color=true") || !strcmp (arg, "--colors=true") || - !strcmp (arg, "--colour=true") || !strcmp (arg, "--colours=true"); -} - -bool is_no_color_option (const char *arg) { - return !strcmp (arg, "--no-color") || !strcmp (arg, "--no-colors") || - !strcmp (arg, "--no-colour") || !strcmp (arg, "--no-colours") || - !strcmp (arg, "--color=0") || !strcmp (arg, "--colors=0") || - !strcmp (arg, "--colour=0") || !strcmp (arg, "--colours=0") || - !strcmp (arg, "--color=false") || - !strcmp (arg, "--colors=false") || - !strcmp (arg, "--colour=false") || - !strcmp (arg, "--colours=false"); -} - -/*------------------------------------------------------------------------*/ - -static uint64_t primes[] = { - 1111111111111111111lu, 2222222222222222249lu, 3333333333333333347lu, - 4444444444444444537lu, 5555555555555555621lu, 6666666666666666677lu, - 7777777777777777793lu, 8888888888888888923lu, 9999999999999999961lu, -}; - -uint64_t hash_string (const char *str) { - const unsigned size = sizeof primes / sizeof *primes; - uint64_t res = 0; - unsigned char ch; - unsigned i = 0; - for (const char *p = str; (ch = *p); p++) { - res += ch; - res *= primes[i++]; - if (i == size) - i = 0; - } - return res; -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_var.cpp b/src/sat/cadical/cadical_var.cpp deleted file mode 100644 index e2348da7b..000000000 --- a/src/sat/cadical/cadical_var.cpp +++ /dev/null @@ -1,45 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -void Internal::reset_subsume_bits () { - LOG ("marking all variables as not subsume"); - for (auto idx : vars) - flags (idx).subsume = false; -} - -void Internal::check_var_stats () { -#ifndef CADICAL_NDEBUG - int64_t fixed = 0, eliminated = 0, substituted = 0, pure = 0, unused = 0; - for (auto idx : vars) { - Flags &f = flags (idx); - if (f.active ()) - continue; - if (f.fixed ()) - fixed++; - if (f.eliminated ()) - eliminated++; - if (f.substituted ()) - substituted++; - if (f.unused ()) - unused++; - if (f.pure ()) - pure++; - } - CADICAL_assert (stats.now.fixed == fixed); - CADICAL_assert (stats.now.eliminated == eliminated); - CADICAL_assert (stats.now.substituted == substituted); - CADICAL_assert (stats.now.pure == pure); - int64_t inactive = unused + fixed + eliminated + substituted + pure; - CADICAL_assert (stats.inactive == inactive); - CADICAL_assert (max_var == stats.active + stats.inactive); -#endif -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_veripbtracer.cpp b/src/sat/cadical/cadical_veripbtracer.cpp deleted file mode 100644 index b1f7c95a7..000000000 --- a/src/sat/cadical/cadical_veripbtracer.cpp +++ /dev/null @@ -1,400 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -/*------------------------------------------------------------------------*/ - -VeripbTracer::VeripbTracer (Internal *i, File *f, bool b, bool a, bool c) - : internal (i), file (f), with_antecedents (a), checked_deletions (c), - num_clauses (0), size_clauses (0), clauses (0), last_hash (0), - last_id (0), last_clause (0) -#ifndef CADICAL_QUIET - , - added (0), deleted (0) -#endif -{ - (void) internal; - - // Initialize random number table for hash function. - // - Random random (42); - for (unsigned n = 0; n < num_nonces; n++) { - uint64_t nonce = random.next (); - if (!(nonce & 1)) - nonce++; - CADICAL_assert (nonce), CADICAL_assert (nonce & 1); - nonces[n] = nonce; - } -#ifndef CADICAL_NDEBUG - binary = b; -#else - (void) b; -#endif -} - -void VeripbTracer::connect_internal (Internal *i) { - internal = i; - file->connect_internal (internal); - LOG ("VERIPB TRACER connected to internal"); -} - -VeripbTracer::~VeripbTracer () { - LOG ("VERIPB TRACER delete"); - delete file; - for (size_t i = 0; i < size_clauses; i++) - for (HashId *c = clauses[i], *next; c; c = next) - next = c->next, delete_clause (c); - delete[] clauses; -} - -/*------------------------------------------------------------------------*/ - -void VeripbTracer::enlarge_clauses () { - CADICAL_assert (num_clauses == size_clauses); - const uint64_t new_size_clauses = size_clauses ? 2 * size_clauses : 1; - LOG ("VeriPB Tracer enlarging clauses from %" PRIu64 " to %" PRIu64, - (uint64_t) size_clauses, (uint64_t) new_size_clauses); - HashId **new_clauses; - new_clauses = new HashId *[new_size_clauses]; - clear_n (new_clauses, new_size_clauses); - for (uint64_t i = 0; i < size_clauses; i++) { - for (HashId *c = clauses[i], *next; c; c = next) { - next = c->next; - const uint64_t h = reduce_hash (c->hash, new_size_clauses); - c->next = new_clauses[h]; - new_clauses[h] = c; - } - } - delete[] clauses; - clauses = new_clauses; - size_clauses = new_size_clauses; -} - -HashId *VeripbTracer::new_clause () { - HashId *res = new HashId (); - res->next = 0; - res->hash = last_hash; - res->id = last_id; - last_clause = res; - num_clauses++; - return res; -} - -void VeripbTracer::delete_clause (HashId *c) { - CADICAL_assert (c); - num_clauses--; - delete c; -} - -uint64_t VeripbTracer::reduce_hash (uint64_t hash, uint64_t size) { - CADICAL_assert (size > 0); - unsigned shift = 32; - uint64_t res = hash; - while ((((uint64_t) 1) << shift) > size) { - res ^= res >> shift; - shift >>= 1; - } - res &= size - 1; - CADICAL_assert (res < size); - return res; -} - -uint64_t VeripbTracer::compute_hash (const int64_t id) { - CADICAL_assert (id > 0); - unsigned j = id % num_nonces; // Dont know if this is a good - uint64_t tmp = nonces[j] * (uint64_t) id; // hash funktion or even better - return last_hash = tmp; // than just using id. -} - -bool VeripbTracer::find_and_delete (const int64_t id) { - if (!num_clauses) - return false; - /* - if (last_clause && last_clause->id == id) { - const uint64_t h = reduce_hash (last_clause->hash, size_clauses); - clauses[h] = last_clause->next; - delete last_clause; - return true; - } - */ - HashId **res = 0, *c; - const uint64_t hash = compute_hash (id); - const uint64_t h = reduce_hash (hash, size_clauses); - for (res = clauses + h; (c = *res); res = &c->next) { - if (c->hash == hash && c->id == id) { - break; - } - if (!c->next) - return false; - } - if (!c) - return false; - CADICAL_assert (c && res); - *res = c->next; - delete_clause (c); - return true; -} - -void VeripbTracer::insert () { - if (num_clauses == size_clauses) - enlarge_clauses (); - const uint64_t h = reduce_hash (compute_hash (last_id), size_clauses); - HashId *c = new_clause (); - c->next = clauses[h]; - clauses[h] = c; -} - -/*------------------------------------------------------------------------*/ - -inline void VeripbTracer::put_binary_zero () { - CADICAL_assert (binary); - CADICAL_assert (file); - file->put ((unsigned char) 0); -} - -inline void VeripbTracer::put_binary_lit (int lit) { - CADICAL_assert (binary); - CADICAL_assert (file); - CADICAL_assert (lit != INT_MIN); - unsigned x = 2 * abs (lit) + (lit < 0); - unsigned char ch; - while (x & ~0x7f) { - ch = (x & 0x7f) | 0x80; - file->put (ch); - x >>= 7; - } - ch = x; - file->put (ch); -} - -inline void VeripbTracer::put_binary_id (int64_t id, bool can_be_negative) { - CADICAL_assert (binary); - CADICAL_assert (file); - uint64_t x = abs (id); - if (can_be_negative) { - x = 2 * x + (id < 0); - } - unsigned char ch; - while (x & ~0x7f) { - ch = (x & 0x7f) | 0x80; - file->put (ch); - x >>= 7; - } - ch = x; - file->put (ch); -} - -/*------------------------------------------------------------------------*/ - -void VeripbTracer::veripb_add_derived_clause ( - int64_t id, bool redundant, const vector &clause, - const vector &chain) { - file->put ("pol "); - bool first = true; - for (auto p = chain.rbegin (); p != chain.rend (); p++) { - auto cid = *p; - if (first) { - first = false; - file->put (cid); - } else { - file->put (' '); - file->put (cid); - file->put (" + s"); - } - } - file->put ("\n"); - file->put ("e "); - for (const auto &external_lit : clause) { - file->put ("1 "); - if (external_lit < 0) - file->put ('~'); - file->put ('x'); - file->put (abs (external_lit)); - file->put (' '); - } - file->put (">= 1 ; "); - file->put (id); - file->put (" ;\n"); - if (!redundant && checked_deletions) { - file->put ("core id "); - file->put (id); - file->put ("\n"); - } -} - -void VeripbTracer::veripb_add_derived_clause (int64_t id, bool redundant, - const vector &clause) { - file->put ("rup "); - for (const auto &external_lit : clause) { - file->put ("1 "); - if (external_lit < 0) - file->put ('~'); - file->put ('x'); - file->put (abs (external_lit)); - file->put (' '); - } - file->put (">= 1 ;\n"); - if (!redundant && checked_deletions) { - file->put ("core id "); - file->put (id); - file->put ("\n"); - } -} - -void VeripbTracer::veripb_begin_proof (int64_t reserved_ids) { - file->put ("pseudo-Boolean proof version 2.0\n"); - file->put ("f "); - file->put (reserved_ids); - file->put ("\n"); -} - -void VeripbTracer::veripb_delete_clause (int64_t id, bool redundant) { - if (!redundant && checked_deletions && find_and_delete (id)) - return; - if (redundant || !checked_deletions) - file->put ("del id "); - else { - file->put ("delc "); - } - file->put (id); - file->put ("\n"); -} - -void VeripbTracer::veripb_report_status (bool unsat, int64_t conflict_id) { - file->put ("output NONE\n"); - if (unsat) { - file->put ("conclusion UNSAT : "); - file->put (conflict_id); - file->put (" \n"); - } else - file->put ("conclusion NONE\n"); - file->put ("end pseudo-Boolean proof\n"); -} - -void VeripbTracer::veripb_strengthen (int64_t id) { - if (!checked_deletions) - return; - file->put ("core id "); - file->put (id); - file->put ("\n"); -} - -/*------------------------------------------------------------------------*/ - -void VeripbTracer::begin_proof (int64_t id) { - if (file->closed ()) - return; - LOG ("VERIPB TRACER tracing start of proof with %" PRId64 - "original clauses", - id); - veripb_begin_proof (id); -} - -void VeripbTracer::add_derived_clause (int64_t id, bool redundant, - const vector &clause, - const vector &chain) { - if (file->closed ()) - return; - LOG ("VERIPB TRACER tracing addition of derived clause[%" PRId64 "]", id); - if (with_antecedents) - veripb_add_derived_clause (id, redundant, clause, chain); - else - veripb_add_derived_clause (id, redundant, clause); -#ifndef CADICAL_QUIET - added++; -#endif -} - -void VeripbTracer::delete_clause (int64_t id, bool redundant, - const vector &) { - if (file->closed ()) - return; - LOG ("VERIPB TRACER tracing deletion of clause[%" PRId64 "]", id); - veripb_delete_clause (id, redundant); -#ifndef CADICAL_QUIET - deleted++; -#endif -} - -void VeripbTracer::report_status (int status, int64_t conflict_id) { - if (file->closed ()) - return; -#ifdef LOGGING - if (conflict_id) - LOG ("VERIPB TRACER tracing finalization of proof with empty " - "clause[%" PRId64 "]", - conflict_id); -#endif - veripb_report_status (status == UNSATISFIABLE, conflict_id); -} - -void VeripbTracer::weaken_minus (int64_t id, const vector &) { - if (!checked_deletions) - return; - if (file->closed ()) - return; - LOG ("VERIPB TRACER tracing weaken minus of clause[%" PRId64 "]", id); - last_id = id; - insert (); -} - -void VeripbTracer::strengthen (int64_t id) { - if (file->closed ()) - return; - LOG ("VERIPB TRACER tracing strengthen of clause[%" PRId64 "]", id); - veripb_strengthen (id); -} - -/*------------------------------------------------------------------------*/ - -bool VeripbTracer::closed () { return file->closed (); } - -#ifndef CADICAL_QUIET - -void VeripbTracer::print_statistics () { - // TODO complete - uint64_t bytes = file->bytes (); - uint64_t total = added + deleted; - MSG ("VeriPB %" PRId64 " added clauses %.2f%%", added, - percent (added, total)); - MSG ("VeriPB %" PRId64 " deleted clauses %.2f%%", deleted, - percent (deleted, total)); - MSG ("VeriPB %" PRId64 " bytes (%.2f MB)", bytes, - bytes / (double) (1 << 20)); -} - -#endif - -void VeripbTracer::close (bool print) { - CADICAL_assert (!closed ()); - file->close (); -#ifndef CADICAL_QUIET - if (print) { - MSG ("VeriPB proof file '%s' closed", file->name ()); - print_statistics (); - } -#else - (void) print; -#endif -} - -void VeripbTracer::flush (bool print) { - CADICAL_assert (!closed ()); - file->flush (); -#ifndef CADICAL_QUIET - if (print) { - MSG ("VeriPB proof file '%s' flushed", file->name ()); - print_statistics (); - } -#else - (void) print; -#endif -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_version.cpp b/src/sat/cadical/cadical_version.cpp deleted file mode 100644 index a0cceef63..000000000 --- a/src/sat/cadical/cadical_version.cpp +++ /dev/null @@ -1,113 +0,0 @@ -#include "global.h" - -/*------------------------------------------------------------------------*/ - -// To simplify the build process without 'make', you can disable the -// generation of 'build.hpp' through '../scripts/make-build-header.sh' by -// defining '-DCADICAL_NBUILD'. Then we try to guess part of the configuration. - -#ifndef CADICAL_NBUILD -#if __GNUC__ > 4 -#if __has_include() -#include "build.hpp" -#endif // __has_include -#else -#include "build.hpp" -#endif // __GNUC > 4 -#endif // CADICAL_NBUILD - -/*------------------------------------------------------------------------*/ - -// We prefer short 3 character version numbers made of digits and lower case -// letters only, which gives 36^3 = 46656 different versions. The following -// macro is used for the non-standard build process and only set from -// the file '../VERSION' with '../scripts/update-version.sh'. The standard -// build process relies on 'VERSION' to be defined in 'build.hpp'. - -#ifdef CADICAL_NBUILD -#ifndef VERSION -#define VERSION "2.2.0-rc1" -#endif // VERSION -#endif // CADICAL_NBUILD - - /*------------------------------------------------------------------------*/ - - // The copyright of the code is here. - - static const char *COPYRIGHT = "Copyright (c) 2016-2024"; -static const char *AUTHORS = - "A. Biere, M. Fleury, N. Froleyks, K. Fazekas, F. Pollitt, T. Faller"; -static const char *AFFILIATIONS = - "JKU Linz, University of Freiburg, TU Wien"; - -/*------------------------------------------------------------------------*/ - -// Again if we do not have 'CADICAL_NBUILD' or if something during configuration is -// broken we still want to be able to compile the solver. In this case we -// then try our best to figure out 'COMPILER' and 'DATE', but for -// 'IDENTIFIER' and 'FLAGS' we can only use the '0' string, which marks -// those as unknown. - -#ifndef COMPILER -#ifdef __clang__ -#ifdef __VERSION__ -#define COMPILER "clang++-" __VERSION__ -#else -#define COMPILER "clang++" -#endif -#elif defined(__GNUC__) -#ifdef __VERSION__ -#define COMPILER "g++-" __VERSION__ -#else -#define COMPILER "g++" -#endif -#else -#define COMPILER 0 -#endif -#endif - -// GIT SHA2 identifier. -// -#ifndef IDENTIFIER -#define IDENTIFIER 0 -#endif -#ifdef SHORTID -#define SHORTIDSTR "-" SHORTID -#else -#define SHORTIDSTR "" -#define SHORTID 0 -#endif - -// Compilation flags. -// -#ifndef FLAGS -#define FLAGS 0 -#endif - -// Build Time and operating system. -// -#ifndef DATE -#define DATE __DATE__ " " __TIME__ -#endif - -/*------------------------------------------------------------------------*/ - -#include "version.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -const char *version () { return VERSION; } -const char *copyright () { return COPYRIGHT; } -const char *authors () { return AUTHORS; } -const char *affiliations () { return AFFILIATIONS; } -const char *signature () { return "cadical-" VERSION SHORTIDSTR; } -const char *identifier () { return IDENTIFIER; } -const char *compiler () { return COMPILER; } -const char *date () { return DATE; } -const char *flags () { return FLAGS; } - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_vivify.cpp b/src/sat/cadical/cadical_vivify.cpp deleted file mode 100644 index 8d99c2932..000000000 --- a/src/sat/cadical/cadical_vivify.cpp +++ /dev/null @@ -1,1962 +0,0 @@ -#include "global.h" - -#include "vivify.hpp" -#include "internal.hpp" -#include "util.hpp" -#include -#include -#include - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -/*------------------------------------------------------------------------*/ - -// Vivification is a special case of asymmetric tautology elimination (ATE) -// and asymmetric literal elimination (ALE). It strengthens and removes -// clauses proven redundant through unit propagation. -// -// The original algorithm is due to a paper by Piette, Hamadi and Sais -// published at ECAI'08. We have an inprocessing version, e.g., it does not -// necessarily run-to-completion. Our version also performs conflict -// analysis and uses a new heuristic for selecting clauses to vivify. - -// Our idea is to focus on clauses with many occurrences of its literals in -// other clauses first. This both complements nicely our implementation of -// subsume, which is bounded, e.g., subsumption attempts are skipped for -// very long clauses with literals with many occurrences and also is -// stronger in the sense that it enables to remove more clauses due to unit -// propagation (AT checks). - -// While first focusing on irredundant clause we then added a separate phase -// upfront which focuses on strengthening also redundant clauses in spirit -// of the ideas presented in the IJCAI'17 paper by M. Luo, C.-M. Li, F. -// Xiao, F. Manya, and Z. Lu. - -// There is another very similar approach called 'distilliation' published -// by Han and Somenzi in DAC'07, which reorganizes the CNF in a trie data -// structure to reuse decisions and propagations along the trie. We used -// that as an inspiration but instead of building a trie we simple sort -// clauses and literals in such a way that we get the same effect. If a new -// clause is 'distilled' or 'vivified' we first check how many of the -// decisions (which are only lazily undone) can be reused for that clause. -// Reusing can be improved by picking a global literal order and sorting the -// literals in all clauses with respect to that order. We favor literals -// with more occurrences first. Then we sort clauses lexicographically with -// respect to that literal order. - -/*------------------------------------------------------------------------*/ - -// Candidate clause 'subsumed' is subsumed by 'subsuming'. - -inline void Internal::vivify_subsume_clause (Clause *subsuming, - Clause *subsumed) { - stats.subsumed++; - stats.vivifysubs++; -#ifndef CADICAL_NDEBUG - CADICAL_assert (subsuming); - CADICAL_assert (subsumed); - CADICAL_assert (subsuming != subsumed); - CADICAL_assert (!subsumed->garbage); - // size after removeing units; - int real_size_subsuming = 0, real_size_subsumed = 0; - for (auto lit : *subsuming) { - if (!val (lit) || var (lit).level) - ++real_size_subsuming; - else - CADICAL_assert (val (lit) < 0); - } - for (auto lit : *subsumed) { - if (!val (lit) || var (lit).level) - ++real_size_subsumed; - else - CADICAL_assert (val (lit) < 0); - } - CADICAL_assert (real_size_subsuming <= real_size_subsumed); -#endif - LOG (subsumed, "subsumed"); - if (subsumed->redundant) { - stats.subred++; - ++stats.vivifysubred; - } else { - stats.subirr++; - ++stats.vivifysubirr; - } - if (subsuming->garbage) { - CADICAL_assert (subsuming->size == 2); - LOG (subsuming, - "binary subsuming clause was already deleted, so undeleting"); - subsuming->garbage = false; - subsuming->glue = 1; - ++stats.current.total; - if (subsuming->redundant) - stats.current.redundant++; - else - stats.current.irredundant++, stats.irrlits += subsuming->size; - } - if (subsumed->redundant || !subsuming->redundant) { - mark_garbage (subsumed); - return; - } - LOG ("turning redundant subsuming clause into irredundant clause"); - subsuming->redundant = false; - if (proof) - proof->strengthen (subsuming->id); - mark_garbage (subsumed); - mark_added (subsuming); - stats.current.irredundant++; - stats.added.irredundant++; - stats.irrlits += subsuming->size; - CADICAL_assert (stats.current.redundant > 0); - stats.current.redundant--; - CADICAL_assert (stats.added.redundant > 0); - stats.added.redundant--; - // ... and keep 'stats.added.total'. -} - -// demoting a clause (opposite is promote from subsume.cpp) - -inline void Internal::demote_clause (Clause *c) { - stats.subsumed++; - stats.vivifydemote++; - LOG (c, "demoting"); - CADICAL_assert (!c->redundant); - mark_removed (c); - c->redundant = true; - CADICAL_assert (stats.current.irredundant > 0); - stats.current.irredundant--; - CADICAL_assert (stats.added.irredundant > 0); - stats.added.irredundant--; - stats.irrlits -= c->size; - stats.current.redundant++; - stats.added.redundant++; - c->glue = c->size - 1; - // ... and keep 'stats.added.total'. -} - -/*------------------------------------------------------------------------*/ -// For vivification we have a separate dedicated propagation routine, which -// prefers to propagate binary clauses first. It also uses its own -// assignment procedure 'vivify_assign', which does not mess with phase -// saving during search nor the conflict and other statistics and further -// can be inlined separately here. The propagation routine needs to ignore -// (large) clauses which are currently vivified. - -inline void Internal::vivify_assign (int lit, Clause *reason) { - require_mode (VIVIFY); - const int idx = vidx (lit); - CADICAL_assert (!vals[idx]); - CADICAL_assert (!flags (idx).eliminated () || !reason); - Var &v = var (idx); - v.level = level; // required to reuse decisions - v.trail = (int) trail.size (); // used in 'vivify_better_watch' - CADICAL_assert ((int) num_assigned < max_var); - num_assigned++; - v.reason = level ? reason : 0; // for conflict analysis - if (!level) - learn_unit_clause (lit); - const signed char tmp = sign (lit); - vals[idx] = tmp; - vals[-idx] = -tmp; - CADICAL_assert (val (lit) > 0); - CADICAL_assert (val (-lit) < 0); - trail.push_back (lit); - LOG (reason, "vivify assign %d", lit); -} - -// Assume negated literals in candidate clause. - -void Internal::vivify_assume (int lit) { - require_mode (VIVIFY); - level++; - control.push_back (Level (lit, trail.size ())); - LOG ("vivify decide %d", lit); - CADICAL_assert (level > 0); - CADICAL_assert (propagated == trail.size ()); - vivify_assign (lit, 0); -} - -// Dedicated routine similar to 'propagate' in 'propagate.cpp' and -// 'probe_propagate' with 'probe_propagate2' in 'probe.cpp'. Please refer -// to that code for more explanation on how propagation is implemented. - -bool Internal::vivify_propagate (int64_t &ticks) { - require_mode (VIVIFY); - CADICAL_assert (!unsat); - START (propagate); - int64_t before = propagated2 = propagated; - for (;;) { - if (propagated2 != trail.size ()) { - const int lit = -trail[propagated2++]; - LOG ("vivify propagating %d over binary clauses", -lit); - Watches &ws = watches (lit); - ticks += - 1 + cache_lines (ws.size (), sizeof (const_watch_iterator *)); - for (const auto &w : ws) { - if (!w.binary ()) - continue; - const signed char b = val (w.blit); - if (b > 0) - continue; - if (b < 0) - conflict = w.clause; // but continue - else { - ticks++; - build_chain_for_units (w.blit, w.clause, 0); - vivify_assign (w.blit, w.clause); - lrat_chain.clear (); - } - } - } else if (!conflict && propagated != trail.size ()) { - const int lit = -trail[propagated++]; - LOG ("vivify propagating %d over large clauses", -lit); - Watches &ws = watches (lit); - const const_watch_iterator eow = ws.end (); - const_watch_iterator i = ws.begin (); - ticks += 1 + cache_lines (ws.size (), sizeof (*i)); - watch_iterator j = ws.begin (); - while (i != eow) { - const Watch w = *j++ = *i++; - if (w.binary ()) - continue; - if (val (w.blit) > 0) - continue; - ticks++; - if (w.clause->garbage) { - j--; - continue; - } - literal_iterator lits = w.clause->begin (); - const int other = lits[0] ^ lits[1] ^ lit; - const signed char u = val (other); - if (u > 0) - j[-1].blit = other; - else { - const int size = w.clause->size; - const const_literal_iterator end = lits + size; - const literal_iterator middle = lits + w.clause->pos; - literal_iterator k = middle; - signed char v = -1; - int r = 0; - while (k != end && (v = val (r = *k)) < 0) - k++; - if (v < 0) { - k = lits + 2; - CADICAL_assert (w.clause->pos <= size); - while (k != middle && (v = val (r = *k)) < 0) - k++; - } - w.clause->pos = k - lits; - CADICAL_assert (lits + 2 <= k), CADICAL_assert (k <= w.clause->end ()); - if (v > 0) - j[-1].blit = r; - else if (!v) { - LOG (w.clause, "unwatch %d in", r); - lits[0] = other; - lits[1] = r; - *k = lit; - ticks++; - watch_literal (r, lit, w.clause); - j--; - } else if (!u) { - if (w.clause == ignore) { - LOG ("ignoring propagation due to clause to vivify"); - continue; - } - ticks++; - CADICAL_assert (v < 0); - vivify_chain_for_units (other, w.clause); - vivify_assign (other, w.clause); - lrat_chain.clear (); - } else { - if (w.clause == ignore) { - LOG ("ignoring conflict due to clause to vivify"); - continue; - } - CADICAL_assert (u < 0); - CADICAL_assert (v < 0); - conflict = w.clause; - break; - } - } - } - if (j != i) { - while (i != eow) - *j++ = *i++; - ws.resize (j - ws.begin ()); - } - } else - break; - } - int64_t delta = propagated2 - before; - stats.propagations.vivify += delta; - if (conflict) - LOG (conflict, "conflict"); - STOP (propagate); - return !conflict; -} - -/*------------------------------------------------------------------------*/ - -// Check whether a literal occurs less often. In the implementation below -// (search for 'int64_t score = ...' or '@4') we actually compute a -// weighted occurrence count similar to the Jeroslow Wang heuristic. - -struct vivify_more_noccs { - - Internal *internal; - - vivify_more_noccs (Internal *i) : internal (i) {} - - bool operator() (int a, int b) { - int64_t n = internal->noccs (a); - int64_t m = internal->noccs (b); - if (n > m) - return true; // larger occurrences / score first - if (n < m) - return false; // smaller occurrences / score last - if (a == -b) - return a > 0; // positive literal first - return abs (a) < abs (b); // smaller index first - } -}; - -struct vivify_more_noccs_kissat { - - Internal *internal; - - vivify_more_noccs_kissat (Internal *i) : internal (i) {} - - bool operator() (int a, int b) { - unsigned t = internal->noccs (a); - unsigned s = internal->noccs (b); - return ((t - s) | ((b - a) & ~(s - t))) >> 31; - } -}; - -// Sort candidate clauses by the number of occurrences (actually by their -// score) of their literals, with clauses to be vivified first last. We -// assume that clauses are sorted w.r.t. more occurring (higher score) -// literals first (with respect to 'vivify_more_noccs'). -// -// For example if there are the following (long irredundant) clauses -// -// 1 -3 -4 (A) -// -1 -2 3 4 (B) -// 2 -3 4 (C) -// -// then we have the following literal scores using Jeroslow Wang scores and -// normalizing it with 2^12 (which is the same as 1<<12): -// -// nocc ( 1) = 2^12 * (2^-3 ) = 512 3. -// nocc (-1) = 2^12 * (2^-4 ) = 256 6. -// nocc ( 2) = 2^12 * (2^-3 ) = 512 4. -// nocc (-2) = 2^12 * (2^-4 ) = 256 7. @1 -// nocc ( 3) = 2^12 * (2^-4 ) = 256 8. -// nocc (-3) = 2^12 * (2^-3 + 2^-3) = 1024 1. -// nocc ( 4) = 2^12 * (2^-3 + 2^-4) = 768 2. -// nocc (-4) = 2^12 * (2^-3 ) = 512 5. -// -// which gives the literal order (according to 'vivify_more_noccs') -// -// -3, 4, 1, 2, -4, -1, -2, 3 -// -// Then sorting the literals in each clause gives -// -// -3 1 -4 (A') -// 4 -1 -2 3 (B') @2 -// -3 4 2 (C') -// -// and finally sorting those clauses lexicographically w.r.t. scores is -// -// -3 4 2 (C') -// -3 1 -4 (A') @3 -// 4 -1 -2 3 (B') -// -// This order is defined by 'vivify_clause_later' which returns 'true' if -// the first clause should be vivified later than the second. - -struct vivify_clause_later { - - Internal *internal; - - vivify_clause_later (Internal *i) : internal (i) {} - - bool operator() (Clause *a, Clause *b) const { - - if (a == b) - return false; - - // First focus on clauses scheduled in the last vivify round but not - // checked yet since then. - // - if (!a->vivify && b->vivify) - return true; - if (a->vivify && !b->vivify) - return false; - - // Among redundant clauses (in redundant mode) prefer small glue. - // - if (a->redundant) { - CADICAL_assert (b->redundant); - if (a->glue > b->glue) - return true; - if (a->glue < b->glue) - return false; - } - - // Then prefer shorter size. - // - if (a->size > b->size) - return true; - if (a->size < b->size) - return false; - - // Now compare literals in the clauses lexicographically with respect to - // the literal order 'vivify_more_noccs' assuming literals are sorted - // decreasingly with respect to that order. - // - const auto eoa = a->end (), eob = b->end (); - auto j = b->begin (); - for (auto i = a->begin (); i != eoa && j != eob; i++, j++) - if (*i != *j) - return vivify_more_noccs (internal) (*j, *i); - - return j == eob; // Prefer shorter clauses to be vivified first. - } -}; - -/*------------------------------------------------------------------------*/ - -// Attempting on-the-fly subsumption during sorting when the last line is -// reached in 'vivify_clause_later' above turned out to be trouble some for -// identical clauses. This is the single point where 'vivify_clause_later' -// is not asymmetric and would require 'stable' sorting for determinism. It -// can also not be made 'complete' on-the-fly. Instead of on-the-fly -// subsumption we thus go over the sorted scheduled in a linear scan -// again and remove certain subsumed clauses (the subsuming clause is -// syntactically a prefix of the subsumed clause), which includes -// those troublesome syntactically identical clauses. - -struct vivify_flush_smaller { - - bool operator() (Clause *a, Clause *b) const { - - const auto eoa = a->end (), eob = b->end (); - auto i = a->begin (), j = b->begin (); - for (; i != eoa && j != eob; i++, j++) - if (*i != *j) - return *i < *j; - - return j == eob && i != eoa; - } -}; - -void Internal::flush_vivification_schedule (std::vector &schedule, - int64_t &ticks) { - ticks += 1 + 3 * cache_lines (schedule.size (), sizeof (Clause *)); - stable_sort (schedule.begin (), schedule.end (), vivify_flush_smaller ()); - - const auto end = schedule.end (); - auto j = schedule.begin (), i = j; - - Clause *prev = 0; - int64_t subsumed = 0; - for (; i != end; i++) { - ticks++; - Clause *c = *j++ = *i; - if (!prev || c->size < prev->size) { - prev = c; - continue; - } - const auto eop = prev->end (); - auto k = prev->begin (); - for (auto l = c->begin (); k != eop; k++, l++) - if (*k != *l) - break; - if (k == eop) { - LOG (c, "found subsumed"); - LOG (prev, "subsuming"); - CADICAL_assert (!c->garbage); - CADICAL_assert (!prev->garbage); - CADICAL_assert (c->redundant || !prev->redundant); - mark_garbage (c); - subsumed++; - j--; - } else - prev = c; - } - - if (subsumed) - PHASE ("vivify", stats.vivifications, - "flushed %" PRId64 " subsumed scheduled clauses", subsumed); - - stats.vivifysubs += subsumed; - - if (subsumed) { - schedule.resize (j - schedule.begin ()); - shrink_vector (schedule); - } else - CADICAL_assert (j == end); -} - -/*------------------------------------------------------------------------*/ - -// Depending on whether we try to vivify redundant or irredundant clauses, -// we schedule a clause to be vivified. For redundant clauses we initially -// only try to vivify them if they are likely to survive the next 'reduce' -// operation, but this left the last schedule empty most of the time. - -bool Internal::consider_to_vivify_clause (Clause *c) { - if (c->garbage) - return false; - if (opts.vivifyonce >= 1 && c->redundant && c->vivified) - return false; - if (opts.vivifyonce >= 2 && !c->redundant && c->vivified) - return false; - if (!c->redundant) - return true; - CADICAL_assert (c->redundant); - - // likely_to_be_kept_clause is too aggressive at removing tier-3 clauses - return true; -} - -/*------------------------------------------------------------------------*/ - -// In a strengthened clause the idea is to move non-false literals to the -// front, followed by false literals. Literals are further sorted by -// reverse assignment order. The goal is to use watches which require to -// backtrack as few as possible decision levels. - -struct vivify_better_watch { - - Internal *internal; - - vivify_better_watch (Internal *i) : internal (i) {} - - bool operator() (int a, int b) { - - const signed char av = internal->val (a), bv = internal->val (b); - - if (av >= 0 && bv < 0) - return true; - if (av < 0 && bv >= 0) - return false; - - return internal->var (a).trail > internal->var (b).trail; - } -}; - -// Common code to actually strengthen a candidate clause. The resulting -// strengthened clause is communicated through the global 'clause'. - -void Internal::vivify_strengthen (Clause *c) { - - CADICAL_assert (!clause.empty ()); - - if (clause.size () == 1) { - - backtrack_without_updating_phases (); - const int unit = clause[0]; - LOG (c, "vivification shrunken to unit %d", unit); - CADICAL_assert (!val (unit)); - assign_unit (unit); - // lrat_chain.clear (); done in search_assign - stats.vivifyunits++; - - bool ok = propagate (); - if (!ok) - learn_empty_clause (); - - } else { - - // See explanation before 'vivify_better_watch' above. - // - sort (clause.begin (), clause.end (), vivify_better_watch (this)); - - int new_level = level; - - const int lit0 = clause[0]; - signed char val0 = val (lit0); - if (val0 < 0) { - const int level0 = var (lit0).level; - LOG ("1st watch %d negative at level %d", lit0, level0); - new_level = level0 - 1; - } - - const int lit1 = clause[1]; - const signed char val1 = val (lit1); - if (val1 < 0 && !(val0 > 0 && var (lit0).level <= var (lit1).level)) { - const int level1 = var (lit1).level; - LOG ("2nd watch %d negative at level %d", lit1, level1); - new_level = level1 - 1; - } - - CADICAL_assert (new_level >= 0); - if (new_level < level) - backtrack (new_level); - - CADICAL_assert (val (lit0) >= 0); - CADICAL_assert (val (lit1) >= 0 || (val (lit0) > 0 && val (lit1) < 0 && - var (lit0).level <= var (lit1).level)); - - Clause *d = new_clause_as (c); - LOG (c, "before vivification"); - LOG (d, "after vivification"); - (void) d; - } - clause.clear (); - mark_garbage (c); - lrat_chain.clear (); - ++stats.vivifystrs; -} - -void Internal::vivify_sort_watched (Clause *c) { - - sort (c->begin (), c->end (), vivify_better_watch (this)); - - int new_level = level; - - const int lit0 = c->literals[0]; - signed char val0 = val (lit0); - if (val0 < 0) { - const int level0 = var (lit0).level; - LOG ("1st watch %d negative at level %d", lit0, level0); - new_level = level0 - 1; - } - - const int lit1 = c->literals[1]; - const signed char val1 = val (lit1); - if (val1 < 0 && !(val0 > 0 && var (lit0).level <= var (lit1).level)) { - const int level1 = var (lit1).level; - LOG ("2nd watch %d negative at level %d", lit1, level1); - new_level = level1 - 1; - } - - CADICAL_assert (new_level >= 0); - if (new_level < level) - backtrack (new_level); - - CADICAL_assert (val (lit0) >= 0); - CADICAL_assert (val (lit1) >= 0 || (val (lit0) > 0 && val (lit1) < 0 && - var (lit0).level <= var (lit1).level)); -} -// Conflict analysis from 'start' which learns a decision only clause. -// -// We cannot use the stack-based implementation of Kissat, because we need -// to iterate over the conflict in topological ordering to produce a valid -// LRAT proof - -void Internal::vivify_analyze (Clause *start, bool &subsumes, - Clause **subsuming, - const Clause *const candidate, int implied, - bool &redundant) { - const auto &t = &trail; // normal trail, so next_trail is wrong - int i = t->size (); // Start at end-of-trail. - Clause *reason = start; - CADICAL_assert (reason); - CADICAL_assert (!trail.empty ()); - int uip = trail.back (); - bool mark_implied = (implied); - - while (i >= 0) { - if (reason) { - redundant = (redundant || reason->redundant); - subsumes = (start != reason && reason->size <= start->size); - LOG (reason, "resolving on %d with", uip); - for (auto other : *reason) { - const Var v = var (other); - Flags &f = flags (other); - if (!marked2 (other) && v.level) { - LOG ("not subsuming due to lit %d", other); - subsumes = false; - } - if (!val (other)) { - LOG ("skipping unset lit %d", other); - continue; - } - if (other == uip) { - continue; - } - if (!v.level) { - if (f.seen || !lrat || reason == start) - continue; - LOG ("unit reason for %d", other); - int64_t id = unit_id (-other); - LOG ("adding unit reason %zd for %d", id, other); - unit_chain.push_back (id); - f.seen = true; - analyzed.push_back (other); - continue; - } - if (mark_implied && other != implied) { - LOG ("skipping non-implied literal %d on current level", other); - continue; - } - - CADICAL_assert (val (other)); - if (f.seen) - continue; - LOG ("pushing lit %d", other); - analyzed.push_back (other); - f.seen = true; - } - if (start->redundant) { - const int new_glue = recompute_glue (start); - promote_clause (start, new_glue); - } - if (subsumes) { - CADICAL_assert (reason); - LOG (reason, "clause found subsuming"); - LOG (candidate, "clause found subsumed"); - *subsuming = reason; - return; - } - } else { - LOG ("vivify analyzed decision %d", uip); - clause.push_back (-uip); - } - mark_implied = false; - - uip = 0; - while (!uip && i > 0) { - CADICAL_assert (i > 0); - const int lit = (*t)[--i]; - if (!var (lit).level) - continue; - if (flags (lit).seen) - uip = lit; - } - if (!uip) - break; - LOG ("uip is %d", uip); - Var &w = var (uip); - reason = w.reason; - if (lrat && reason) - lrat_chain.push_back (reason->id); - } - (void) candidate; -} - -void Internal::vivify_deduce (Clause *candidate, Clause *conflict, - int implied, Clause **subsuming, - bool &redundant) { - CADICAL_assert (lrat_chain.empty ()); - bool subsumes; - Clause *reason; - - CADICAL_assert (clause.empty ()); - if (implied) { - reason = candidate; - mark2 (candidate); - const int not_implied = -implied; - CADICAL_assert (var (not_implied).level); - Flags &f = flags (not_implied); - f.seen = true; - LOG ("pushing implied lit %d", not_implied); - analyzed.push_back (not_implied); - clause.push_back (implied); - } else { - reason = (conflict ? conflict : candidate); - CADICAL_assert (reason); - CADICAL_assert (!reason->garbage); - mark2 (candidate); - subsumes = (candidate != reason); - redundant = reason->redundant; - LOG (reason, "resolving with"); - if (lrat) - lrat_chain.push_back (reason->id); - for (auto lit : *reason) { - const Var &v = var (lit); - Flags &f = flags (lit); - CADICAL_assert (val (lit) < 0); - if (!v.level) { - if (!lrat) - continue; - LOG ("adding unit %d", lit); - if (!f.seen) { - // nevertheless we can use var (l) as if l was still assigned - // because var is updated lazily - int64_t id = unit_id (-lit); - LOG ("adding unit reason %zd for %d", id, lit); - unit_chain.push_back (id); - } - f.seen = true; - analyzed.push_back (lit); - continue; - } - CADICAL_assert (v.level); - if (!marked2 (lit)) { - LOG ("lit %d is not marked", lit); - subsumes = false; - } - LOG ("analyzing lit %d", lit); - LOG ("pushing lit %d", lit); - analyzed.push_back (lit); - f.seen = true; - } - if (reason != candidate && reason->redundant) { - const int new_glue = recompute_glue (reason); - promote_clause (reason, new_glue); - } - if (subsumes) { - CADICAL_assert (candidate != reason); -#ifndef CADICAL_NDEBUG - int nonfalse_reason = 0; - for (auto lit : *reason) - if (!fixed (lit)) - ++nonfalse_reason; - - int nonfalse_candidate = 0; - for (auto lit : *candidate) - if (!fixed (lit)) - ++nonfalse_candidate; - - CADICAL_assert (nonfalse_reason <= nonfalse_candidate); -#endif - LOG (candidate, "vivify subsumed 0"); - LOG (reason, "vivify subsuming 0"); - *subsuming = reason; - unmark (candidate); - if (lrat) - lrat_chain.clear (); - return; - } - } - - vivify_analyze (reason, subsumes, subsuming, candidate, implied, - redundant); - unmark (candidate); - if (subsumes) { - CADICAL_assert (*subsuming); - LOG (candidate, "vivify subsumed"); - LOG (*subsuming, "vivify subsuming"); - if (lrat) - lrat_chain.clear (); - } -} -/*------------------------------------------------------------------------*/ - -bool Internal::vivify_shrinkable (const std::vector &sorted, - Clause *conflict) { - - unsigned count_implied = 0; - for (auto lit : sorted) { - const signed char value = val (lit); - if (!value) { - LOG ("vivification unassigned %d", lit); - return true; - } - if (value > 0) { - LOG ("vivification implied satisfied %d", lit); - if (conflict) - return true; - if (count_implied++) { - LOG ("at least one implied literal with conflict thus shrinking"); - return true; - } - } else { - CADICAL_assert (value < 0); - const Var &v = var (lit); - const Flags &f = flags (lit); - if (!v.level) - continue; - if (!f.seen) { - LOG ("vivification non-analyzed %d", lit); - return true; - } - if (v.reason) { - LOG ("vivification implied falsified %d", lit); - return true; - } - } - } - return false; -} -/*------------------------------------------------------------------------*/ - -inline void Internal::vivify_increment_stats (const Vivifier &vivifier) { - switch (vivifier.tier) { - case Vivify_Mode::TIER1: - ++stats.vivifystred1; - break; - case Vivify_Mode::TIER2: - ++stats.vivifystred2; - break; - case Vivify_Mode::TIER3: - ++stats.vivifystred3; - break; - default: - CADICAL_assert (vivifier.tier == Vivify_Mode::IRREDUNDANT); - ++stats.vivifystrirr; - break; - } -} -/*------------------------------------------------------------------------*/ -// instantiate last literal (see the description of the hack track 2023), -// fix the watches and -// backtrack two level back -bool Internal::vivify_instantiate ( - const std::vector &sorted, Clause *c, - std::vector> &lrat_stack, - int64_t &ticks) { - LOG ("now trying instantiation"); - conflict = nullptr; - const int lit = sorted.back (); - LOG ("vivify instantiation"); - CADICAL_assert (!var (lit).reason); - CADICAL_assert (var (lit).level); - CADICAL_assert (val (lit)); - backtrack (level - 1); - CADICAL_assert (val (lit) == 0); - stats.vivifydecs++; - vivify_assume (lit); - bool ok = vivify_propagate (ticks); - if (!ok) { - LOG (c, "instantiate success with literal %d in", lit); - stats.vivifyinst++; - // strengthen clause - if (lrat) { - clear_analyzed_literals (); - CADICAL_assert (lrat_chain.empty ()); - vivify_build_lrat (0, c, lrat_stack); - vivify_build_lrat (0, conflict, lrat_stack); - clear_analyzed_literals (); - } - int remove = lit; - conflict = nullptr; - unwatch_clause (c); - backtrack_without_updating_phases (level - 2); - strengthen_clause (c, remove); - vivify_sort_watched (c); - watch_clause (c); - CADICAL_assert (!conflict); - return true; - } else { - LOG ("vivify instantiation failed"); - return false; - } -} - -/*------------------------------------------------------------------------*/ - -// Main function: try to vivify this candidate clause in the given mode. - -bool Internal::vivify_clause (Vivifier &vivifier, Clause *c) { - - CADICAL_assert (c->size > 2); // see (NO-BINARY) below - CADICAL_assert (analyzed.empty ()); - - c->vivify = false; // mark as checked / tried - c->vivified = true; // and globally remember - - CADICAL_assert (!c->garbage); - - auto &lrat_stack = vivifier.lrat_stack; - auto &ticks = vivifier.ticks; - ticks++; - - // First check whether the candidate clause is already satisfied and at - // the same time copy its non fixed literals to 'sorted'. The literals - // in the candidate clause might not be sorted anymore due to replacing - // watches during propagation, even though we sorted them initially - // while pushing the clause onto the schedule and sorting the schedule. - // - auto &sorted = vivifier.sorted; - sorted.clear (); - - for (const auto &lit : *c) { - const int tmp = fixed (lit); - if (tmp > 0) { - LOG (c, "satisfied by propagated unit %d", lit); - mark_garbage (c); - return false; - } else if (!tmp) - sorted.push_back (lit); - } - - CADICAL_assert (sorted.size () > 1); - if (sorted.size () == 2) { - LOG ("skipping actual binary"); - return false; - } - - sort (sorted.begin (), sorted.end (), vivify_more_noccs_kissat (this)); - - // The actual vivification checking is performed here, by assuming the - // negation of each of the remaining literals of the clause in turn and - // propagating it. If a conflict occurs or another literal in the - // clause becomes assigned during propagation, we can stop. - // - LOG (c, "vivification checking"); - stats.vivifychecks++; - - // If the decision 'level' is non-zero, then we can reuse decisions for - // the previous candidate, and avoid re-propagating them. In preliminary - // experiments this saved between 30%-50% decisions (and thus - // propagations), which in turn lets us also vivify more clauses within - // the same propagation bounds, or terminate earlier if vivify runs to - // completion. - // - if (level) { -#ifdef LOGGING - int orig_level = level; -#endif - // First check whether this clause is actually a reason for forcing - // one of its literals to true and then backtrack one level before - // that happened. Otherwise this clause might be incorrectly - // considered to be redundant or if this situation is checked then - // redundancy by other clauses using this forced literal becomes - // impossible. - // - int forced = 0; - - // This search could be avoided if we would eagerly set the 'reason' - // boolean flag of clauses, which however we do not want to do for - // binary clauses (during propagation) and thus would still require - // a version of 'protect_reason' for binary clauses during 'reduce' - // (well binary clauses are not collected during 'reduce', but again - // this exception from the exception is pretty complex and thus a - // simply search here is probably easier to understand). - - for (const auto &lit : *c) { - const signed char tmp = val (lit); - if (tmp < 0) - continue; - if (tmp > 0 && var (lit).reason == c) - forced = lit; - break; - } - if (forced) { - LOG ("clause is reason forcing %d", forced); - CADICAL_assert (var (forced).level); - backtrack_without_updating_phases (var (forced).level - 1); - } - - // As long the (remaining) literals of the sorted clause match - // decisions on the trail we just reuse them. - // - if (level) { - - int l = 1; // This is the decision level we want to reuse. - - for (const auto &lit : sorted) { - CADICAL_assert (!fixed (lit)); - const int decision = control[l].decision; - if (-lit == decision) { - LOG ("reusing decision %d at decision level %d", decision, l); - stats.vivifyreused++; - if (++l > level) - break; - } else { - LOG ("literal %d does not match decision %d at decision level %d", - lit, decision, l); - backtrack_without_updating_phases (l - 1); - break; - } - } - } - - LOG ("reused %d decision levels from %d", level, orig_level); - } - - LOG (sorted, "sorted size %zd probing schedule", sorted.size ()); - - // Make sure to ignore this clause during propagation. This is not that - // easy for binary clauses (NO-BINARY), e.g., ignoring binary clauses, - // without changing 'propagate'. Actually, we do not want to remove binary - // clauses which are subsumed. Those are hyper binary resolvents and - // should be kept as learned clauses instead, unless they are transitive - // in the binary implication graph, which in turn is detected during - // transitive reduction in 'transred'. - // - ignore = c; - - int subsume = 0; // determined to be redundant / subsumed - - // If the candidate is redundant, i.e., we are in redundant mode, the - // clause is subsumed (in one of the two cases below where 'subsume' is - // assigned) and further all reasons involved are only binary clauses, - // then this redundant clause is what we once called a hidden tautology, - // and even for redundant clauses it makes sense to remove the candidate. - // It does not add anything to propagation power of the formula. This is - // the same argument as removing transitive clauses in the binary - // implication graph during transitive reduction. - // - - // Go over the literals in the candidate clause in sorted order. - // - for (const auto &lit : sorted) { - - // Exit loop as soon a literal is positively implied (case '@5' below) - // or propagation of the negation of a literal fails ('@6'). - // - if (subsume) - break; - - // We keep on assigning literals, even though we know already that we - // can remove one (was negatively implied), since we either might run - // into the 'subsume' case above or more false literals become implied. - // In any case this might result in stronger vivified clauses. As a - // consequence continue with this loop even if 'remove' is non-zero. - - const signed char tmp = val (lit); - - if (tmp) { // literal already assigned - - const Var &v = var (lit); - CADICAL_assert (v.level); - if (!v.reason) { - LOG ("skipping decision %d", lit); - continue; - } - - if (tmp < 0) { - CADICAL_assert (v.level); - LOG ("literal %d is already false and can be removed", lit); - continue; - } - - CADICAL_assert (tmp > 0); - LOG ("subsumed since literal %d already true", lit); - subsume = lit; // will be able to subsume candidate '@5' - break; - } - - CADICAL_assert (!tmp); - - stats.vivifydecs++; - vivify_assume (-lit); - LOG ("negated decision %d score %" PRId64 "", lit, noccs (lit)); - - if (!vivify_propagate (ticks)) { - break; // hot-spot - } - } - - if (subsume) { - int better_subsume_trail = var (subsume).trail; - for (auto lit : sorted) { - if (val (lit) <= 0) - continue; - const Var v = var (lit); - if (v.trail < better_subsume_trail) { - LOG ("improving subsume from %d at %d to %d at %d", subsume, - better_subsume_trail, lit, v.trail); - better_subsume_trail = v.trail; - subsume = lit; - } - } - } - - Clause *subsuming = nullptr; - bool redundant = false; - const int level_after_assumptions = level; - CADICAL_assert (level_after_assumptions); - vivify_deduce (c, conflict, subsume, &subsuming, redundant); - - bool res; - - // reverse lrat_chain. We could probably work with reversed iterators - // (views) to be more efficient but we would have to distinguish in proof - // - if (lrat) { - for (auto id : unit_chain) - lrat_chain.push_back (id); - unit_chain.clear (); - reverse (lrat_chain.begin (), lrat_chain.end ()); - } - - if (subsuming) { - CADICAL_assert (c != subsuming); - LOG (c, "deleting subsumed clause"); - if (c->redundant && subsuming->redundant && c->glue < subsuming->glue) { - promote_clause (c, c->glue); - } - vivify_subsume_clause (subsuming, c); - res = false; - // stats.vivifysubs++; // already done in vivify_subsume_clause - } else if (vivify_shrinkable (sorted, conflict)) { - vivify_increment_stats (vivifier); - LOG ("vivify succeeded, learning new clause"); - clear_analyzed_literals (); - LOG (lrat_chain, "lrat"); - LOG (clause, "learning clause"); - conflict = nullptr; // TODO dup from below - vivify_strengthen (c); - res = true; - } else if (subsume && c->redundant) { - LOG (c, "vivification implied"); - mark_garbage (c); - ++stats.vivifyimplied; - res = true; - } else if ((conflict || subsume) && !c->redundant && !redundant) { - LOG ("demote clause from irredundant to redundant"); - if (opts.vivifydemote) { - demote_clause (c); - const int new_glue = recompute_glue (c); - promote_clause (c, new_glue); - res = false; - } else { - mark_garbage (c); - ++stats.vivifyimplied; - res = true; - } - } else if (subsume) { - LOG (c, "no vivification instantiation with implied literal %d", - subsume); - CADICAL_assert (!c->redundant); - CADICAL_assert (redundant); - res = false; - ++stats.vivifyimplied; - } else { - CADICAL_assert (level > 2); - CADICAL_assert ((size_t) level == sorted.size ()); - LOG (c, "vivification failed on"); - lrat_chain.clear (); - CADICAL_assert (!subsume); - if (!subsume && opts.vivifyinst) { - res = vivify_instantiate (sorted, c, lrat_stack, ticks); - CADICAL_assert (!conflict); - } else { - LOG ("cannot apply instantiation"); - res = false; - } - } - - if (conflict && level == level_after_assumptions) { - LOG ("forcing backtracking at least one level after conflict"); - backtrack_without_updating_phases (level - 1); - } - - clause.clear (); - clear_analyzed_literals (); // TODO why needed? - lrat_chain.clear (); - conflict = nullptr; - return res; -} - -// when we can strengthen clause c we have to build lrat. -// uses f.seen so do not forget to clear flags afterwards. -// this can happen in three cases. (1), (2) are only sound in redundant mode -// (1) literal l in c is positively implied. in this case we call the -// function with (l, l.reason). This justifies the reduction because the new -// clause c' will include l and all decisions so l.reason is a conflict -// assuming -c' (2) conflict during vivify propagation. function is called -// with (0, conflict) similar to (1) but more direct. (3) some literals in c -// are negatively implied and can therefore be removed. in this case we call -// the function with (0, c). originally we justified each literal in c on -// its own but this is not actually necessary. -// - -// Non-recursive version, as some bugs have been found. DFS over the -// reasons with preordering (aka we explore the entire reason before -// exploring deeper) -void Internal::vivify_build_lrat ( - int lit, Clause *reason, - std::vector> &stack) { - CADICAL_assert (stack.empty ()); - stack.push_back ({lit, reason, false}); - while (!stack.empty ()) { - int lit; - Clause *reason; - bool finished; - std::tie (lit, reason, finished) = stack.back (); - LOG ("VIVIFY LRAT justifying %d", lit); - stack.pop_back (); - if (lit && flags (lit).seen) { - LOG ("skipping already justified"); - continue; - } - if (finished) { - lrat_chain.push_back (reason->id); - if (lit && reason) { - Flags &f = flags (lit); - f.seen = true; - analyzed.push_back (lit); // CADICAL_assert (val (other) < 0); - CADICAL_assert (flags (lit).seen); - } - continue; - } else - stack.push_back ({lit, reason, true}); - for (const auto &other : *reason) { - if (other == lit) - continue; - Var &v = var (other); - Flags &f = flags (other); - if (f.seen) - continue; - if (!v.level) { - const int64_t id = unit_id (-other); - lrat_chain.push_back (id); - f.seen = true; - analyzed.push_back (other); - continue; - } - if (v.reason) { // recursive justification - LOG ("VIVIFY LRAT pushing %d", other); - stack.push_back ({other, v.reason, false}); - } - } - } - stack.clear (); -} - -// calculate lrat_chain -// -inline void Internal::vivify_chain_for_units (int lit, Clause *reason) { - if (!lrat) - return; - // LOG ("building chain for units"); bad line for debugging - // equivalence if (opts.chrono && assignment_level (lit, reason)) return; - if (level) - return; // not decision level 0 - CADICAL_assert (lrat_chain.empty ()); - for (auto &reason_lit : *reason) { - if (lit == reason_lit) - continue; - CADICAL_assert (val (reason_lit)); - const int signed_reason_lit = val (reason_lit) * reason_lit; - int64_t id = unit_id (signed_reason_lit); - lrat_chain.push_back (id); - } - lrat_chain.push_back (reason->id); -} - -vivify_ref create_ref (Internal *internal, Clause *c) { - LOG (c, "creating vivify_refs of clause"); - vivify_ref ref; - ref.clause = c; - ref.size = c->size; - for (int i = 0; i < COUNTREF_COUNTS; ++i) - ref.count[i] = 0; - ref.vivify = c->vivify; - int lits[COUNTREF_COUNTS] = {0}; - for (int i = 0; i != std::min (COUNTREF_COUNTS, c->size); ++i) { - int best = 0; - unsigned best_count = 0; - for (auto lit : *c) { - LOG ("to find best number of occurrences for literal %d, looking at " - "literal %d", - i, lit); - for (int j = 0; j != i; ++j) { - LOG ("comparing %d with literal %d", lit, lits[j]); - if (lits[j] == lit) - goto CONTINUE_WITH_NEXT_LITERAL; - } - { - const int64_t lit_count = internal->noccs (lit); - CADICAL_assert (lit_count); - LOG ("checking literal %d with %zd occurrences", lit, lit_count); - if (lit_count <= best_count) - continue; - best_count = lit_count; - best = lit; - } - CONTINUE_WITH_NEXT_LITERAL:; - } - CADICAL_assert (best); - CADICAL_assert (best_count); - CADICAL_assert (best_count < UINT32_MAX); - ref.count[i] = - ((uint64_t) best_count << 32) + (uint64_t) internal->vlit (best); - LOG ("final count at position %d is %d - %d: %lu", i, best, best_count, - ref.count[i]); - lits[i] = best; - } - return ref; -} -/*------------------------------------------------------------------------*/ -inline void -Internal::vivify_prioritize_leftovers ([[maybe_unused]] char tag, - size_t prioritized, - std::vector &schedule) { - if (prioritized) { - PHASE ("vivify", stats.vivifications, - "[phase %c] leftovers of %" PRId64 " clause", tag, prioritized); - } else { - PHASE ("vivify", stats.vivifications, - "[phase %c] prioritizing all clause", tag); - for (auto c : schedule) - c->vivify = true; - } - const size_t max = opts.vivifyschedmax; - if (schedule.size () > max) { - if (prioritized) { - std::partition (begin (schedule), end (schedule), - [] (Clause *c) { return c->vivify; }); - } - schedule.resize (max); - } - // let's try to save a bit of memory - shrink_vector (schedule); -} - -void Internal::vivify_initialize (Vivifier &vivifier, int64_t &ticks) { - - const int tier1 = vivifier.tier1_limit; - const int tier2 = vivifier.tier2_limit; - // Count the number of occurrences of literals in all clauses, - // particularly binary clauses, which are usually responsible - // for most of the propagations. - // - init_noccs (); - - // Disconnect all watches since we sort literals within clauses. - // - CADICAL_assert (watching ()); -#if 0 - clear_watches (); -#endif - - size_t prioritized_irred = 0, prioritized_tier1 = 0, - prioritized_tier2 = 0, prioritized_tier3 = 0; - for (const auto &c : clauses) { - ++ticks; - if (c->size == 2) - continue; // see also (NO-BINARY) above - if (!consider_to_vivify_clause (c)) - continue; - - // This computes an approximation of the Jeroslow Wang heuristic - // score - // - // nocc (L) = sum 2^(12-|C|) - // L in C in F - // - // but we cap the size at 12, that is all clauses of size 12 and - // larger contribute '1' to the score, which allows us to use 'long' - // numbers. See the example above (search for '@1'). - // - const int shift = 12 - c->size; - const int64_t score = shift < 1 ? 1 : (1l << shift); // @4 - for (const auto lit : *c) { - noccs (lit) += score; - } - LOG (c, "putting clause in candidates"); - if (!c->redundant) - vivifier.schedule_irred.push_back (c), - prioritized_irred += (c->vivify); - else if (c->glue <= tier1) - vivifier.schedule_tier1.push_back (c), - prioritized_tier1 += (c->vivify); - else if (c->glue <= tier2) - vivifier.schedule_tier2.push_back (c), - prioritized_tier2 += (c->vivify); - else - vivifier.schedule_tier3.push_back (c), - prioritized_tier3 += (c->vivify); - ++ticks; - } - - vivify_prioritize_leftovers ('x', prioritized_irred, - vivifier.schedule_irred); - vivify_prioritize_leftovers ('u', prioritized_tier1, - vivifier.schedule_tier1); - vivify_prioritize_leftovers ('v', prioritized_tier2, - vivifier.schedule_tier2); - vivify_prioritize_leftovers ('w', prioritized_tier3, - vivifier.schedule_tier3); - - if (opts.vivifyflush) { - clear_watches (); - for (auto &sched : vivifier.schedules) { - for (const auto &c : sched) { - // Literals in scheduled clauses are sorted with their highest score - // literals first (as explained above in the example at '@2'). This - // is also needed in the prefix subsumption checking below. We do an - // approximation below that is done only in the vivify_ref structure - // below. - // - sort (c->begin (), c->end (), vivify_more_noccs (this)); - } - // Flush clauses subsumed by another clause with the same prefix, - // which also includes flushing syntactically identical clauses. - // - flush_vivification_schedule (sched, ticks); - } - connect_watches (); // watch all relevant clauses - } -#if 0 - connect_watches (); // watch all relevant clauses - vivify_propagate (ticks); -#endif - vivify_propagate (ticks); -} - -inline std::vector ¤t_refs_schedule (Vivifier &vivifier) { - switch (vivifier.tier) { - case Vivify_Mode::TIER1: - return vivifier.refs_schedule_tier1; - break; - case Vivify_Mode::TIER2: - return vivifier.refs_schedule_tier2; - break; - case Vivify_Mode::TIER3: - return vivifier.refs_schedule_tier3; - break; - default: - return vivifier.refs_schedule_irred; - break; - } -#ifdef WIN32 - __assume(false); -#else - __builtin_unreachable (); -#endif -} - -inline std::vector ¤t_schedule (Vivifier &vivifier) { - switch (vivifier.tier) { - case Vivify_Mode::TIER1: - return vivifier.schedule_tier1; - break; - case Vivify_Mode::TIER2: - return vivifier.schedule_tier2; - break; - case Vivify_Mode::TIER3: - return vivifier.schedule_tier3; - break; - default: - return vivifier.schedule_irred; - break; - } -#ifdef WIN32 - __assume(false); -#else - __builtin_unreachable (); -#endif -} - -struct vivify_refcount_rank { - int offset; - vivify_refcount_rank (int j) : offset (j) { - CADICAL_assert (offset < COUNTREF_COUNTS); - } - typedef uint64_t Type; - Type operator() (const vivify_ref &a) const { return a.count[offset]; } -}; - -struct vivify_refcount_smaller { - int offset; - vivify_refcount_smaller (int j) : offset (j) { - CADICAL_assert (offset < COUNTREF_COUNTS); - } - bool operator() (const vivify_ref &a, const vivify_ref &b) const { - const auto s = vivify_refcount_rank (offset) (a); - const auto t = vivify_refcount_rank (offset) (b); - return s < t; - } -}; - -struct vivify_inversesize_rank { - vivify_inversesize_rank () {} - typedef uint64_t Type; - Type operator() (const vivify_ref &a) const { return ~a.size; } -}; - -struct vivify_inversesize_smaller { - vivify_inversesize_smaller () {} - bool operator() (const vivify_ref &a, const vivify_ref &b) const { - const auto s = vivify_inversesize_rank () (a); - const auto t = vivify_inversesize_rank () (b); - return s < t; - } -}; - -/*------------------------------------------------------------------------*/ -// There are two modes of vivification, one using all clauses and one -// focusing on irredundant clauses only. The latter variant working on -// irredundant clauses only can also remove irredundant asymmetric -// tautologies (clauses subsumed through unit propagation), which in -// redundant mode is incorrect (due to propagating over redundant clauses). - -void Internal::vivify_round (Vivifier &vivifier, int64_t ticks_limit) { - - if (unsat) - return; - if (terminated_asynchronously ()) - return; - - PHASE ("vivify", stats.vivifications, - "starting %c vivification round ticks limit %" PRId64 "", - vivifier.tag, ticks_limit); - - PHASE ("vivify", stats.vivifications, - "starting %c vivification round ticks limit %" PRId64 "", - vivifier.tag, ticks_limit); - - CADICAL_assert (watching ()); - - auto &refs_schedule = current_refs_schedule (vivifier); - auto &schedule = current_schedule (vivifier); - - int64_t ticks = 1 + schedule.size (); - - // Sort candidates, with first to be tried candidate clause last, i.e., - // many occurrences and high score literals) as in the example explained - // above (search for '@3'). - // - if (vivifier.tier != Vivify_Mode::IRREDUNDANT || - irredundant () / 10 < redundant ()) { - // Literals in scheduled clauses are sorted with their highest score - // literals first (as explained above in the example at '@2'). This is - // also needed in the prefix subsumption checking below. We do an - // approximation below that is done only in the vivify_ref structure - // below. - // - - // first build the schedule with vivifier_refs - auto end_schedule = end (schedule); - refs_schedule.resize (schedule.size ()); - std::transform (begin (schedule), end_schedule, begin (refs_schedule), - [&] (Clause *c) { return create_ref (this, c); }); - // now sort by size - MSORT (opts.radixsortlim, refs_schedule.begin (), refs_schedule.end (), - vivify_inversesize_rank (), vivify_inversesize_smaller ()); - // now (stable) sort by number of occurrences - for (int i = 0; i < COUNTREF_COUNTS; ++i) { - const int offset = COUNTREF_COUNTS - 1 - i; - MSORT (opts.radixsortlim, refs_schedule.begin (), - refs_schedule.end (), vivify_refcount_rank (offset), - vivify_refcount_smaller (offset)); - } - // force left-overs at the end - std::stable_partition (begin (refs_schedule), end (refs_schedule), - [] (vivify_ref c) { return !c.vivify; }); - std::transform (begin (refs_schedule), end (refs_schedule), - begin (schedule), - [] (vivify_ref c) { return c.clause; }); - erase_vector (refs_schedule); - LOG ("clause after sorting final:"); - } else { - // skip sorting but still put clauses with the vivify tag at the end to - // be done first Kissat does this implicitely by going twice over all - // clauses - std::stable_partition (begin (schedule), end (schedule), - [] (Clause *c) { return !c->vivify; }); - } - - // Remember old values of counters to summarize after each round with - // verbose messages what happened in that round. - // - int64_t checked = stats.vivifychecks; - int64_t subsumed = stats.vivifysubs; - int64_t strengthened = stats.vivifystrs; - int64_t units = stats.vivifyunits; - - int64_t scheduled = schedule.size (); - stats.vivifysched += scheduled; - - PHASE ("vivify", stats.vivifications, - "scheduled %" PRId64 " clauses to be vivified %.0f%%", scheduled, - percent (scheduled, stats.current.irredundant)); - - // Limit the number of propagations during vivification as in 'probe'. - // - const int64_t limit = ticks_limit - stats.ticks.vivify; - CADICAL_assert (limit >= 0); - - // the clauses might still contain set literals, so propagation since the - // beginning - propagated2 = propagated = 0; - - if (!unsat && !propagate ()) { - LOG ("propagation after connecting watches in inconsistency"); - learn_empty_clause (); - } - - vivifier.ticks = ticks; - int retry = 0; - while (!unsat && !terminated_asynchronously () && !schedule.empty () && - vivifier.ticks < limit) { - Clause *c = schedule.back (); // Next candidate. - schedule.pop_back (); - if (vivify_clause (vivifier, c) && !c->garbage && c->size > 2 && - retry < opts.vivifyretry) { - ++retry; - schedule.push_back (c); - } else - retry = 0; - } - - if (level) - backtrack_without_updating_phases (); - - if (!unsat) { - int64_t still_need_to_be_vivified = schedule.size (); -#if 0 - // in the current round we have new_clauses_to_vivify @ leftovers from previous round There are - // now two possibilities: (i) we consider all clauses as leftovers, or (ii) only the leftovers - // from previous round are considered leftovers. - // - // CaDiCaL had the first version before. If - // commented out we go to the second version. - for (auto c : schedule) - c->vivify = true; -#elif 1 - // if we have gone through all the leftovers, the current clauses are - // leftovers for the next round - if (!schedule.empty () && !schedule.front ()->vivify && - schedule.back ()->vivify) - for (auto c : schedule) - c->vivify = true; -#else - // do nothing like in kissat and use the candidates for next time. -#endif - // Preference clauses scheduled but not vivified yet next time. - // - if (still_need_to_be_vivified) - PHASE ("vivify", stats.vivifications, - "still need to vivify %" PRId64 " clauses %.02f%% of %" PRId64 - " scheduled", - still_need_to_be_vivified, - percent (still_need_to_be_vivified, scheduled), scheduled); - else { - PHASE ("vivify", stats.vivifications, - "no previously not yet vivified clause left"); - } - - erase_vector (schedule); // Reclaim memory early. - } - - if (!unsat) { - - // Since redundant clause were disconnected during propagating vivified - // units in redundant mode, and further irredundant clauses are - // arbitrarily sorted, we have to propagate all literals again after - // connecting the first two literals in the clauses, in order to - // reestablish the watching invariant. - // - propagated2 = propagated = 0; - - if (!propagate ()) { - LOG ("propagating vivified units leads to conflict"); - learn_empty_clause (); - } - } - - checked = stats.vivifychecks - checked; - subsumed = stats.vivifysubs - subsumed; - strengthened = stats.vivifystrs - strengthened; - units = stats.vivifyunits - units; - - PHASE ("vivify", stats.vivifications, - "checked %" PRId64 " clauses %.02f%% of %" PRId64 - " scheduled using %" PRIu64 " ticks", - checked, percent (checked, scheduled), scheduled, vivifier.ticks); - if (units) - PHASE ("vivify", stats.vivifications, - "found %" PRId64 " units %.02f%% of %" PRId64 " checked", units, - percent (units, checked), checked); - if (subsumed) - PHASE ("vivify", stats.vivifications, - "subsumed %" PRId64 " clauses %.02f%% of %" PRId64 " checked", - subsumed, percent (subsumed, checked), checked); - if (strengthened) - PHASE ("vivify", stats.vivifications, - "strengthened %" PRId64 " clauses %.02f%% of %" PRId64 - " checked", - strengthened, percent (strengthened, checked), checked); - - stats.subsumed += subsumed; - stats.strengthened += strengthened; - stats.ticks.vivify += vivifier.ticks; - - bool unsuccessful = !(subsumed + strengthened + units); - report (vivifier.tag, unsuccessful); -} - -void set_vivifier_mode (Vivifier &vivifier, Vivify_Mode tier) { - vivifier.tier = tier; - switch (tier) { - case Vivify_Mode::TIER1: - vivifier.tag = 'u'; - break; - case Vivify_Mode::TIER2: - vivifier.tag = 'v'; - break; - case Vivify_Mode::TIER3: - vivifier.tag = 'w'; - break; - default: - CADICAL_assert (tier == Vivify_Mode::IRREDUNDANT); - vivifier.tag = 'x'; - break; - } -} -/*------------------------------------------------------------------------*/ - -void Internal::compute_tier_limits (Vivifier &vivifier) { - if (!opts.vivifycalctier) { - vivifier.tier1_limit = 2; - vivifier.tier2_limit = 6; - return; - } - vivifier.tier1_limit = tier1[false]; - vivifier.tier2_limit = tier2[false]; -} - -/*------------------------------------------------------------------------*/ - -bool Internal::vivify () { - - if (unsat) - return false; - if (terminated_asynchronously ()) - return false; - if (!opts.vivify) - return false; - if (!stats.current.irredundant) - return false; - if (level) - backtrack (); - CADICAL_assert (opts.vivify); - CADICAL_assert (!level); - - SET_EFFORT_LIMIT (totallimit, vivify, true); - - private_steps = true; - - START_SIMPLIFIER (vivify, VIVIFY); - stats.vivifications++; - - // the effort is normalized by dividing by sumeffort below, hence no need - // to multiply by 1e-3 (also making the precision better) - double tier1effort = !opts.vivifytier1 ? 0 : (double) opts.vivifytier1eff; - double tier2effort = !opts.vivifytier2 ? 0 : (double) opts.vivifytier2eff; - double tier3effort = !opts.vivifytier3 ? 0 : (double) opts.vivifytier3eff; - double irreffort = - delaying_vivify_irredundant.bumpreasons.delay () || !opts.vivifyirred - ? 0 - : (double) opts.vivifyirredeff; - double sumeffort = tier1effort + tier2effort + tier3effort + irreffort; - if (!stats.current.redundant) - tier1effort = tier2effort = tier3effort = 0; - if (!sumeffort) - sumeffort = irreffort = 1; - int64_t total = totallimit - stats.ticks.vivify; - - PHASE ("vivify", stats.vivifications, - "vivification limit of %" PRId64 " ticks", total); - Vivifier vivifier (Vivify_Mode::TIER1); - compute_tier_limits (vivifier); - - if (vivifier.tier1_limit == vivifier.tier2_limit) { - tier1effort += tier2effort; - tier2effort = 0; - LOG ("vivification tier1 matches tier2 " - "thus using tier2 budget for tier1"); - } - int64_t init_ticks = 0; - - // Refill the schedule every time. Unchecked clauses are 'saved' by - // setting their 'vivify' bit, such that they can be tried next time. - // - // TODO: count against ticks.vivify directly instead of this unholy - // shifting. - vivify_initialize (vivifier, init_ticks); - stats.ticks.vivify += init_ticks; - int64_t limit = stats.ticks.vivify; - const double shared_effort = (double) init_ticks / 4.0; - if (opts.vivifytier1) { - set_vivifier_mode (vivifier, Vivify_Mode::TIER1); - if (limit < stats.ticks.vivify) - limit = stats.ticks.vivify; - const double effort = (total * tier1effort) / sumeffort; - CADICAL_assert (std::numeric_limits::max () - (int64_t) effort >= - limit); - limit += effort; - if (limit - shared_effort > stats.ticks.vivify) { - limit -= shared_effort; - CADICAL_assert (limit >= 0); - vivify_round (vivifier, limit); - } else { - LOG ("building the schedule already used our entire ticks budget for " - "tier1"); - } - } - - if (!unsat && tier2effort) { - erase_vector ( - vivifier.schedule_tier1); // save memory (well, not really as we - // already reached the peak memory) - if (limit < stats.ticks.vivify) - limit = stats.ticks.vivify; - const double effort = (total * tier2effort) / sumeffort; - CADICAL_assert (std::numeric_limits::max () - (int64_t) effort >= - limit); - limit += effort; - if (limit - shared_effort > stats.ticks.vivify) { - limit -= shared_effort; - CADICAL_assert (limit >= 0); - set_vivifier_mode (vivifier, Vivify_Mode::TIER2); - vivify_round (vivifier, limit); - } else { - LOG ("building the schedule already used our entire ticks budget for " - "tier2"); - } - } - - if (!unsat && tier3effort) { - erase_vector (vivifier.schedule_tier2); - if (limit < stats.ticks.vivify) - limit = stats.ticks.vivify; - const double effort = (total * tier3effort) / sumeffort; - CADICAL_assert (std::numeric_limits::max () - (int64_t) effort >= - limit); - limit += effort; - if (limit - shared_effort > stats.ticks.vivify) { - limit -= shared_effort; - CADICAL_assert (limit >= 0); - set_vivifier_mode (vivifier, Vivify_Mode::TIER3); - vivify_round (vivifier, limit); - } else { - LOG ("building the schedule already used our entire ticks budget for " - "tier3"); - } - } - - if (!unsat && irreffort) { - erase_vector (vivifier.schedule_tier3); - if (limit < stats.ticks.vivify) - limit = stats.ticks.vivify; - const double effort = (total * irreffort) / sumeffort; - CADICAL_assert (std::numeric_limits::max () - (int64_t) effort >= - limit); - limit += effort; - if (limit - shared_effort > stats.ticks.vivify) { - limit -= shared_effort; - CADICAL_assert (limit >= 0); - set_vivifier_mode (vivifier, Vivify_Mode::IRREDUNDANT); - const int old = stats.vivifystrirr; - const int old_tried = stats.vivifychecks; - vivify_round (vivifier, limit); - if (stats.vivifychecks - old_tried == 0 || - (float) (stats.vivifystrirr - old) / - (float) (stats.vivifychecks - old_tried) < - 0.01) { - delaying_vivify_irredundant.bumpreasons.bump_delay (); - } else { - delaying_vivify_irredundant.bumpreasons.reduce_delay (); - } - } else { - delaying_vivify_irredundant.bumpreasons.bump_delay (); - LOG ("building the schedule already used our entire ticks budget for " - "irredundant"); - } - } - - reset_noccs (); - STOP_SIMPLIFIER (vivify, VIVIFY); - - private_steps = false; - - return true; -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_walk.cpp b/src/sat/cadical/cadical_walk.cpp deleted file mode 100644 index 13b1bf9f4..000000000 --- a/src/sat/cadical/cadical_walk.cpp +++ /dev/null @@ -1,710 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -/*------------------------------------------------------------------------*/ - -// Random walk local search based on 'ProbSAT' ideas. - -struct Walker { - - Internal *internal; - - Random random; // local random number generator - int64_t propagations; // number of propagations - int64_t limit; // limit on number of propagations - vector broken; // currently unsatisfied clauses - double epsilon; // smallest considered score - vector table; // break value to score table - vector scores; // scores of candidate literals - - double score (unsigned); // compute score from break count - - Walker (Internal *, double size, int64_t limit); -}; - -// These are in essence the CB values from Adrian Balint's thesis. They -// denote the inverse 'cb' of the base 'b' of the (probability) weight -// 'b^-i' for picking a literal with the break value 'i' (first column is -// the 'size', second the 'CB' value). - -static double cbvals[][2] = { - {0.0, 2.00}, {3.0, 2.50}, {4.0, 2.85}, {5.0, 3.70}, - {6.0, 5.10}, {7.0, 7.40}, // Adrian has '5.4', but '7.4' looks better. -}; - -static const int ncbvals = sizeof cbvals / sizeof cbvals[0]; - -// We interpolate the CB values for uniform random SAT formula to the non -// integer situation of average clause size by piecewise linear functions. -// -// y2 - y1 -// ------- * (x - x1) + y1 -// x2 - x1 -// -// where 'x' is the average size of clauses and 'y' the CB value. - -inline static double fitcbval (double size) { - int i = 0; - while (i + 2 < ncbvals && - (cbvals[i][0] > size || cbvals[i + 1][0] < size)) - i++; - const double x2 = cbvals[i + 1][0], x1 = cbvals[i][0]; - const double y2 = cbvals[i + 1][1], y1 = cbvals[i][1]; - const double dx = x2 - x1, dy = y2 - y1; - CADICAL_assert (dx); - const double res = dy * (size - x1) / dx + y1; - CADICAL_assert (res > 0); - return res; -} - -// Initialize the data structures for one local search round. - -Walker::Walker (Internal *i, double size, int64_t l) - : internal (i), random (internal->opts.seed), // global random seed - propagations (0), limit (l) { - random += internal->stats.walk.count; // different seed every time - - // This is the magic constant in ProbSAT (also called 'CB'), which we pick - // according to the average size every second invocation and otherwise - // just the default '2.0', which turns into the base '0.5'. - // - const bool use_size_based_cb = (internal->stats.walk.count & 1); - const double cb = use_size_based_cb ? fitcbval (size) : 2.0; - CADICAL_assert (cb); - const double base = 1 / cb; // scores are 'base^0,base^1,base^2,... - - double next = 1; - for (epsilon = next; next; next = epsilon * base) - table.push_back (epsilon = next); - - PHASE ("walk", internal->stats.walk.count, - "CB %.2f with inverse %.2f as base and table size %zd", cb, base, - table.size ()); -} - -// The scores are tabulated for faster computation (to avoid 'pow'). - -inline double Walker::score (unsigned i) { - const double res = (i < table.size () ? table[i] : epsilon); - LOG ("break %u mapped to score %g", i, res); - return res; -} - -/*------------------------------------------------------------------------*/ - -Clause *Internal::walk_pick_clause (Walker &walker) { - require_mode (WALK); - CADICAL_assert (!walker.broken.empty ()); - int64_t size = walker.broken.size (); - if (size > INT_MAX) - size = INT_MAX; - int pos = walker.random.pick_int (0, size - 1); - Clause *res = walker.broken[pos]; - LOG (res, "picking random position %d", pos); - return res; -} - -/*------------------------------------------------------------------------*/ - -// Compute the number of clauses which would be become unsatisfied if 'lit' -// is flipped and set to false. This is called the 'break-count' of 'lit'. - -unsigned Internal::walk_break_value (int lit) { - - require_mode (WALK); - CADICAL_assert (val (lit) > 0); - - unsigned res = 0; // The computed break-count of 'lit'. - - for (auto &w : watches (lit)) { - CADICAL_assert (w.blit != lit); - if (val (w.blit) > 0) - continue; - if (w.binary ()) { - res++; - continue; - } - - Clause *c = w.clause; - CADICAL_assert (lit == c->literals[0]); - - // Now try to find a second satisfied literal starting at 'literals[1]' - // shifting all the traversed literals to right by one position in order - // to move such a second satisfying literal to 'literals[1]'. This move - // to front strategy improves the chances to find the second satisfying - // literal earlier in subsequent break-count computations. - // - auto begin = c->begin () + 1; - const auto end = c->end (); - auto i = begin; - int prev = 0; - while (i != end) { - const int other = *i; - *i++ = prev; - prev = other; - if (val (other) < 0) - continue; - - // Found 'other' as second satisfying literal. - - w.blit = other; // Update 'blit' - *begin = other; // and move to front. - - break; - } - - if (i != end) - continue; // Double satisfied! - - // Otherwise restore literals (undo shift to the right). - // - while (i != begin) { - const int other = *--i; - *i = prev; - prev = other; - } - - res++; // Literal 'lit' single satisfies clause 'c'. - } - - return res; -} - -/*------------------------------------------------------------------------*/ - -// Given an unsatisfied clause 'c', in which we want to flip a literal, we -// first determine the exponential score based on the break-count of its -// literals and then sample the literals based on these scores. The CB -// value is smaller than one and thus the score is exponentially decreasing -// with the break-count increasing. The sampling works as in 'ProbSAT' and -// 'YalSAT' by summing up the scores and then picking a random limit in the -// range of zero to the sum, then summing up the scores again and picking -// the first literal which reaches the limit. Note, that during incremental -// SAT solving we can not flip assumed variables. Those are assigned at -// decision level one, while the other variables are assigned at two. - -int Internal::walk_pick_lit (Walker &walker, Clause *c) { - LOG ("picking literal by break-count"); - CADICAL_assert (walker.scores.empty ()); - double sum = 0; - int64_t propagations = 0; - for (const auto lit : *c) { - CADICAL_assert (active (lit)); - if (var (lit).level == 1) { - LOG ("skipping assumption %d for scoring", -lit); - continue; - } - CADICAL_assert (active (lit)); - propagations++; - unsigned tmp = walk_break_value (-lit); - double score = walker.score (tmp); - LOG ("literal %d break-count %u score %g", lit, tmp, score); - walker.scores.push_back (score); - sum += score; - } - LOG ("scored %zd literals", walker.scores.size ()); - CADICAL_assert (!walker.scores.empty ()); - walker.propagations += propagations; - stats.propagations.walk += propagations; - CADICAL_assert (walker.scores.size () <= (size_t) c->size); - const double lim = sum * walker.random.generate_double (); - LOG ("score sum %g limit %g", sum, lim); - const auto end = c->end (); - auto i = c->begin (); - auto j = walker.scores.begin (); - int res; - for (;;) { - CADICAL_assert (i != end); - res = *i++; - if (var (res).level > 1) - break; - LOG ("skipping assumption %d without score", -res); - } - sum = *j++; - while (sum <= lim && i != end) { - res = *i++; - if (var (res).level == 1) { - LOG ("skipping assumption %d without score", -res); - continue; - } - sum += *j++; - } - walker.scores.clear (); - LOG ("picking literal %d by break-count", res); - return res; -} - -/*------------------------------------------------------------------------*/ - -void Internal::walk_flip_lit (Walker &walker, int lit) { - - require_mode (WALK); - LOG ("flipping assign %d", lit); - CADICAL_assert (val (lit) < 0); - - // First flip the literal value. - // - const int tmp = sign (lit); - const int idx = abs (lit); - set_val (idx, tmp); - CADICAL_assert (val (lit) > 0); - - // Then remove 'c' and all other now satisfied (made) clauses. - { - // Simply go over all unsatisfied (broken) clauses. - - LOG ("trying to make %zd broken clauses", walker.broken.size ()); - - // We need to measure (and bound) the memory accesses during traversing - // broken clauses in terms of 'propagations'. This is tricky since we - // are not actually propagating literals. Instead we use the clause - // variable 'ratio' as an approximation to the number of clauses used - // during propagating a literal. Note that we use a one-watch scheme. - // Accordingly the number of broken clauses traversed divided by that - // ratio is an approximation of the number of propagation this would - // correspond to (in terms of memory access). To eagerly update these - // statistics we simply increment the propagation counter after every - // 'ratio' traversed clause. These propagations are particularly - // expensive if the number of broken clauses is large which usually - // happens initially. - // - const double ratio = clause_variable_ratio (); - const auto eou = walker.broken.end (); - auto j = walker.broken.begin (), i = j; -#ifdef LOGGING - int64_t made = 0; -#endif - int64_t count = 0; - - while (i != eou) { - - Clause *d = *j++ = *i++; - - int *literals = d->literals, prev = 0; - - // Find 'lit' in 'd'. - // - const int size = d->size; - for (int i = 0; i < size; i++) { - const int other = literals[i]; - CADICAL_assert (active (other)); - literals[i] = prev; - prev = other; - if (other == lit) - break; - CADICAL_assert (val (other) < 0); - } - - // If 'lit' is in 'd' then move it to the front to watch it. - // - if (prev == lit) { - literals[0] = lit; - LOG (d, "made"); - watch_literal (literals[0], literals[1], d); -#ifdef LOGGING - made++; -#endif - j--; - - } else { // Otherwise the clause is not satisfied, undo shift. - - for (int i = size - 1; i >= 0; i--) { - int other = literals[i]; - literals[i] = prev; - prev = other; - } - } - - if (count--) - continue; - - // Update these counters eagerly. Otherwise if we delay the update - // until all clauses are traversed, interrupting the solver has a high - // chance of giving bogus statistics on the number of 'propagations' - // in 'walk', if it is interrupted in this loop. - - count = ratio; // Starting counting down again. - walker.propagations++; - stats.propagations.walk++; - } - LOG ("made %" PRId64 " clauses by flipping %d", made, lit); - walker.broken.resize (j - walker.broken.begin ()); - } - - // Finally add all new unsatisfied (broken) clauses. - { - walker.propagations++; // This really corresponds now to one - stats.propagations.walk++; // propagation (in a one-watch scheme). - -#ifdef LOGGING - int64_t broken = 0; -#endif - Watches &ws = watches (-lit); - - LOG ("trying to break %zd watched clauses", ws.size ()); - - for (const auto &w : ws) { - Clause *d = w.clause; - LOG (d, "unwatch %d in", -lit); - int *literals = d->literals, replacement = 0, prev = -lit; - CADICAL_assert (literals[0] == -lit); - const int size = d->size; - for (int i = 1; i < size; i++) { - const int other = literals[i]; - CADICAL_assert (active (other)); - literals[i] = prev; // shift all to right - prev = other; - const signed char tmp = val (other); - if (tmp < 0) - continue; - replacement = other; // satisfying literal - break; - } - if (replacement) { - literals[1] = -lit; - literals[0] = replacement; - CADICAL_assert (-lit != replacement); - watch_literal (replacement, -lit, d); - } else { - for (int i = size - 1; i > 0; i--) { // undo shift - const int other = literals[i]; - literals[i] = prev; - prev = other; - } - CADICAL_assert (literals[0] == -lit); - LOG (d, "broken"); - walker.broken.push_back (d); -#ifdef LOGGING - broken++; -#endif - } - } - LOG ("broken %" PRId64 " clauses by flipping %d", broken, lit); - ws.clear (); - } -} - -/*------------------------------------------------------------------------*/ - -// Check whether to save the current phases as new global minimum. - -inline void Internal::walk_save_minimum (Walker &walker) { - int64_t broken = walker.broken.size (); - if (broken >= stats.walk.minimum) - return; - VERBOSE (3, "new global minimum %" PRId64 "", broken); - stats.walk.minimum = broken; - for (auto i : vars) { - const signed char tmp = vals[i]; - if (tmp) - phases.min[i] = phases.saved[i] = tmp; - } -} - -/*------------------------------------------------------------------------*/ - -int Internal::walk_round (int64_t limit, bool prev) { - - backtrack (); - if (propagated < trail.size () && !propagate ()) { - LOG ("empty clause after root level propagation"); - learn_empty_clause (); - return 20; - } - - stats.walk.count++; - - clear_watches (); - - // Remove all fixed variables first (assigned at decision level zero). - // - if (last.collect.fixed < stats.all.fixed) - garbage_collection (); - -#ifndef CADICAL_QUIET - // We want to see more messages during initial local search. - // - if (localsearching) { - CADICAL_assert (!force_phase_messages); - force_phase_messages = true; - } -#endif - - PHASE ("walk", stats.walk.count, - "random walk limit of %" PRId64 " propagations", limit); - - // First compute the average clause size for picking the CB constant. - // - double size = 0; - int64_t n = 0; - for (const auto c : clauses) { - if (c->garbage) - continue; - if (c->redundant) { - if (!opts.walkredundant) - continue; - if (!likely_to_be_kept_clause (c)) - continue; - } - size += c->size; - n++; - } - double average_size = relative (size, n); - - PHASE ("walk", stats.walk.count, - "%" PRId64 " clauses average size %.2f over %d variables", n, - average_size, active ()); - - // Instantiate data structures for this local search round. - // - Walker walker (internal, average_size, limit); - - bool failed = false; // Inconsistent assumptions? - - level = 1; // Assumed variables assigned at level 1. - - if (assumptions.empty ()) { - LOG ("no assumptions so assigning all variables to decision phase"); - } else { - LOG ("assigning assumptions to their forced phase first"); - for (const auto lit : assumptions) { - signed char tmp = val (lit); - if (tmp > 0) - continue; - if (tmp < 0) { - LOG ("inconsistent assumption %d", lit); - failed = true; - break; - } - if (!active (lit)) - continue; - tmp = sign (lit); - const int idx = abs (lit); - LOG ("initial assign %d to assumption phase", tmp < 0 ? -idx : idx); - set_val (idx, tmp); - CADICAL_assert (level == 1); - var (idx).level = 1; - } - if (!failed) - LOG ("now assigning remaining variables to their decision phase"); - } - - level = 2; // All other non assumed variables assigned at level 2. - - if (!failed) { - - for (auto idx : vars) { - if (!active (idx)) { - LOG ("skipping inactive variable %d", idx); - continue; - } - if (vals[idx]) { - CADICAL_assert (var (idx).level == 1); - LOG ("skipping assumed variable %d", idx); - continue; - } - int tmp = 0; - if (prev) - tmp = phases.prev[idx]; - if (!tmp) - tmp = sign (decide_phase (idx, true)); - CADICAL_assert (tmp == 1 || tmp == -1); - set_val (idx, tmp); - CADICAL_assert (level == 2); - var (idx).level = 2; - LOG ("initial assign %d to decision phase", tmp < 0 ? -idx : idx); - } - - LOG ("watching satisfied and registering broken clauses"); -#ifdef LOGGING - int64_t watched = 0; -#endif - for (const auto c : clauses) { - - if (c->garbage) - continue; - if (c->redundant) { - if (!opts.walkredundant) - continue; - if (!likely_to_be_kept_clause (c)) - continue; - } - - bool satisfiable = false; // contains not only assumptions - int satisfied = 0; // clause satisfied? - - int *lits = c->literals; - const int size = c->size; - - // Move to front satisfied literals and determine whether there - // is at least one (non-assumed) literal that can be flipped. - // - for (int i = 0; satisfied < 2 && i < size; i++) { - const int lit = lits[i]; - CADICAL_assert (active (lit)); // Due to garbage collection. - if (val (lit) > 0) { - swap (lits[satisfied], lits[i]); - if (!satisfied++) - LOG ("first satisfying literal %d", lit); - } else if (!satisfiable && var (lit).level > 1) { - LOG ("non-assumption potentially satisfying literal %d", lit); - satisfiable = true; - } - } - - if (!satisfied && !satisfiable) { - LOG (c, "due to assumptions unsatisfiable"); - LOG ("stopping local search since assumptions falsify a clause"); - failed = true; - break; - } - - if (satisfied) { - watch_literal (lits[0], lits[1], c); -#ifdef LOGGING - watched++; -#endif - } else { - CADICAL_assert (satisfiable); // at least one non-assumed variable ... - LOG (c, "broken"); - walker.broken.push_back (c); - } - } -#ifdef LOGGING - if (!failed) { - int64_t broken = walker.broken.size (); - int64_t total = watched + broken; - LOG ("watching %" PRId64 " clauses %.0f%% " - "out of %" PRId64 " (watched and broken)", - watched, percent (watched, total), total); - } -#endif - } - - int64_t old_global_minimum = stats.walk.minimum; - - int res; // Tells caller to continue with local search. - - if (!failed) { - - int64_t broken = walker.broken.size (); - - PHASE ("walk", stats.walk.count, - "starting with %" PRId64 " unsatisfied clauses " - "(%.0f%% out of %" PRId64 ")", - broken, percent (broken, stats.current.irredundant), - stats.current.irredundant); - - walk_save_minimum (walker); - - int64_t minimum = broken; -#ifndef CADICAL_QUIET - int64_t flips = 0; -#endif - while (!terminated_asynchronously () && !walker.broken.empty () && - walker.propagations < walker.limit) { -#ifndef CADICAL_QUIET - flips++; -#endif - stats.walk.flips++; - stats.walk.broken += broken; - Clause *c = walk_pick_clause (walker); - const int lit = walk_pick_lit (walker, c); - walk_flip_lit (walker, lit); - broken = walker.broken.size (); - LOG ("now have %" PRId64 " broken clauses in total", broken); - if (broken >= minimum) - continue; - minimum = broken; - VERBOSE (3, "new phase minimum %" PRId64 " after %" PRId64 " flips", - minimum, flips); - walk_save_minimum (walker); - } - - if (minimum < old_global_minimum) - PHASE ("walk", stats.walk.count, - "%snew global minimum %" PRId64 "%s in %" PRId64 " flips and " - "%" PRId64 " propagations", - tout.bright_yellow_code (), minimum, tout.normal_code (), - flips, walker.propagations); - else - PHASE ("walk", stats.walk.count, - "best phase minimum %" PRId64 " in %" PRId64 " flips and " - "%" PRId64 " propagations", - minimum, flips, walker.propagations); - - if (opts.profile >= 2) { - PHASE ("walk", stats.walk.count, - "%.2f million propagations per second", - relative (1e-6 * walker.propagations, - time () - profiles.walk.started)); - - PHASE ("walk", stats.walk.count, "%.2f thousand flips per second", - relative (1e-3 * flips, time () - profiles.walk.started)); - - } else { - PHASE ("walk", stats.walk.count, "%.2f million propagations", - 1e-6 * walker.propagations); - - PHASE ("walk", stats.walk.count, "%.2f thousand flips", 1e-3 * flips); - } - - if (minimum > 0) { - LOG ("minimum %" PRId64 " non-zero thus potentially continue", - minimum); - res = 0; - } else { - LOG ("minimum is zero thus stop local search"); - res = 10; - } - - } else { - - res = 20; - - PHASE ("walk", stats.walk.count, - "aborted due to inconsistent assumptions"); - } - - copy_phases (phases.prev); - - for (auto idx : vars) - if (active (idx)) - set_val (idx, 0); - - CADICAL_assert (level == 2); - level = 0; - - clear_watches (); - connect_watches (); - -#ifndef CADICAL_QUIET - if (localsearching) { - CADICAL_assert (force_phase_messages); - force_phase_messages = false; - } -#endif - - return res; -} - -void Internal::walk () { - START_INNER_WALK (); - int64_t limit = stats.propagations.search; - limit *= 1e-3 * opts.walkeffort; - if (limit < opts.walkmineff) - limit = opts.walkmineff; - if (limit > opts.walkmaxeff) - limit = opts.walkmaxeff; - (void) walk_round (limit, false); - STOP_INNER_WALK (); -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_watch.cpp b/src/sat/cadical/cadical_watch.cpp deleted file mode 100644 index 84c51ef2c..000000000 --- a/src/sat/cadical/cadical_watch.cpp +++ /dev/null @@ -1,132 +0,0 @@ -#include "global.h" - -#include "internal.hpp" - -ABC_NAMESPACE_IMPL_START - -namespace CaDiCaL { - -void Internal::init_watches () { - CADICAL_assert (wtab.empty ()); - if (wtab.size () < 2 * vsize) - wtab.resize (2 * vsize, Watches ()); - LOG ("initialized watcher tables"); -} - -void Internal::clear_watches () { - for (auto lit : lits) - watches (lit).clear (); -} - -void Internal::reset_watches () { - CADICAL_assert (!wtab.empty ()); - erase_vector (wtab); - LOG ("reset watcher tables"); -} - -// This can be quite costly since lots of memory is accessed in a rather -// random fashion, and thus we optionally profile it. - -void Internal::connect_watches (bool irredundant_only) { - START (connect); - CADICAL_assert (watching ()); - - LOG ("watching all %sclauses", irredundant_only ? "irredundant " : ""); - - // First connect binary clauses. - // - for (const auto &c : clauses) { - if (irredundant_only && c->redundant) - continue; - if (c->garbage || c->size > 2) - continue; - watch_clause (c); - } - - // Then connect non-binary clauses. - // - for (const auto &c : clauses) { - if (irredundant_only && c->redundant) - continue; - if (c->garbage || c->size == 2) - continue; - watch_clause (c); - if (!level) { - const int lit0 = c->literals[0]; - const int lit1 = c->literals[1]; - const signed char tmp0 = val (lit0); - const signed char tmp1 = val (lit1); - if (tmp0 > 0) - continue; - if (tmp1 > 0) - continue; - if (tmp0 < 0) { - const size_t pos0 = var (lit0).trail; - if (pos0 < propagated) { - propagated = pos0; - LOG ("literal %d resets propagated to %zd", lit0, pos0); - } - } - if (tmp1 < 0) { - const size_t pos1 = var (lit1).trail; - if (pos1 < propagated) { - propagated = pos1; - LOG ("literal %d resets propagated to %zd", lit1, pos1); - } - } - } - } - - STOP (connect); -} - -// This can be quite costly since lots of memory is accessed in a rather -// random fashion, and thus we optionally profile it. - -void Internal::connect_binary_watches () { - START (connect); - CADICAL_assert (watching ()); - - LOG ("watching binary clauses"); - - // First connect binary clauses. - // - for (const auto &c : clauses) { - if (c->garbage || c->size > 2) - continue; - watch_clause (c); - } - - STOP (connect); -} - -void Internal::sort_watches () { - CADICAL_assert (watching ()); - LOG ("sorting watches"); - Watches saved; - for (auto lit : lits) { - Watches &ws = watches (lit); - - const const_watch_iterator end = ws.end (); - watch_iterator j = ws.begin (); - const_watch_iterator i; - - CADICAL_assert (saved.empty ()); - - for (i = j; i != end; i++) { - const Watch w = *i; - if (w.binary ()) - *j++ = w; - else - saved.push_back (w); - } - - std::copy (saved.cbegin (), saved.cend (), j); - - saved.clear (); - } -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/ccadical.h b/src/sat/cadical/ccadical.h deleted file mode 100644 index ec5292a79..000000000 --- a/src/sat/cadical/ccadical.h +++ /dev/null @@ -1,74 +0,0 @@ -#ifndef _ccadical_h_INCLUDED -#define _ccadical_h_INCLUDED - -#include "global.h" - -/*------------------------------------------------------------------------*/ -ABC_NAMESPACE_HEADER_START -/*------------------------------------------------------------------------*/ - -#include -#include - -// C wrapper for CaDiCaL's C++ API following IPASIR. - -typedef struct CCaDiCaL CCaDiCaL; - -const char *ccadical_signature (void); -CCaDiCaL *ccadical_init (void); -void ccadical_release (CCaDiCaL *); - -void ccadical_add (CCaDiCaL *, int lit); -void ccadical_assume (CCaDiCaL *, int lit); -int ccadical_solve (CCaDiCaL *); -int ccadical_val (CCaDiCaL *, int lit); -int ccadical_failed (CCaDiCaL *, int lit); - -void ccadical_set_terminate (CCaDiCaL *, void *state, - int (*terminate) (void *state)); - -void ccadical_set_learn (CCaDiCaL *, void *state, int max_length, - void (*learn) (void *state, int *clause)); - -/*------------------------------------------------------------------------*/ - -// Non-IPASIR conformant 'C' functions. - -void ccadical_constrain (CCaDiCaL *, int lit); -int ccadical_constraint_failed (CCaDiCaL *); -void ccadical_set_option (CCaDiCaL *, const char *name, int val); -void ccadical_limit (CCaDiCaL *, const char *name, int limit); -int ccadical_get_option (CCaDiCaL *, const char *name); -void ccadical_print_statistics (CCaDiCaL *); -int64_t ccadical_active (CCaDiCaL *); -int64_t ccadical_irredundant (CCaDiCaL *); -int ccadical_fixed (CCaDiCaL *, int lit); -int ccadical_trace_proof (CCaDiCaL *, FILE *, const char *); -void ccadical_close_proof (CCaDiCaL *); -void ccadical_conclude (CCaDiCaL *); -void ccadical_terminate (CCaDiCaL *); -void ccadical_freeze (CCaDiCaL *, int lit); -int ccadical_frozen (CCaDiCaL *, int lit); -void ccadical_melt (CCaDiCaL *, int lit); -int ccadical_simplify (CCaDiCaL *); -int ccadical_vars (CCaDiCaL *); -int ccadical_reserve_difference (CCaDiCaL *, int number_of_vars); - -// Extra - -void ccadical_reserve(CCaDiCaL *, int min_max_var); -int ccadical_is_inconsistent(CCaDiCaL *); - -/*------------------------------------------------------------------------*/ - -// Support legacy names used before moving to more IPASIR conforming names. - -#define ccadical_reset ccadical_release -#define ccadical_sat ccadical_solve -#define ccadical_deref ccadical_val - -/*------------------------------------------------------------------------*/ -ABC_NAMESPACE_HEADER_END -/*------------------------------------------------------------------------*/ - -#endif diff --git a/src/sat/cadical/checker.hpp b/src/sat/cadical/checker.hpp deleted file mode 100644 index 8c351e326..000000000 --- a/src/sat/cadical/checker.hpp +++ /dev/null @@ -1,178 +0,0 @@ -#ifndef _checker_hpp_INCLUDED -#define _checker_hpp_INCLUDED - -#include "global.h" - -#include "tracer.hpp" // Alphabetically after 'checker'. - -#include - -ABC_NAMESPACE_CXX_HEADER_START - -namespace CaDiCaL { - -/*------------------------------------------------------------------------*/ - -// This checker implements an online forward DRUP proof checker enabled by -// 'opts.checkproof' (requires 'opts.check' also to be enabled). This is -// useful for model basted testing (and delta-debugging), where we can not -// rely on an external proof checker such as 'drat-trim'. We also do not -// have yet a flow for offline incremental proof checking, while this -// checker here can also be used in an incremental setting. -// -// In essence the checker implements is a simple propagation online SAT -// solver with an additional hash table to find clauses fast for -// 'delete_clause'. It requires its own data structure for clauses -// ('CheckerClause') and watches ('CheckerWatch'). -// -// In our experiments the checker slows down overall SAT solving time by a -// factor of 3, which we contribute to its slightly less efficient -// implementation. - -/*------------------------------------------------------------------------*/ - -struct CheckerClause { - CheckerClause *next; // collision chain link for hash table - uint64_t hash; // previously computed full 64-bit hash - unsigned size; // zero if this is a garbage clause - int literals[2]; // otherwise 'literals' of length 'size' -}; - -struct CheckerWatch { - int blit; - unsigned size; - CheckerClause *clause; - CheckerWatch () {} - CheckerWatch (int b, CheckerClause *c) - : blit (b), size (c->size), clause (c) {} -}; - -typedef vector CheckerWatcher; - -/*------------------------------------------------------------------------*/ - -class Checker : public StatTracer { - - Internal *internal; - - // Capacity of variable values. - // - int64_t size_vars; - - // For the assignment we want to have an as fast access as possible and - // thus we use an array which can also be indexed by negative literals and - // is actually valid in the range [-size_vars+1, ..., size_vars-1]. - // - signed char *vals; - - // The 'watchers' and 'marks' data structures are not that time critical - // and thus we access them by first mapping a literal to 'unsigned'. - // - static unsigned l2u (int lit); - vector watchers; // watchers of literals - vector marks; // mark bits of literals - - signed char &mark (int lit); - CheckerWatcher &watcher (int lit); - - bool inconsistent; // found or added empty clause - - uint64_t num_clauses; // number of clauses in hash table - uint64_t num_garbage; // number of garbage clauses - uint64_t size_clauses; // size of clause hash table - CheckerClause **clauses; // hash table of clauses - CheckerClause *garbage; // linked list of garbage clauses - - vector unsimplified; // original clause for reporting - vector simplified; // clause for sorting - - vector trail; // for propagation - - unsigned next_to_propagate; // next to propagate on trail - - void enlarge_vars (int64_t idx); - void import_literal (int lit); - void import_clause (const vector &); - bool tautological (); - - static const unsigned num_nonces = 4; - - uint64_t nonces[num_nonces]; // random numbers for hashing - uint64_t last_hash; // last computed hash value of clause - int64_t last_id; - uint64_t compute_hash (); // compute and save hash value of clause - - // Reduce hash value to the actual size. - // - static uint64_t reduce_hash (uint64_t hash, uint64_t size); - - void enlarge_clauses (); // enlarge hash table for clauses - void insert (); // insert clause in hash table - CheckerClause **find (); // find clause position in hash table - - void add_clause (const char *type); - - void collect_garbage_clauses (); - - CheckerClause *new_clause (); - void delete_clause (CheckerClause *); - - signed char val (int lit); // returns '-1', '0' or '1' - - bool clause_satisfied (CheckerClause *); - - void assign (int lit); // assign a literal to true - void assume (int lit); // assume a literal - bool propagate (); // propagate and check for conflicts - void backtrack (unsigned); // prepare for next clause - bool check (); // check simplified clause is implied - bool check_blocked (); // check if clause is blocked - - struct { - - int64_t added; // number of added clauses - int64_t original; // number of added original clauses - int64_t derived; // number of added derived clauses - - int64_t deleted; // number of deleted clauses - - int64_t assumptions; // number of assumed literals - int64_t propagations; // number of propagated literals - - int64_t insertions; // number of clauses added to hash table - int64_t collisions; // number of hash collisions in 'find' - int64_t searches; // number of searched clauses in 'find' - - int64_t checks; // number of implication checks - - int64_t collections; // garbage collections - int64_t units; - - } stats; - -public: - Checker (Internal *); - virtual ~Checker (); - - void connect_internal (Internal *i) override; - - void add_original_clause (int64_t, bool, const vector &, - bool = false) override; - void add_derived_clause (int64_t, bool, const vector &, - const vector &) override; - void delete_clause (int64_t, bool, const vector &) override; - - void finalize_clause (int64_t, const vector &) override {} // skip - void report_status (int, int64_t) override {} // skip - void begin_proof (int64_t) override {} // skip - void add_assumption_clause (int64_t, const vector &, - const vector &) override; - void print_stats () override; - void dump (); // for debugging purposes only -}; - -} // namespace CaDiCaL - -ABC_NAMESPACE_CXX_HEADER_END - -#endif diff --git a/src/sat/cadical/clause.hpp b/src/sat/cadical/clause.hpp deleted file mode 100644 index e5d0290f6..000000000 --- a/src/sat/cadical/clause.hpp +++ /dev/null @@ -1,194 +0,0 @@ -#ifndef _clause_hpp_INCLUDED -#define _clause_hpp_INCLUDED - -#include "global.h" - -#include "util.hpp" -#include -#include -#include - -ABC_NAMESPACE_CXX_HEADER_START - -namespace CaDiCaL { - -/*------------------------------------------------------------------------*/ - -typedef int *literal_iterator; -typedef const int *const_literal_iterator; - -/*------------------------------------------------------------------------*/ - -// The 'Clause' data structure is very important. There are usually many -// clauses and accessing them is a hot-spot. Thus we use common -// optimizations to reduce memory and improve cache usage, even though this -// induces some complexity in understanding the code. -// -// The most important optimization is to 'embed' the actual literals in the -// clause. This requires a variadic size structure and thus strictly is not -// 'C' conform, but supported by all compilers we used. The alternative is -// to store the actual literals somewhere else, which not only needs more -// memory but more importantly also requires another memory access and thus -// is very costly. - -struct Clause { - union { - int64_t id; // Used to create LRAT-style proofs - Clause *copy; // Only valid if 'moved', then that's where to. - // - // The 'copy' field is only valid for 'moved' clauses in the moving - // garbage collector 'copy_non_garbage_clauses' for keeping clauses - // compactly in a contiguous memory arena. Otherwise, so almost all of - // the time, 'id' is valid. See 'collect.cpp' for details. - }; - bool conditioned : 1; // Tried for globally blocked clause elimination. - bool covered : 1; // Already considered for covered clause elimination. - bool enqueued : 1; // Enqueued on backward queue. - bool frozen : 1; // Temporarily frozen (in covered clause elimination). - bool garbage : 1; // can be garbage collected unless it is a 'reason' - bool gate : 1; // Clause part of a gate (function definition). - bool hyper : 1; // redundant hyper binary or ternary resolved - bool instantiated : 1; // tried to instantiate - bool moved : 1; // moved during garbage collector ('copy' valid) - bool reason : 1; // reason / antecedent clause can not be collected - bool redundant : 1; // aka 'learned' so not 'irredundant' (original) - bool transred : 1; // already checked for transitive reduction - bool subsume : 1; // not checked in last subsumption round - bool swept : 1; // clause used to sweep equivalences - bool flushed : 1; // garbage in proof deleted binaries - unsigned used : 8; // resolved in conflict analysis since last 'reduce' - bool vivified : 1; // clause already vivified - bool vivify : 1; // clause scheduled to be vivified - - // The glucose level ('LBD' or short 'glue') is a heuristic value for the - // expected usefulness of a learned clause, where smaller glue is consider - // more useful. During learning the 'glue' is determined as the number of - // decisions in the learned clause. Thus the glue of a clause is a strict - // upper limit on the smallest number of decisions needed to make it - // propagate. For instance a binary clause will propagate if one of its - // literals is set to false. Similarly a learned clause with glue 1 can - // propagate after one decision, one with glue 2 after 2 decisions etc. - // In some sense the glue is an abstraction of the size of the clause. - // - // See the IJCAI'09 paper by Audemard & Simon for more details. We - // switched back and forth between keeping the glue stored in a clause and - // using it only initially to determine whether it is kept, that is - // survives clause reduction. The latter strategy is not bad but also - // does not allow to use glue values for instance in 'reduce'. - // - // More recently we also update the glue and promote clauses to lower - // level tiers during conflict analysis. The idea of using three tiers is - // also due to Chanseok Oh and thus used in all recent 'Maple...' solvers. - // Tier one are the always kept clauses with low glue at most - // 'opts.reducetier1glue' (default '2'). The second tier contains all - // clauses with glue larger than 'opts.reducetier1glue' but smaller or - // equal than 'opts.reducetier2glue' (default '6'). The third tier - // consists of clauses with glue larger than 'opts.reducetier2glue'. - // - // Clauses in tier one are not deleted in 'reduce'. Clauses in tier - // two require to be unused in two consecutive 'reduce' intervals before - // being collected while for clauses in tier three not being used since - // the last 'reduce' call makes them deletion candidates. Clauses derived - // by hyper binary or ternary resolution (even though small and thus with - // low glue) are always removed if they remain unused during one interval. - // See 'mark_useless_redundant_clauses_as_garbage' in 'reduce.cpp' and - // 'bump_clause' in 'analyze.cpp'. - // - int glue; - - int size; // Actual size of 'literals' (at least 2). - int pos; // Position of last watch replacement [Gent'13]. - - // This 'flexible array member' is of variadic 'size' (and actually - // shrunken if strengthened) and keeps the literals close to the header of - // the clause to avoid another pointer dereference, which would be costly. - - // In earlier versions we used 'literals[2]' to fake it (in order to - // support older Microsoft compilers even though this feature is in C99) - // and at the same time being able to overlay the first two literals with - // the 'copy' field above, as having a flexible array member inside a - // union is not allowed. Now compilers start to figure out that those - // literals can be accessed with indices larger than 1 and produce - // warnings. After having the 'id' field mandatory we now overlay that - // one with the copy field. - - // However, it turns out that even though flexible array members are in - // C99 they are not in C11++, and therefore pedantic compilation with - // '--pedantic' fails completely. Therefore we still support as - // alternative faked flexible array members, which unfortunately need - // then again more care when accessing the literals outside the faked - // virtual sizes and the compiler can somehow figure that out, because - // that would in turn produce a warning. - -#ifndef NFLEXIBLE - int literals[]; -#else - int literals[2]; -#endif - - // Supports simple range based for loops over clauses. - - literal_iterator begin () { return literals; } - literal_iterator end () { return literals + size; } - - const_literal_iterator begin () const { return literals; } - const_literal_iterator end () const { return literals + size; } - - static size_t bytes (int size) { - - // Memory sanitizer insists that clauses put into consecutive memory in - // the arena are still 8 byte aligned. We could also allocate 8 byte - // aligned memory there. However, assuming the real memory foot print - // of a clause is 8 bytes anyhow, we just allocate 8 byte aligned memory - // all the time (even if allocated outside of the arena). - // - CADICAL_assert (size > 1); - const size_t header_bytes = sizeof (Clause); - const size_t actual_literal_bytes = size * sizeof (int); - size_t combined_bytes = header_bytes + actual_literal_bytes; -#ifdef NFLEXIBLE - const size_t faked_literals_bytes = sizeof ((Clause *) 0)->literals; - combined_bytes -= faked_literals_bytes; -#endif - size_t aligned_bytes = align (combined_bytes, 8); - return aligned_bytes; - } - - size_t bytes () const { return bytes (size); } - - // Check whether this clause is ready to be collected and deleted. The - // 'reason' flag is only there to protect reason clauses in 'reduce', - // which does not backtrack to the root level. If garbage collection is - // triggered from a preprocessor, which backtracks to the root level, then - // 'reason' is false for sure. We want to use the same garbage collection - // code though for both situations and thus hide here this variance. - // - bool collect () const { return !reason && garbage; } -}; - -struct clause_smaller_size { - bool operator() (const Clause *a, const Clause *b) { - return a->size < b->size; - } -}; - -/*------------------------------------------------------------------------*/ - -// Place literals over the same variable close to each other. This would -// allow eager removal of identical literals and detection of tautological -// clauses but is only currently used for better logging (see also -// 'opts.logsort' in 'logging.cpp'). - -struct clause_lit_less_than { - bool operator() (int a, int b) const { - using namespace std; - int s = abs (a), t = abs (b); - return s < t || (s == t && a < b); - } -}; - -} // namespace CaDiCaL - -ABC_NAMESPACE_CXX_HEADER_END - -#endif diff --git a/src/sat/cadical/config.hpp b/src/sat/cadical/config.hpp deleted file mode 100644 index d49b05c84..000000000 --- a/src/sat/cadical/config.hpp +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef _config_hpp_INCLUDED -#define _config_hpp_INCLUDED - -#include "global.h" - -ABC_NAMESPACE_CXX_HEADER_START - -namespace CaDiCaL { - -class Options; - -struct Config { - - static bool has (const char *); - static bool set (Options &, const char *); - static void usage (); - - static const char **begin (); - static const char **end (); -}; - -} // namespace CaDiCaL - -ABC_NAMESPACE_CXX_HEADER_END - -#endif diff --git a/src/sat/cadical/congruence.hpp b/src/sat/cadical/congruence.hpp deleted file mode 100644 index e0acf9b00..000000000 --- a/src/sat/cadical/congruence.hpp +++ /dev/null @@ -1,720 +0,0 @@ -#ifndef _congruenc_hpp_INCLUDED -#define _congruenc_hpp_INCLUDED - -#include "global.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "clause.hpp" -#include "inttypes.hpp" -#include "util.hpp" -#include "watch.hpp" - -ABC_NAMESPACE_CXX_HEADER_START - -namespace CaDiCaL { - -typedef int64_t LRAT_ID; - -// This implements the algorithm algorithm from SAT 2024. -// -// The idea is to: -// 0. handle binary clauses -// 1. detect gates and merge gates with same inputs ('lazy') -// 2. eagerly replace the equivalent literals and merge gates with same -// inputs -// 3. forward subsume -// -// In step 0 the normalization is fully lazy but we do not care about a -// normal form. Therefore we actually eagerly merge literals. -// -// In step 2 there is a subtility: we only replace with the equivalence -// chain as far as we propagated so far. This is the eager part. For LRAT we -// produce the equivalence up to the point we have propagated, no the full -// chain. This is important for merging literals. To merge literals we use -// union-find but we only compress paths when rewriting the literal, not -// before. The compression was not considered important in Kissat, but we do -// it aggressively as a mirror of the equivalences we have generated. -// -// We have two structures for merging: -// - the lazy ones contains alls merges, with functions like -// find_representative -// -// - the eager version that gets the merges one by one, with functions -// like find_eager_representatives -// -// The two structures are nicely separated and we only working on one of -// them except for: -// -// 1. When propagating one equivalence, we first important the -// equivalence from the lazy to the eager version, producing the full -// chain. -// -// 2. When merging the literals, we merge the literals given by the lazy -// structure, then we merge their representative in the eager version, -// updating only the lazy structure. We do not update the eager version. -// -// An important point: We cannot use internal->lrat_chain and -// internal->clause because in most places we can interrupt the -// transformation to learn a new clause representing an equivalence. -// However, we can only have 2 layers so we use this->lrat_chain and -// internal->lrat_chain when we really produce the proof. -struct Internal; - -#define LD_MAX_ARITY 26 -#define MAX_ARITY ((1 << LD_MAX_ARITY) - 1) - -enum class Gate_Type { And_Gate, XOr_Gate, ITE_Gate }; - -// Wrapper when we are looking for implication in if-then-else gates -struct lit_implication { - int first; - int second; - Clause *clause; - lit_implication (int f, int s, Clause *_id) - : first (f), second (s), clause (_id) {} - lit_implication (int f, int s) : first (f), second (s), clause (0) {} - lit_implication () : first (0), second (0), clause (nullptr) {} - void swap () { std::swap (first, second); } -}; - -// Wrapper when we are looking for equivalence for if-then-else-gate. They -// are produced by merging implication -struct lit_equivalence { - int first; - int second; - Clause *first_clause; - Clause *second_clause; - void check_invariant () { - CADICAL_assert (second_clause); - CADICAL_assert (first_clause); - CADICAL_assert (std::find (begin (*first_clause), end (*first_clause), first) != - end (*first_clause)); - CADICAL_assert (std::find (begin (*second_clause), end (*second_clause), - second) != end (*second_clause)); - CADICAL_assert (std::find (begin (*first_clause), end (*first_clause), - -second) != end (*first_clause)); - CADICAL_assert (std::find (begin (*second_clause), end (*second_clause), - -first) != end (*second_clause)); - } - lit_equivalence (int f, Clause *f_id, int s, Clause *s_id) - : first (f), second (s), first_clause (f_id), second_clause (s_id) {} - lit_equivalence (int f, int s) - : first (f), second (s), first_clause (nullptr), - second_clause (nullptr) {} - lit_equivalence () - : first (0), second (0), first_clause (nullptr), - second_clause (nullptr) {} - lit_equivalence swap () { - std::swap (first, second); - std::swap (first_clause, second_clause); - return *this; - } - lit_equivalence negate_both () { - first = -first; - second = -second; - std::swap (first_clause, second_clause); - return *this; - } -}; - -typedef std::vector lit_implications; -typedef std::vector lit_equivalences; - -std::string string_of_gate (Gate_Type t); - -struct LitClausePair { - int current_lit; // current literal from the gate - Clause *clause; - LitClausePair (int lit, Clause *cl) : current_lit (lit), clause (cl) {} - LitClausePair () : current_lit (0), clause (nullptr) {} -}; -struct LitIdPair { - int lit; // current literal from the gate - LRAT_ID id; - LitIdPair (int l, LRAT_ID i) : lit (l), id (i) {} - LitIdPair () : lit (0), id (0) {} -}; - -/*------------------------------------------------------------------------*/ - -// Sorting the scheduled clauses is way faster if we compute and save the -// clause size in the schedule to avoid pointer access to clauses during -// sorting. This slightly increases the schedule size though. - -struct ClauseSize { - size_t size; - Clause *clause; - ClauseSize (int s, Clause *c) : size (s), clause (c) {} - ClauseSize (Clause *c): size (c->size), clause (c) {} - ClauseSize () {} -}; - -struct smaller_clause_size_rank { - typedef size_t Type; - Type operator() (const ClauseSize &a) { return a.size; } -}; - -/*------------------------------------------------------------------------*/ -// There are many special cases for ITE gates and we have to keep track of -// them as it is a gate property (rewriting might not make it obvious -// anymore). -// a = (a ? t : e) results in no -t and no +e gate (a --> a = t == (-a v -a v t) & (-a v a v -t)) -// a = (-a ? t : e) results in no +t and no -e gate -// a = (c ? a : e) results in no t gate (none of them) -// a = (c ? t : a) results in no e gate (none of them) - -enum Special_ITE_GATE { - NORMAL = 0, - NO_PLUS_THEN = (1 << 0), - NO_NEG_THEN = (1 << 1), - NO_THEN = NO_PLUS_THEN + NO_NEG_THEN, - NO_PLUS_ELSE = (1 << 2), - NO_NEG_ELSE = (1 << 3), - NO_ELSE = NO_PLUS_ELSE + NO_NEG_ELSE, - COND_LHS = NO_NEG_THEN + NO_PLUS_ELSE, - UCOND_LHS = NO_PLUS_THEN + NO_NEG_ELSE, -}; - -inline bool ite_flags_no_then_clauses (int8_t flag) { - return (flag & NO_THEN) == NO_THEN; -} - -inline bool ite_flags_no_else_clauses (int8_t flag) { - return (flag & NO_ELSE) == NO_ELSE; -} - -inline bool ite_flags_neg_cond_lhs (int8_t flag) { - return (flag & UCOND_LHS) == UCOND_LHS; -} - -inline bool ite_flags_cond_lhs (int8_t flag) { - return (flag & COND_LHS) == COND_LHS; -} - -/*------------------------------------------------------------------------*/ - -// The core structure of this algorithm: the gate. It is composed of a -// left-hand side and an array of right-hand side. -// -// There are a few tags to help remembering the status of the gate (like -// deleted) -// -// To keep track of the proof we use two extra arrays: -// - `neg_lhs_ids' contains the long clause for AND gates. Otherwise, it is -// empty. TODO: change to std::option as it contains at most one element -// - `pos_lhs_ids' contains all the remaining gates. -// -// We keep the reasons with an index. This index depends on the gates: - -// - AND-Gates and ITE-Gates: the index is the literal from the RHS -// -// - XOR-Gates: if you order the clauses by the order of the literals, -// each literal is either positive (bit '1') or negative (bit '0'). This -// gives a number that we can use. -// -// TODO Florian: I do not think that you have to changed anything, look at -// the 'Look at this first' in the CPP file. -// -// Important for the proofs: the LHS is not updated. -// -// TODO: we currently use a vector for the rhs, but we could also use FMA -// and inline the structure to avoid any indirection. -// -// One warning for degenerated gate: it is a monotone property on the -// defining clauses, but not on the LHS/RHS as the LHS is not rewritten: -// take 4 = AND 3 4 (degenerated with only the clause -4 3) with a rewriting -// 4 -> 1 (unchanged clause) and later 1 -> 3 (unchanged clause) but you do -// not know anymore from the gate that it is degenerated -struct Gate { -#ifdef LOGGING - uint64_t id; -#endif - int lhs; - Gate_Type tag; - bool garbage : 1; - bool indexed : 1; - bool marked : 1; - bool shrunken : 1; - size_t hash; // TODO remove this field (the C++ implementation is caching - // it anyway) - vector pos_lhs_ids; - vector neg_lhs_ids; - bool degenerated_and_neg = false; // LRAT only relevant for AND Gates, neg lhs in RHS - bool degenerated_and_pos = false; // LRAT only relevant for AND Gates, pos lhs in RHS - int8_t degenerated_ite = Special_ITE_GATE::NORMAL; - vector rhs; - - size_t arity () const { return rhs.size (); } - - bool operator== (Gate const &lhs) { - return tag == lhs.tag && hash == lhs.hash && rhs == lhs.rhs; - } -}; - -typedef vector GOccs; - -struct GateEqualTo { - bool operator() (const Gate *const lhs, const Gate *const rhs) const { - return lhs->rhs == rhs->rhs && lhs->tag == rhs->tag; - } -}; - -struct CompactBinary { - Clause *clause; - LRAT_ID id; - int lit1, lit2; - CompactBinary (Clause *c, LRAT_ID i, int l1, int l2) - : clause (c), id (i), lit1 (l1), lit2 (l2) {} - CompactBinary () : clause (nullptr), id (0), lit1 (0), lit2 (0) {} -}; - -struct Hash { - Hash (std::array &ncs) : nonces (ncs) {} - std::array &nonces; - size_t operator() (const Gate *const g) const; -}; - -struct Rewrite { - int src, dst; - LRAT_ID id1; - LRAT_ID id2; - - Rewrite (int _src, int _dst, LRAT_ID _id1, LRAT_ID _id2) - : src (_src), dst (_dst), id1 (_id1), id2 (_id2) {} - Rewrite () : src (0), dst (0), id1 (0), id2 (0) {} -}; - -struct Closure { - - Closure (Internal *i); - - Internal *const internal; - vector extra_clauses; - vector binaries; - std::vector> offsetsize; - bool full_watching = false; - std::array nonces; - typedef unordered_set GatesTable; - - vector scheduled; - vector marks; - vector mu1_ids, mu2_ids, - mu4_ids; // remember the ids and the literal. 2 and 4 are - // only used for lrat proofs, but we need 1 to - // promote binary clauses to irredundant - - vector lits; // result of definitions - vector rhs; // stack for storing RHS - vector unsimplified; // stack for storing unsimplified version (XOR, - // ITEs) for DRAT proof - vector chain; // store clauses to be able to delete them properly - vector clause; // storing partial clauses - vector - glargecounts; // count for large clauses to complement internal->noccs - vector gnew_largecounts; // count for large clauses to - // complement internal->noccs - GatesTable table; - std::array condbin; - std::array condeq; - - std::vector new_unwatched_binary_clauses; - // LRAT proofs - vector resolvent_analyzed; - mutable vector lrat_chain; // storing LRAT chain - -#ifdef LOGGING - uint64_t fresh_id; -#endif - - uint64_t &new_largecounts (int lit); - uint64_t &largecounts (int lit); - - void unmark_all (); - vector representant; // union-find - vector eager_representant; // union-find - vector representant_id; // lrat version of union-find - vector eager_representant_id; // lrat version of union-find - int &representative (int lit); - int representative (int lit) const; - LRAT_ID &representative_id (int lit); - LRAT_ID representative_id (int lit) const; - int &eager_representative (int lit); - int eager_representative (int lit) const; - LRAT_ID &eager_representative_id (int lit); - LRAT_ID eager_representative_id (int lit) const; - std::vector lazy_propagated_idx; - char &lazy_propagated (int lit); - - int find_lrat_representative_with_marks (int lit); - // representative in the union-find structure in the lazy equivalences - int find_representative (int lit); - // find the representative and produce the binary clause representing the - // normalization from the literal to the result. - int find_representative_and_compress (int, bool update_eager = true); - // find the lazy representative for the `lit' and `-lit' - void find_representative_and_compress_both (int); - // find the eager representative - int find_eager_representative (int); - - // compreses the path from lit to the representative with a new clause if - // needed. Save internal->lrat_chain to avoid any issue. - int find_eager_representative_and_compress (int); - // Import the path from the literal and its negation to the representative - // in the lazy graph to the eager part, producing the binary clauses. - void import_lazy_and_find_eager_representative_and_compress_both ( - int); // generates clauses for -lit and lit - - // returns the ID of the LRAT clause for the normalization from the - // literal lit to its argument, assuming that the representative was - // already compressed. - LRAT_ID find_representative_lrat (int lit); - // returns the ID of the LRAT clause for the eager normalization from the - // literal lit to its argument assuming that the representative was - // already compressed. - LRAT_ID find_eager_representative_lrat (int lit); - - // Writes the LRAT chain required for the eager normalization to - // `lrat_chain`. - void produce_eager_representative_lrat (int lit); - // Writes the LRAT chain required for the lazy normalization to - // `lrat_chain`. - void produce_representative_lrat (int lit); - - // learns a binary clause if not unit - Clause *maybe_add_binary_clause (int a, int b); - // add binary clause - Clause *add_binary_clause (int a, int b); - // add tmp clause - Clause *add_tmp_binary_clause (int a, int b); - // add clause taking core of tmp or full - Clause *learn_binary_tmp_or_full_clause (int a, int b); - - // promotes a clause from redundant to irredundant. We do this for all - // clauses involved in gates to make sure that we produce correct result. - void promote_clause (Clause *); - - // Merge functions. We actually need different several versions for LRAT - // in order to simplify the proof production. - // - // When merging binary clauses, we can simply produce the LRAT chain by - // (1) using the two binary clauses and (2) the reason clause from the - // literals to the representatives. - // - // The same approach does not work for merging gates because the - // representative might be also a representative of another literal - // (because of eager rewriting), requiring to resolve more than once on - // the same literal. An example of this are the two gates 4=-2&7 and - // 6=-2&1, the rewriting 7=1 and the equivalence 4=1. The simple road of - // merging 6 and 4 (requires resolving away 1) + adding the rewrite 4 to 1 - // (requires adding 1) does not work. - // - // Therefore, we actually go for the more regular road and produce two - // equivalence: the merge from the LHS, followed by the actual equivalence - // (by combining it with the rewrite). In DRAT this is less important - // because the checker finds a chain and is less restricted than our LRAT - // chain. - bool merge_literals_equivalence (int lit, int other, Clause *c1, - Clause *c2); - bool merge_literals_lrat (Gate *g, Gate *h, int lit, int other, - const std::vector & = {}, - const std::vector & = {}); - bool merge_literals_lrat (int lit, int other, - const std::vector & = {}, - const std::vector & = {}); - - // proof production - vector lrat_chain_and_gate; - void push_lrat_id (const Clause *const c, int lit); - void push_lrat_unit (int lit); - - // pushes the clause with the reasons to rewrite clause - // unless: - // - the rewriting is not necessary (resolvent_marked == 1) - // - it is overwritten by one of the arguments - void push_id_and_rewriting_lrat_unit (Clause *c, Rewrite rewrite1, - std::vector &chain, - bool = true, - Rewrite rewrite2 = Rewrite (), - int execept_lhs = 0, - int except_lhs2 = 0); - void push_id_and_rewriting_lrat_full (Clause *c, Rewrite rewrite1, - std::vector &chain, - bool = true, - Rewrite rewrite2 = Rewrite (), - int execept_lhs = 0, - int except_lhs2 = 0); - // TODO: does nothing except pushing on the stack, remove! - void push_id_on_chain (std::vector &chain, Clause *c); - // TODO: does nothing except pushing on the stack, remove! - void push_id_on_chain (std::vector &chain, - const std::vector &c); - // TODO: does nothing except pushing on the stack, remove! - void push_id_on_chain (std::vector &chain, Rewrite rewrite, int); - void update_and_gate_build_lrat_chain ( - Gate *g, Gate *h, std::vector &extra_reasons_lit, - std::vector &extra_reasons_ulit, bool remove_units = true); - void update_and_gate_unit_build_lrat_chain ( - Gate *g, int src, LRAT_ID id1, LRAT_ID id2, int dst, - std::vector &extra_reasons_lit, - std::vector &extra_reasons_ulit); - // occs - vector gtab; - GOccs &goccs (int lit); - void connect_goccs (Gate *g, int lit); - vector garbage; - void mark_garbage (Gate *); - // remove the gate from the table - bool remove_gate (Gate *); - bool remove_gate (GatesTable::iterator git); - void index_gate (Gate *); - - // second counter for size, complements noccs - uint64_t &largecount (int lit); - - // simplification - bool skip_and_gate (Gate *g); - bool skip_xor_gate (Gate *g); - void update_and_gate (Gate *g, GatesTable::iterator, int src, int dst, - LRAT_ID id1, LRAT_ID id2, int falsified = 0, - int clashing = 0); - void update_xor_gate (Gate *g, GatesTable::iterator); - void shrink_and_gate (Gate *g, int falsified = 0, int clashing = 0); - bool simplify_gate (Gate *g); - void simplify_and_gate (Gate *g); - void simplify_ite_gate (Gate *g); - Clause *simplify_xor_clause (int lhs, Clause *); - void simplify_xor_gate (Gate *g); - bool simplify_gates (int lit); - void simplify_and_sort_xor_lrat_clauses (const vector &, - vector &, int, - int except2 = 0, bool flip = 0); - void simplify_unit_xor_lrat_clauses (const vector &, int); - - // rewriting - bool rewriting_lhs (Gate *g, int dst); - bool rewrite_gates (int dst, int src, LRAT_ID id1, LRAT_ID id2); - bool rewrite_gate (Gate *g, int dst, int src, LRAT_ID id1, LRAT_ID id2); - void rewrite_xor_gate (Gate *g, int dst, int src); - void rewrite_and_gate (Gate *g, int dst, int src, LRAT_ID id1, - LRAT_ID id2); - void rewrite_ite_gate (Gate *g, int dst, int src); - - size_t units; // next trail position to propagate - bool propagate_unit (int lit); - bool propagate_units (); - size_t propagate_units_and_equivalences (); - bool propagate_equivalence (int lit); - - // gates - void init_closure (); - void reset_closure (); - void reset_extraction (); - void reset_and_gate_extraction (); - void extract_and_gates (Closure &); - void extract_gates (); - void extract_and_gates_with_base_clause (Clause *c); - void init_and_gate_extraction (); - Gate *find_first_and_gate (Clause *base_clause, int lhs); - Gate *find_remaining_and_gate (Clause *base_clause, int lhs); - void extract_and_gates (); - - Gate *find_and_lits (const vector &rhs, Gate *except = nullptr); - // rhs is sorted, so passing by copy - Gate *find_gate_lits (const vector &rhs, Gate_Type typ, - Gate *except = nullptr); - Gate *find_xor_lits (const vector &rhs); - // not const to normalize negations, also fixes the order of the LRAT - Gate *find_ite_gate (Gate *, bool &); - Gate *find_xor_gate (Gate *); - - void reset_xor_gate_extraction (); - void init_xor_gate_extraction (std::vector &candidates); - LRAT_ID check_and_add_to_proof_chain (vector &clause); - void add_xor_matching_proof_chain (Gate *g, int lhs1, - const vector &, - int lhs2, vector &, - vector &); - void add_xor_shrinking_proof_chain (Gate *g, int src); - void extract_xor_gates (); - void extract_xor_gates_with_base_clause (Clause *c); - Clause *find_large_xor_side_clause (std::vector &lits); - - void merge_condeq (int cond, lit_equivalences &condeq, - lit_equivalences ¬_condeq); - void find_conditional_equivalences (int lit, lit_implications &condbin, - lit_equivalences &condeq); - void copy_conditional_equivalences (int lit, lit_implications &condbin); - void check_ite_implied (int lhs, int cond, int then_lit, int else_lit); - void check_ite_gate_implied (Gate *g); - void check_and_gate_implied (Gate *g); - void check_ite_lrat_reasons (Gate *g, bool = false); - void check_contained_module_rewriting (Clause *c, int lit, bool, - int except); - void delete_proof_chain (); - - // ite gate extraction - void extract_ite_gates_of_literal (int); - void extract_ite_gates_of_variable (int idx); - void extract_condeq_pairs (int lit, lit_implications &condbin, - lit_equivalences &condeq); - void init_ite_gate_extraction (std::vector &candidates); - lit_implications::const_iterator find_lit_implication_second_literal ( - int lit, lit_implications::const_iterator begin, - lit_implications::const_iterator end); - void search_condeq (int lit, int pos_lit, - lit_implications::const_iterator pos_begin, - lit_implications::const_iterator pos_end, int neg_lit, - lit_implications::const_iterator neg_begin, - lit_implications::const_iterator neg_end, - lit_equivalences &condeq); - void reset_ite_gate_extraction (); - void extract_ite_gates (); - - void forward_subsume_matching_clauses (); - - void extract_congruence (); - - void add_ite_matching_proof_chain (Gate *g, Gate *h, int lhs1, int lhs2, - std::vector &reasons1, - std::vector &reasons2); - void add_ite_turned_and_binary_clauses (Gate *g); - Gate *new_and_gate (Clause *, int); - Gate *new_ite_gate (int lhs, int cond, int then_lit, int else_lit, - std::vector &&clauses); - Gate *new_xor_gate (const vector &, int); - // check - void check_xor_gate_implied (Gate const *const); - void check_ternary (int a, int b, int c); - void check_binary_implied (int a, int b); - void check_implied (); - - // learn units. You can delay units if you want to learn several at once before - // propagation. Otherwise, propagate! If you need propagation even if nothing is set, use the - // second parameter. - // - // The function can also learn the empty clause if the unit is already set. Do not add the unit in - // the chain! - bool learn_congruence_unit (int unit, bool = false, bool = false); - bool fully_propagate (); - void learn_congruence_unit_falsifies_lrat_chain (Gate *g, int src, - int dst, - int clashing, - int falsified, int unit); - void learn_congruence_unit_when_lhs_set (Gate *g, int src, LRAT_ID id1, - LRAT_ID id2, int dst); - - void find_units (); - void find_equivalences (); - void subsume_clause (Clause *subsuming, Clause *subsumed); - bool find_subsuming_clause (Clause *c); - void produce_rewritten_clause_lrat_and_clean (vector &, - int execept_lhs = 0, - bool = true); - // rewrite the clause using eager rewriting and rew1 and rew2, except for - // 2 literals Usage: - // - the except are used to ignore LHS of gates that have not and should - // not be rewritten. - // - TODO: except_lhs2 should never be used actually - // - the Rewrite are for additional rewrite to allow for lazy rewrites - // to be taken into account without being added to the eager rewriting - // (yet) - Clause *produce_rewritten_clause_lrat (Clause *c, int execept_lhs = 0, - bool remove_units = true, bool = true); - void produce_rewritten_clause_lrat (vector &, - int execept_lhs = 0, - bool = true); - void compute_rewritten_clause_lrat_simple (Clause *c, int except); - // variant where we update the indices after removing the tautologies and - // remove the tautological clauses - void produce_rewritten_clause_lrat_and_clean ( - std::vector &litIds, int except_lhs, - size_t &old_position1, size_t &old_position2, - bool remove_units = true); - // binary extraction and ternary strengthening - void extract_binaries (); - bool find_binary (int, int) const; - - Clause *new_tmp_clause (std::vector &clause); - Clause *maybe_promote_tmp_binary_clause (Clause *); - void check_not_tmp_binary_clause (Clause *c); - Clause *new_clause (); - // - void sort_literals_by_var (vector &rhs); - void sort_literals_by_var_except (vector &rhs, int, int except2 = 0); - - // schedule - queue schedule; - void schedule_literal (int lit); - void add_clause_to_chain (std::vector, LRAT_ID); - // proof. If delete_id is non-zero, then delete the clause instead of - // learning it - LRAT_ID simplify_and_add_to_proof_chain (vector &unsimplified, - LRAT_ID delete_id = 0); - - // we define our own wrapper as cadical has otherwise a non-compatible - // marking system - signed char &marked (int lit); - void set_mu1_reason (int lit, Clause *c); - void set_mu2_reason (int lit, Clause *c); - void set_mu4_reason (int lit, Clause *c); - LitClausePair marked_mu1 (int lit); - LitClausePair marked_mu2 (int lit); - LitClausePair marked_mu4 (int lit); - - // XOR - uint32_t number_from_xor_reason_reversed (const std::vector &rhs); - uint32_t number_from_xor_reason (const std::vector &rhs, int, - int except2 = 0, bool flip = 0); - void gate_sort_lrat_reasons (std::vector &, int, - int except2 = 0, bool flip = 0); - void gate_sort_lrat_reasons (LitClausePair &, int, int except2 = 0, - bool flip = 0); - - bool rewrite_ite_gate_to_and (Gate *g, int dst, int src, size_t c, - size_t d, int cond_lit_to_learn_if_degenerated); - void produce_ite_merge_then_else_reasons ( - Gate *g, int dst, int src, std::vector &reasons_implication, - std::vector &reasons_back); - void produce_ite_merge_lhs_then_else_reasons ( - Gate *g, std::vector &reasons_implication, - std::vector &reasons_back, - std::vector &reasons_unit, bool, bool &); - void rewrite_ite_gate_update_lrat_reasons (Gate *g, int src, int dst); - void simplify_ite_gate_produce_unit_lrat (Gate *g, int lit, size_t idx1, - size_t idx2); - void merge_and_gate_lrat_produce_lrat ( - Gate *g, Gate *h, std::vector &reasons_lrat, - std::vector &reasons_lrat_back, bool remove_units = true); - // first index is a binary clause after unit propagation and the second - // has length 3 - bool simplify_ite_gate_to_and (Gate *g, size_t idx1, size_t idx2, - int removed); - void - merge_ite_gate_same_then_else_lrat (std::vector &clauses, - std::vector &reasons_implication, - std::vector &reasons_back); - void simplify_ite_gate_then_else_set ( - Gate *g, std::vector &reasons_implication, - std::vector &reasons_back, size_t idx1, size_t idx2); - - void simplify_ite_gate_condition_set ( - Gate *g, std::vector &reasons_lrat, - std::vector &reasons_back_lrat, size_t idx1, size_t idx2); - bool normalize_ite_lits_gate (Gate *rhs); -}; - -} // namespace CaDiCaL - -ABC_NAMESPACE_CXX_HEADER_END - -#endif diff --git a/src/sat/cadical/contract.hpp b/src/sat/cadical/contract.hpp deleted file mode 100644 index 4a3ba066a..000000000 --- a/src/sat/cadical/contract.hpp +++ /dev/null @@ -1,142 +0,0 @@ -#ifndef _contract_hpp_INCLUDED -#define _contract_hpp_INCLUDED - -#include "global.h" - -ABC_NAMESPACE_CXX_HEADER_START - -/*------------------------------------------------------------------------*/ -#ifndef CADICAL_NCONTRACTS -/*------------------------------------------------------------------------*/ - -// If the user violates API contracts while calling functions declared in -// 'cadical.hpp' and implemented in 'solver.cpp' then an error is reported. -// Currently we also force aborting the program. In the future it might be -// better to allow the user to provide a call back function, which then can -// for instance throw a C++ exception or execute a 'longjmp' in 'C' etc. - -#define CONTRACT_VIOLATED(...) \ - do { \ - fatal_message_start (); \ - fprintf (stderr, \ - "invalid API usage of '%s' in '%s': ", __PRETTY_FUNCTION__, \ - __FILE__); \ - fprintf (stderr, __VA_ARGS__); \ - fputc ('\n', stderr); \ - fflush (stderr); \ - abort (); \ - } while (0) - -/*------------------------------------------------------------------------*/ - -namespace CaDiCaL { - -// It would be much easier to just write 'REQUIRE (this, "not initialized")' -// which however produces warnings due to the '-Wnonnull' check. Note, that -// 'this' is always assumed to be non zero in modern C++. Much worse, if we -// use instead 'this != 0' or something similar like 'this != nullptr' then -// optimization silently removes this check ('gcc-7.4.0' at least) even -// though of course a zero pointer might be used as 'this' if the user did -// not initialize it. The only solution I found is to disable optimization -// for this check. It does not seem to be necessary for 'clang++' though -// ('clang++-6.0.0' at least). The alternative is to not check that the -// user forgot to initialize the solver pointer, but as long this works we -// keep this ugly hack. It also forces the function not to be inlined. -// The actual code I is in 'contract.cpp'. -// -void require_solver_pointer_to_be_non_zero (const void *ptr, - const char *function_name, - const char *file_name); -#define REQUIRE_NON_ZERO_THIS() \ - do { \ - require_solver_pointer_to_be_non_zero (this, __PRETTY_FUNCTION__, \ - __FILE__); \ - } while (0) - -} // namespace CaDiCaL - -/*------------------------------------------------------------------------*/ - -// These are common shortcuts for 'Solver' API contracts (requirements). - -#define REQUIRE(COND, ...) \ - do { \ - if ((COND)) \ - break; \ - CONTRACT_VIOLATED (__VA_ARGS__); \ - } while (0) - -#define REQUIRE_INITIALIZED() \ - do { \ - REQUIRE_NON_ZERO_THIS (); \ - REQUIRE (external, "external solver not initialized"); \ - REQUIRE (internal, "internal solver not initialized"); \ - } while (0) - -#define REQUIRE_VALID_STATE() \ - do { \ - REQUIRE_INITIALIZED (); \ - REQUIRE (this->state () & VALID, "solver in invalid state"); \ - } while (0) - -#define REQUIRE_READY_STATE() \ - do { \ - REQUIRE_VALID_STATE (); \ - REQUIRE (state () != ADDING, \ - "clause incomplete (terminating zero not added)"); \ - } while (0) - -#define REQUIRE_VALID_OR_SOLVING_STATE() \ - do { \ - REQUIRE_INITIALIZED (); \ - REQUIRE (this->state () & (VALID | SOLVING), \ - "solver neither in valid nor solving state"); \ - } while (0) - -#define REQUIRE_VALID_LIT(LIT) \ - do { \ - REQUIRE ((int) (LIT) && ((int) (LIT)) != INT_MIN, \ - "invalid literal '%d'", (int) (LIT)); \ - REQUIRE (external->is_valid_input ((int) (LIT)), \ - "extension variable %d defined by the solver", (int) (LIT)); \ - } while (0) - -#define REQUIRE_STEADY_STATE() \ - do { \ - REQUIRE_INITIALIZED (); \ - REQUIRE (this->state () & STEADY, "solver is not in steady state"); \ - } while (0) - -/*------------------------------------------------------------------------*/ -#else // CADICAL_NCONTRACTS -/*------------------------------------------------------------------------*/ - -#define REQUIRE(...) \ - do { \ - } while (0) -#define REQUIRE_INITIALIZED() \ - do { \ - } while (0) -#define REQUIRE_VALID_STATE() \ - do { \ - } while (0) -#define REQUIRE_READY_STATE() \ - do { \ - } while (0) -#define REQUIRE_VALID_OR_SOLVING_STATE() \ - do { \ - } while (0) -#define REQUIRE_VALID_LIT(...) \ - do { \ - } while (0) -#define REQUIRE_STEADY_STATE() \ - do { \ - } while (0) - -/*------------------------------------------------------------------------*/ -#endif -/*------------------------------------------------------------------------*/ - -ABC_NAMESPACE_CXX_HEADER_END - -#endif diff --git a/src/sat/cadical/cover.hpp b/src/sat/cadical/cover.hpp deleted file mode 100644 index 47e6f1b82..000000000 --- a/src/sat/cadical/cover.hpp +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef _cover_hpp_INCLUDED -#define _cover_hpp_INCLUDED - -#include "global.h" - -/*------------------------------------------------------------------------*/ - -// This header only provides the 'COVER' macro for testing. It is unrelated -// to 'cover.cpp' which implements covered clause elimination (CCE), but we -// wanted to use the name base name in both cases. More explanation on CCE -// is provided in 'cover.cpp'. - -/*------------------------------------------------------------------------*/ - -// Coverage goal, used similar to 'CADICAL_assert' (but with flipped condition) and -// also included even if 'CADICAL_NDEBUG' is defined (in optimizing compilation). -// -// This should in essence not be used in production code. -// -// There seems to be no problem overloading the name 'COVER' of this macro -// with the constant 'COVER' of 'Internal::Mode' (surprisingly). - -#define COVER(COND) \ - do { \ - if (!(COND)) \ - break; \ - fprintf (stderr, \ - "%scadical%s: %s:%d: %s: Coverage goal %s`%s'%s reached.\n", \ - terr.bold_code (), terr.normal_code (), __FUNCTION__, \ - __LINE__, __FILE__, terr.green_code (), #COND, \ - terr.normal_code ()); \ - fflush (stderr); \ - abort (); \ - } while (0) - -#endif diff --git a/src/sat/cadical/decompose.hpp b/src/sat/cadical/decompose.hpp deleted file mode 100644 index 9c93e8448..000000000 --- a/src/sat/cadical/decompose.hpp +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef _decompose_hpp_INCLUDED -#define _decompose_hpp_INCLUDED - -#include "global.h" - -ABC_NAMESPACE_CXX_HEADER_START - -namespace CaDiCaL { - -// This implements Tarjan's algorithm for decomposing the binary implication -// graph intro strongly connected components (SCCs). Literals in one SCC -// are equivalent and we replace them all by the literal with the smallest -// index in the SCC. These variables are marked 'substituted' and will be -// removed from all clauses. Their value will be fixed during 'extend'. - -#define TRAVERSED UINT_MAX // mark completely traversed - -struct DFS { - unsigned idx; // depth first search index - unsigned min; // minimum reachable index - Clause *parent; // for lrat - DFS () : idx (0), min (0), parent (0) {} -}; - -} // namespace CaDiCaL - -ABC_NAMESPACE_CXX_HEADER_END - -#endif diff --git a/src/sat/cadical/delay.hpp b/src/sat/cadical/delay.hpp deleted file mode 100644 index 9ee9a9234..000000000 --- a/src/sat/cadical/delay.hpp +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef _delay_hpp_INCLUDED -#define _delay_hpp_INCLUDED - -#include "global.h" - -#include -#include - -ABC_NAMESPACE_CXX_HEADER_START - -namespace CaDiCaL { -struct Delay { - unsigned count; - unsigned current; - - Delay () : count (0), current (0) {} - - bool delay () { - if (count) { - --count; - return true; - } else { - return false; - } - } - - void bump_delay () { - current += current < std::numeric_limits::max (); - count = current; - } - - void reduce_delay () { - if (!current) - return; - current /= 2; - count = current; - } -}; - -} // namespace CaDiCaL - -ABC_NAMESPACE_CXX_HEADER_END - -#endif diff --git a/src/sat/cadical/drattracer.hpp b/src/sat/cadical/drattracer.hpp deleted file mode 100644 index 8c2c023d5..000000000 --- a/src/sat/cadical/drattracer.hpp +++ /dev/null @@ -1,59 +0,0 @@ -#ifndef _drattracer_h_INCLUDED -#define _drattracer_h_INCLUDED - -#include "global.h" - -#include "tracer.hpp" - -ABC_NAMESPACE_CXX_HEADER_START - -namespace CaDiCaL { - -class DratTracer : public FileTracer { - - Internal *internal; - File *file; - bool binary; -#ifndef CADICAL_QUIET - int64_t added, deleted; -#endif - void put_binary_zero (); - void put_binary_lit (int external_lit); - - // support DRAT - void drat_add_clause (const vector &); - void drat_delete_clause (const vector &); - -public: - // own and delete 'file' - DratTracer (Internal *, File *file, bool binary); - ~DratTracer (); - - void connect_internal (Internal *i) override; - void begin_proof (int64_t) override {} // skip - - void add_original_clause (int64_t, bool, const vector &, - bool = false) override {} // skip - - void add_derived_clause (int64_t, bool, const vector &, - const vector &) override; - - void delete_clause (int64_t, bool, const vector &) override; - - void finalize_clause (int64_t, const vector &) override {} // skip - - void report_status (int, int64_t) override {} // skip - -#ifndef CADICAL_QUIET - void print_statistics (); -#endif - bool closed () override; - void close (bool) override; - void flush (bool) override; -}; - -} // namespace CaDiCaL - -ABC_NAMESPACE_CXX_HEADER_END - -#endif diff --git a/src/sat/cadical/elim.hpp b/src/sat/cadical/elim.hpp deleted file mode 100644 index 73e1bf547..000000000 --- a/src/sat/cadical/elim.hpp +++ /dev/null @@ -1,59 +0,0 @@ -#ifndef _elim_hpp_INCLUDED -#define _elim_hpp_INCLUDED - -#include "global.h" - -#include "heap.hpp" // Alphabetically after 'elim.hpp'. - -ABC_NAMESPACE_CXX_HEADER_START - -namespace CaDiCaL { - -struct Internal; - -struct elim_more { - Internal *internal; - elim_more (Internal *i) : internal (i) {} - bool operator() (unsigned a, unsigned b); -}; - -typedef heap ElimSchedule; - -struct proof_clause { - int64_t id; - vector literals; - // for lrat - unsigned cid; // cadical_kitten id - bool learned; - vector chain; -}; - -enum GateType { NO = 0, EQUI = 1, AND = 2, ITE = 3, XOR = 4, DEF = 5 }; - -struct Eliminator { - - Internal *internal; - ElimSchedule schedule; - - Eliminator (Internal *i) - : internal (i), schedule (elim_more (i)), definition_unit (0), - gatetype (NO) {} - ~Eliminator (); - - queue backward; - - Clause *dequeue (); - void enqueue (Clause *); - - vector gates; - unsigned definition_unit; - vector proof_clauses; - vector marked; - GateType gatetype; -}; - -} // namespace CaDiCaL - -ABC_NAMESPACE_CXX_HEADER_END - -#endif diff --git a/src/sat/cadical/ema.hpp b/src/sat/cadical/ema.hpp deleted file mode 100644 index 51eb5f8c1..000000000 --- a/src/sat/cadical/ema.hpp +++ /dev/null @@ -1,74 +0,0 @@ -#ifndef _ema_hpp_INCLUDED -#define _ema_hpp_INCLUDED - -#include "global.h" - -#include - -ABC_NAMESPACE_CXX_HEADER_START - -namespace CaDiCaL { - -struct Internal; - -// This is a more complex generic exponential moving average class to -// support more robust initialization (see comments in the 'update' -// implementation). - -struct EMA { - -#ifdef LOGGING - uint64_t updated; -#endif - double value; // unbiased (corrected) moving average - double biased; // biased initialized moving average - double alpha; // input scaling with 'alpha = 1 - beta' - double beta; // decay of 'biased' with 'beta = 1 - alpha' - double exp; // 'exp = pow (beta, updated)' - - EMA () - : -#ifdef LOGGING - updated (0), -#endif - value (0), biased (0), alpha (0), beta (0), exp (0) { - } - - EMA (double a) - : -#ifdef LOGGING - updated (0), -#endif - value (0), biased (0), alpha (a), beta (1 - a), exp (!!beta) { - CADICAL_assert (beta >= 0); - } - - operator double () const { return value; } - void update (Internal *, double y, const char *name); -}; - -} // namespace CaDiCaL - -/*------------------------------------------------------------------------*/ - -// Compact average update and initialization macros for better logging. - -#define UPDATE_AVERAGE(A, Y) \ - do { \ - A.update (internal, (Y), #A); \ - } while (0) - -#define INIT_EMA(E, WINDOW) \ - do { \ - CADICAL_assert ((WINDOW) >= 1); \ - double ALPHA = 1.0 / (double) (WINDOW); \ - E = EMA (ALPHA); \ - LOG ("init " #E " EMA target alpha %g window %d", ALPHA, \ - (int) WINDOW); \ - } while (0) - -/*------------------------------------------------------------------------*/ - -ABC_NAMESPACE_CXX_HEADER_END - -#endif diff --git a/src/sat/cadical/external.hpp b/src/sat/cadical/external.hpp deleted file mode 100644 index 7618fb936..000000000 --- a/src/sat/cadical/external.hpp +++ /dev/null @@ -1,467 +0,0 @@ -#ifndef _external_hpp_INCLUDED -#define _external_hpp_INCLUDED - -#include "global.h" - -/*------------------------------------------------------------------------*/ - -#include "range.hpp" -#include -#include - -/*------------------------------------------------------------------------*/ - -ABC_NAMESPACE_CXX_HEADER_START - -namespace CaDiCaL { - -using namespace std; - -/*------------------------------------------------------------------------*/ - -// The CaDiCaL code is split into three layers: -// -// Solver: facade object providing the actual API of the solver -// External: communication layer between 'Solver' and 'Internal' -// Internal: the actual solver code -// -// Note, that 'Solver' is defined in 'cadical.hpp' and 'solver.cpp', while -// 'External' and 'Internal' in '{external,internal}.{hpp,cpp}'. -// -// Also note, that any user should access the library only through the -// 'Solver' API. For the library internal 'Parser' code we make an -// exception and allow access to both 'External' and 'Internal'. The former -// to enforce the same external to internal mapping of variables and the -// latter for profiling and messages. The same applies to 'App'. -// -// The 'External' class provided here stores the information needed to map -// external variable indices to internal variables (actually literals). -// This is helpful for shrinking the working size of the internal solver -// after many variables become inactive. It will also help to provide -// support for extended resolution in the future, since it allows to -// introduce only internally visible variables (even though we do not know -// how to support generating incremental proofs in this situation yet). -// -// External literals are usually called 'elit' and internal 'ilit'. - -/*------------------------------------------------------------------------*/ - -struct Clause; -struct Internal; -struct CubesWithStatus; - -/*------------------------------------------------------------------------*/ - -/*------------------------------------------------------------------------*/ - -struct External { - - /*==== start of state ==================================================*/ - - Internal *internal; // The actual internal solver. - - int max_var; // External maximum variable index. - size_t vsize; // Allocated external size. - - vector vals; // Current external (extended) assignment. - vector e2i; // External 'idx' to internal 'lit'. - - vector assumptions; // External assumptions. - vector constraint; // External constraint. Terminated by zero. - - vector - ext_units; // External units. Needed to compute LRAT for eclause - vector ext_flags; // to avoid duplicate units - vector eclause; // External version of original input clause. - // The extension stack for reconstructing complete satisfying assignments - // (models) of the original external formula is kept in this external - // solver object. It keeps track of blocked clauses and clauses containing - // eliminated variable. These irredundant clauses are stored in terms of - // external literals on the 'extension' stack after mapping the - // internal literals given as arguments with 'externalize'. - - bool extended; // Have been extended. - bool concluded; - vector extension; // Solution reconstruction extension stack. - - vector witness; // Literal witness on extension stack. - vector tainted; // Literal tainted in adding literals. - - vector ervars; // Variables added through Extended Resolution. - - vector frozentab; // Reference counts for frozen variables. - - // Regularly checked terminator if non-zero. The terminator is set from - // 'Solver::set (Terminator *)' and checked by 'Internal::terminating ()'. - - Terminator *terminator; - - // If there is a learner export learned clauses. - - Learner *learner; - - void export_learned_empty_clause (); - void export_learned_unit_clause (int ilit); - void export_learned_large_clause (const vector &); - - // If there is a listener for fixed assignments. - - FixedAssignmentListener *fixed_listener; - - // If there is an external propagator. - - ExternalPropagator *propagator; - - vector is_observed; // Quick flag for each external variable - - // Saved 'forgettable' original clauses coming from the external - // propagator. The value of the map starts with a Boolean flag indicating - // if the clause is still present or got already deleted, and then - // followed by the literals of the clause. - unordered_map> forgettable_original; - - void add_observed_var (int elit); - void remove_observed_var (int elit); - void reset_observed_vars (); - - bool observed (int elit); - bool is_witness (int elit); - bool is_decision (int elit); - - void force_backtrack (size_t new_level); - - //----------------------------------------------------------------------// - - signed char *solution; // Given solution checking for debugging. - int solution_size; // Given solution checking for debugging. - vector original; // Saved original formula for checking. - - // If 'opts.checkfrozen' is set make sure that only literals are added - // which were never completely molten before. These molten literals are - // marked at the beginning of the 'solve' call. Note that variables - // larger than 'max_var' are not molten and can thus always be used in the - // future. Only needed to check and debug old style freeze semantics. - // - vector moltentab; - - //----------------------------------------------------------------------// - - const Range vars; // Provides safe variable iterations. - - /*==== end of state ====================================================*/ - - // These two just factor out common sanity (CADICAL_assertion) checking code. - - inline int vidx (int elit) const { - CADICAL_assert (elit); - CADICAL_assert (elit != INT_MIN); - int res = abs (elit); - CADICAL_assert (res <= max_var); - return res; - } - - inline int vlit (int elit) const { - CADICAL_assert (elit); - CADICAL_assert (elit != INT_MIN); - CADICAL_assert (abs (elit) <= max_var); - return elit; - } - - inline bool is_valid_input (int elit) { - CADICAL_assert (elit); - CADICAL_assert (elit != INT_MIN); - int eidx = abs (elit); - return eidx > max_var || !ervars[eidx]; - } - - /*----------------------------------------------------------------------*/ - - // The following five functions push individual literals or clauses on the - // extension stack. They all take internal literals as argument, and map - // them back to external literals first, before pushing them on the stack. - - void push_zero_on_extension_stack (); - - // Our general version of extension stacks always pushes a set of witness - // literals (for variable elimination the literal of the eliminated - // literal and for blocked clauses the blocking literal) followed by all - // the clause literals starting with and separated by zero. - // - void push_clause_literal_on_extension_stack (int ilit); - void push_witness_literal_on_extension_stack (int ilit); - - void push_clause_on_extension_stack (Clause *); - void push_clause_on_extension_stack (Clause *, int witness); - void push_binary_clause_on_extension_stack (int64_t id, int witness, - int other); - - // The main 'extend' function which extends an internal assignment to an - // external assignment using the extension stack (and sets 'extended'). - // - void extend (); - void conclude_sat (); - - /*----------------------------------------------------------------------*/ - - // Marking external literals. - - unsigned elit2ulit (int elit) const { - CADICAL_assert (elit); - CADICAL_assert (elit != INT_MIN); - const int idx = abs (elit) - 1; - CADICAL_assert (idx <= max_var); - return 2u * idx + (elit < 0); - } - - bool marked (const vector &map, int elit) const { - const unsigned ulit = elit2ulit (elit); - return ulit < map.size () ? map[ulit] : false; - } - - void mark (vector &map, int elit) { - const unsigned ulit = elit2ulit (elit); - if (ulit >= map.size ()) - map.resize (ulit + 1, false); - map[ulit] = true; - } - - void unmark (vector &map, int elit) { - const unsigned ulit = elit2ulit (elit); - if (ulit < map.size ()) - map[ulit] = false; - } - - /*----------------------------------------------------------------------*/ - - void push_external_clause_and_witness_on_extension_stack ( - const vector &clause, const vector &witness, int64_t id); - - void push_id_on_extension_stack (int64_t id); - - // Restore a clause, which was pushed on the extension stack. - void restore_clause (const vector::const_iterator &begin, - const vector::const_iterator &end, - const int64_t id); - - void restore_clauses (); - - /*----------------------------------------------------------------------*/ - - // Explicitly freeze and melt literals (instead of just freezing - // internally and implicitly assumed literals). Passes on freezing and - // melting to the internal solver, which has separate frozen counters. - - void freeze (int elit); - void melt (int elit); - - bool frozen (int elit) { - CADICAL_assert (elit); - CADICAL_assert (elit != INT_MIN); - int eidx = abs (elit); - if (eidx > max_var) - return false; - if (eidx >= (int) frozentab.size ()) - return false; - return frozentab[eidx] > 0; - } - - /*----------------------------------------------------------------------*/ - - External (Internal *); - ~External (); - - void enlarge (int new_max_var); // Enlarge allocated 'vsize'. - void init (int new_max_var, - bool extension = false); // Initialize up-to 'new_max_var'. - - int internalize ( - int, - bool extension = false); // Translate external to internal literal. - - /*----------------------------------------------------------------------*/ - - // According to the CaDiCaL API contract (as well as IPASIR) we have to - // forget about the previous assumptions after a 'solve' call. This - // should however be delayed until we transition out of an 'UNSATISFIED' - // state, i.e., after no more 'failed' calls are expected. Note that - // 'failed' requires to know the failing assumptions, and the 'failed' - // status of those should cleared before at start of the next 'solve'. - // As a consequence 'reset_assumptions' is only called from - // 'transition_to_unknown_state' in API calls in 'solver.cpp'. - - void reset_assumptions (); - - // Similarly to 'failed', 'conclude' needs to know about failing - // assumptions and therefore needs to be reset when leaving the - // 'UNSATISFIED' state. - // - void reset_concluded (); - - // Similarly a valid external assignment obtained through 'extend' has to - // be reset at each point it risks to become invalid. This is done - // in the external layer in 'external.cpp' functions.. - - void reset_extended (); - - // Finally, the semantics of incremental solving also require that limits - // are only valid for the next 'solve' call. Since the limits can not - // really be queried, handling them is less complex and they are just - // reset immediately at the end of 'External::solve'. - - void reset_limits (); - - /*----------------------------------------------------------------------*/ - - // Proxies to IPASIR functions. - - void add (int elit); - void assume (int elit); - int solve (bool preprocess_only); - - // We call it 'ival' as abbreviation for 'val' with 'int' return type to - // avoid bugs due to using 'signed char tmp = val (lit)', which might turn - // a negative value into a positive one (happened in 'extend'). - // - inline int ival (int elit) const { - CADICAL_assert (elit != INT_MIN); - int eidx = abs (elit); - bool val = false; - if (eidx <= max_var && (size_t) eidx < vals.size ()) - val = vals[eidx]; - if (elit < 0) - val = !val; - return val ? elit : -elit; - } - - bool flip (int elit); - bool flippable (int elit); - - bool failed (int elit); - - void terminate (); - - // Other important non IPASIR functions. - - /*----------------------------------------------------------------------*/ - - // Add literal to external constraint. - // - void constrain (int elit); - - // Returns true if 'solve' returned 20 because of the constraint. - // - bool failed_constraint (); - - // Deletes the current constraint clause. Called on - // 'transition_to_unknown_state' and if a new constraint is added. Can be - // called directly using the API. - // - void reset_constraint (); - - /*----------------------------------------------------------------------*/ - - int propagate_assumptions (); - void implied (std::vector &entrailed); - void conclude_unknown (); - - /*----------------------------------------------------------------------*/ - int lookahead (); - CaDiCaL::CubesWithStatus generate_cubes (int, int); - - int fixed (int elit) const; // Implemented in 'internal.hpp'. - - /*----------------------------------------------------------------------*/ - - void phase (int elit); - void unphase (int elit); - - /*----------------------------------------------------------------------*/ - - // Traversal functions for the witness stack and units. The explanation - // in 'external.cpp' for why we have to distinguish these cases. - - bool traverse_all_frozen_units_as_clauses (ClauseIterator &); - bool traverse_all_non_frozen_units_as_witnesses (WitnessIterator &); - bool traverse_witnesses_backward (WitnessIterator &); - bool traverse_witnesses_forward (WitnessIterator &); - - /*----------------------------------------------------------------------*/ - - // Copy flags for determining preprocessing state. - - void copy_flags (External &other) const; - - /*----------------------------------------------------------------------*/ - - // Check solver behaves as expected during testing and debugging. - - void check_assumptions_satisfied (); - void check_constraint_satisfied (); - void check_failing (); - - void check_solution_on_learned_clause (); - void check_solution_on_shrunken_clause (Clause *); - void check_solution_on_learned_unit_clause (int unit); - void check_no_solution_after_learning_empty_clause (); - - void check_learned_empty_clause () { - if (solution) - check_no_solution_after_learning_empty_clause (); - } - - void check_learned_unit_clause (int unit) { - if (solution) - check_solution_on_learned_unit_clause (unit); - } - - void check_learned_clause () { - if (solution) - check_solution_on_learned_clause (); - } - - void check_shrunken_clause (Clause *c) { - if (solution) - check_solution_on_shrunken_clause (c); - } - - void check_assignment (int (External::*assignment) (int) const); - - void check_satisfiable (); - void check_unsatisfiable (); - - void check_solve_result (int res); - - void update_molten_literals (); - - /*----------------------------------------------------------------------*/ - - // For debugging and testing only. See 'solution.hpp' for more details. - // TODO: if elit > solution_size, elit is an extension variable. For now - // the clause will count as satisfied regardless. For the future one - // should check that actually there is one consistent extension for the - // solution that satisfies the clauses with this extension variable (by - // setting it to a value once a clause is learned which is not satisfied - // already). - // - inline int sol (int elit) const { - CADICAL_assert (solution); - CADICAL_assert (elit != INT_MIN); - int eidx = abs (elit); - if (eidx > max_var) - return 0; - else if (eidx > solution_size) - return elit; - signed char value = solution[eidx]; - if (!value) - return 0; - if (elit < 0) - value = -value; - return value > 0 ? elit : -elit; - } -}; - -} // namespace CaDiCaL - -ABC_NAMESPACE_CXX_HEADER_END - -#endif diff --git a/src/sat/cadical/factor.hpp b/src/sat/cadical/factor.hpp deleted file mode 100644 index 3aa5ea6c6..000000000 --- a/src/sat/cadical/factor.hpp +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef _factor_hpp_INCLUDED -#define _factor_hpp_INCLUDED - -#include "global.h" - -#include "clause.hpp" -#include "heap.hpp" - -ABC_NAMESPACE_CXX_HEADER_START - -namespace CaDiCaL { - -struct Internal; - -struct factor_occs_size { - Internal *internal; - factor_occs_size (Internal *i) : internal (i) {} - bool operator() (unsigned a, unsigned b); -}; - -struct Quotient { - Quotient (int f) : factor (f) {} - ~Quotient () {} - int factor; - size_t id; - int64_t bid; // for LRAT - Quotient *prev, *next; - vector qlauses; - vector matches; - size_t matched; -}; - -typedef heap FactorSchedule; - -struct Factoring { - Factoring (Internal *, int64_t); - ~Factoring (); - - // These are initialized by the constructor - Internal *internal; - int64_t limit; - FactorSchedule schedule; - - int initial; - int bound; - vector count; - vector fresh; - vector counted; - vector nounted; - vector flauses; - struct { - Quotient *first, *last; - } quotients; -}; - -} // namespace CaDiCaL - -ABC_NAMESPACE_CXX_HEADER_END - -#endif diff --git a/src/sat/cadical/file.hpp b/src/sat/cadical/file.hpp deleted file mode 100644 index 860e9613a..000000000 --- a/src/sat/cadical/file.hpp +++ /dev/null @@ -1,221 +0,0 @@ -#ifndef _file_hpp_INCLUDED -#define _file_hpp_INCLUDED - -#include "global.h" - -#include -#include -#include -#include -#include - -#ifndef CADICAL_NDEBUG -#include -#endif - -/*------------------------------------------------------------------------*/ -#ifdef WIN32 -#define cadical_putc_unlocked putc -#define cadical_getc_unlocked getc -#else -#ifndef NUNLOCKED -#define cadical_putc_unlocked putc_unlocked -#define cadical_getc_unlocked getc_unlocked -#else -#define cadical_putc_unlocked putc -#define cadical_getc_unlocked getc -#endif -#endif -/*------------------------------------------------------------------------*/ - -ABC_NAMESPACE_CXX_HEADER_START - -namespace CaDiCaL { - -// Wraps a 'C' file 'FILE' with name and supports zipped reading and writing -// through 'popen' using external helper tools. Reading has line numbers. -// Compression and decompression relies on external utilities, e.g., 'gzip', -// 'bzip2', 'xz', and '7z', which should be in the 'PATH'. - -struct Internal; - -class File { - - Internal *internal; -#if !defined(CADICAL_QUIET) || !defined(CADICAL_NDEBUG) - bool writing; -#endif - - int close_file; // need to close file (1=fclose, 2=pclose, 3=pipe) - int child_pid; - FILE *file; - char *_name; - uint64_t _lineno; - uint64_t _bytes; - - File (Internal *, bool, int, int, FILE *, const char *); - - static FILE *open_file (Internal *, const char *path, const char *mode); - static FILE *read_file (Internal *, const char *path); - static FILE *write_file (Internal *, const char *path); - - static void split_str (const char *, std::vector &); - static void delete_str_vector (std::vector &); - - static FILE *open_pipe (Internal *, const char *fmt, const char *path, - const char *mode); - static FILE *read_pipe (Internal *, const char *fmt, const int *sig, - const char *path); -#ifndef WIN32 - static FILE *write_pipe (Internal *, const char *fmt, const char *path, - int &child_pid); -#endif - -public: - static char *find_program (const char *prg); // search in 'PATH' - static bool exists (const char *path); // file exists? - static bool writable (const char *path); // can write to that file? - static size_t size (const char *path); // file size in bytes - - bool piping (); // Is opened file a pipe? - - // Does the file match the file type signature. - // - static bool match (Internal *, const char *path, const int *sig); - - // Read from existing file. Assume given name. - // - static File *read (Internal *, FILE *f, const char *name); - - // Open file from path name for reading (possibly through opening a pipe - // to a decompression utility, based on the suffix). - // - static File *read (Internal *, const char *path); - - // Same for writing as for reading above. - // - static File *write (Internal *, FILE *, const char *name); - static File *write (Internal *, const char *path); - - ~File (); - - // Using the 'unlocked' versions here is way faster but - // not thread safe if the same file is used by different - // threads, which on the other hand currently is impossible. - - int get () { - CADICAL_assert (!writing); - int res = cadical_getc_unlocked (file); - if (res == '\n') - _lineno++; - if (res != EOF) - _bytes++; - return res; - } - - bool put (char ch) { - CADICAL_assert (writing); - if (cadical_putc_unlocked (ch, file) == EOF) - return false; - _bytes++; - return true; - } - - bool endl () { return put ('\n'); } - - bool put (unsigned char ch) { - CADICAL_assert (writing); - if (cadical_putc_unlocked (ch, file) == EOF) - return false; - _bytes++; - return true; - } - - bool put (const char *s) { - for (const char *p = s; *p; p++) - if (!put (*p)) - return false; - return true; - } - - bool put (int lit) { - CADICAL_assert (writing); - if (!lit) - return put ('0'); - else if (lit == -2147483648) { - CADICAL_assert (lit == INT_MIN); - return put ("-2147483648"); - } else { - char buffer[11]; - int i = sizeof buffer; - buffer[--i] = 0; - CADICAL_assert (lit != INT_MIN); - unsigned idx = abs (lit); - while (idx) { - CADICAL_assert (i > 0); - buffer[--i] = '0' + idx % 10; - idx /= 10; - } - if (lit < 0 && !put ('-')) - return false; - return put (buffer + i); - } - } - - bool put (int64_t l) { - CADICAL_assert (writing); - if (!l) - return put ('0'); - else if (l == INT64_MIN) { - CADICAL_assert (sizeof l == 8); - return put ("-9223372036854775808"); - } else { - char buffer[21]; - int i = sizeof buffer; - buffer[--i] = 0; - CADICAL_assert (l != INT64_MIN); - uint64_t k = l < 0 ? -l : l; - while (k) { - CADICAL_assert (i > 0); - buffer[--i] = '0' + k % 10; - k /= 10; - } - if (l < 0 && !put ('-')) - return false; - return put (buffer + i); - } - } - - bool put (uint64_t l) { - CADICAL_assert (writing); - if (!l) - return put ('0'); - else { - char buffer[22]; - int i = sizeof buffer; - buffer[--i] = 0; - while (l) { - CADICAL_assert (i > 0); - buffer[--i] = '0' + l % 10; - l /= 10; - } - return put (buffer + i); - } - } - - const char *name () const { return _name; } - uint64_t lineno () const { return _lineno; } - uint64_t bytes () const { return _bytes; } - - void connect_internal (Internal *i) { internal = i; } - bool closed () { return !file; } - - void close (bool print = false); - void flush (); -}; - -} // namespace CaDiCaL - -ABC_NAMESPACE_CXX_HEADER_END - -#endif diff --git a/src/sat/cadical/flags.hpp b/src/sat/cadical/flags.hpp deleted file mode 100644 index 995438c7a..000000000 --- a/src/sat/cadical/flags.hpp +++ /dev/null @@ -1,91 +0,0 @@ -#ifndef _flags_hpp_INCLUDED -#define _flags_hpp_INCLUDED - -#include "global.h" - -ABC_NAMESPACE_CXX_HEADER_START - -namespace CaDiCaL { - -struct Flags { // Variable flags. - - // The first set of flags is related to 'analyze' and 'minimize'. - // - bool seen : 1; // seen in generating first UIP clause in 'analyze' - bool keep : 1; // keep in learned clause in 'minimize' - bool poison : 1; // can not be removed in 'minimize' - bool removable : 1; // can be removed in 'minimize' - bool shrinkable : 1; // can be removed in 'shrink' - bool added : 1; // has already been added to lrat_chain (in 'minimize') - - // These three variable flags are used to schedule clauses in subsumption - // ('subsume'), variables in bounded variable elimination ('elim') and in - // hyper ternary resolution ('ternary'). - // - bool elim : 1; // removed since last 'elim' round (*) - bool subsume : 1; // added since last 'subsume' round (*) - bool ternary : 1; // added in ternary clause since last 'ternary' (*) - bool sweep : 1; - bool blockable : 1; - - unsigned char - marked_signed : 2; // generate correct LRAT chains in decompose - unsigned char factor : 2; - - // These literal flags are used by blocked clause elimination ('block'). - // - unsigned char block : 2; // removed since last 'block' round (*) - unsigned char skip : 2; // skip this literal as blocking literal - - // Bits for handling assumptions. - // - unsigned char assumed : 2; - unsigned char failed : 2; // 0 if not part of failure - // 1 if positive lit is in failure - // 2 if negated lit is in failure - - enum { - UNUSED = 0, - ACTIVE = 1, - FIXED = 2, - ELIMINATED = 3, - SUBSTITUTED = 4, - PURE = 5 - }; - - unsigned char status : 3; - - // Initialized explicitly in 'Internal::init' through this function. - // - Flags () { - seen = keep = poison = removable = shrinkable = added = sweep = false; - subsume = elim = ternary = true; - block = 3u; - skip = assumed = failed = marked_signed = factor = 0; - status = UNUSED; - } - - bool unused () const { return status == UNUSED; } - bool active () const { return status == ACTIVE; } - bool fixed () const { return status == FIXED; } - bool eliminated () const { return status == ELIMINATED; } - bool substituted () const { return status == SUBSTITUTED; } - bool pure () const { return status == PURE; } - - // The flags marked with '(*)' are copied during 'External::copy_flags', - // which in essence means they are reset in the copy if they were clear. - // This avoids the effort of fruitless preprocessing the copy. - - void copy (Flags &dst) const { - dst.elim = elim; - dst.subsume = subsume; - dst.ternary = ternary; - dst.block = block; - } -}; - -} // namespace CaDiCaL - -ABC_NAMESPACE_CXX_HEADER_END - -#endif diff --git a/src/sat/cadical/format.hpp b/src/sat/cadical/format.hpp deleted file mode 100644 index cf229e760..000000000 --- a/src/sat/cadical/format.hpp +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef _format_hpp_INCLUDED -#define _format_hpp_INCLUDED - -#include "global.h" - -#include -#include - -ABC_NAMESPACE_CXX_HEADER_START - -namespace CaDiCaL { - -// This class provides a 'printf' style formatting utility. -// Only '%c', '%d', '%s' are supported at this point. -// It is used to capture and save an error message. - -class Format { - char *buffer; - int64_t count, size; - void enlarge (); - void push_char (char); - void push_string (const char *); - void push_int (int); - void push_uint64 (uint64_t); - const char *add (const char *fmt, va_list &); - -public: - Format () : buffer (0), count (0), size (0) {} - ~Format () { - if (buffer) - delete[] buffer; - } - const char *init (const char *fmt, ...) CADICAL_ATTRIBUTE_FORMAT (2, 3); - const char *append (const char *fmt, ...) CADICAL_ATTRIBUTE_FORMAT (2, 3); - operator const char * () const { return count ? buffer : 0; } -}; - -} // namespace CaDiCaL - -ABC_NAMESPACE_CXX_HEADER_END - -#endif diff --git a/src/sat/cadical/frattracer.hpp b/src/sat/cadical/frattracer.hpp deleted file mode 100644 index cadfa3721..000000000 --- a/src/sat/cadical/frattracer.hpp +++ /dev/null @@ -1,68 +0,0 @@ -#ifndef _frattracer_h_INCLUDED -#define _frattracer_h_INCLUDED - -#include "global.h" - -ABC_NAMESPACE_CXX_HEADER_START - -namespace CaDiCaL { - -class FratTracer : public FileTracer { - - Internal *internal; - File *file; - bool binary; - bool with_antecedents; - -#ifndef CADICAL_QUIET - int64_t added, deleted; - int64_t finalized, original; -#endif - - vector delete_ids; - - void put_binary_zero (); - void put_binary_lit (int external_lit); - void put_binary_id (int64_t id, bool = false); - - // support FRAT - void frat_add_original_clause (int64_t, const vector &); - void frat_add_derived_clause (int64_t, const vector &); - void frat_add_derived_clause (int64_t, const vector &, - const vector &); - void frat_delete_clause (int64_t, const vector &); - void frat_finalize_clause (int64_t, const vector &); - -public: - // own and delete 'file' - FratTracer (Internal *, File *file, bool binary, bool antecedents); - ~FratTracer (); - - void connect_internal (Internal *i) override; - void begin_proof (int64_t) override {} // skip - - void add_original_clause (int64_t, bool, const vector &, - bool = false) override; - - void add_derived_clause (int64_t, bool, const vector &, - const vector &) override; - - void delete_clause (int64_t, bool, const vector &) override; - - void finalize_clause (int64_t, const vector &) override; - - void report_status (int, int64_t) override {} // skip - -#ifndef CADICAL_QUIET - void print_statistics (); -#endif - bool closed () override; - void close (bool) override; - void flush (bool) override; -}; - -} // namespace CaDiCaL - -ABC_NAMESPACE_CXX_HEADER_END - -#endif diff --git a/src/sat/cadical/global.h b/src/sat/cadical/global.h deleted file mode 100644 index 916246cab..000000000 --- a/src/sat/cadical/global.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef ABC_SAT_CADICAL_GLOBAL_HPP_ -#define ABC_SAT_CADICAL_GLOBAL_HPP_ - -// comment out next line to enable cadical debug mode -#define CADICAL_NDEBUG - -#define CADICAL_NBUILD -#define CADICAL_QUIET -#define CADICAL_NCONTRACTS -#define CADICAL_NTRACING -#define CADICAL_NCLOSEFROM - -#ifdef CADICAL_NDEBUG -#define CADICAL_assert(ignore) ((void)0) -#else -#define CADICAL_assert(cond) assert(cond) -#endif - -#include "misc/util/abc_global.h" - -#endif diff --git a/src/sat/cadical/heap.hpp b/src/sat/cadical/heap.hpp deleted file mode 100644 index c42941413..000000000 --- a/src/sat/cadical/heap.hpp +++ /dev/null @@ -1,218 +0,0 @@ -#ifndef _heap_hpp_INCLUDED -#define _heap_hpp_INCLUDED - -#include "global.h" - -#include "util.hpp" // Alphabetically after 'heap.hpp'. - -#include - -ABC_NAMESPACE_CXX_HEADER_START - -namespace CaDiCaL { - -using namespace std; - -// This is a priority queue with updates for unsigned integers implemented -// as binary heap. We need to map integer elements added (through -// 'push_back') to positions on the binary heap in 'array'. This map is -// stored in the 'pos' array. This approach is really wasteful (at least in -// terms of memory) if only few and a sparse set of integers is added. So -// it should not be used in this situation. A generic priority queue would -// implement the mapping externally provided by another template parameter. -// Since we use 'UINT_MAX' as 'not contained' flag, we can only have -// 'UINT_MAX - 1' elements in the heap. - -const unsigned invalid_heap_position = UINT_MAX; - -template class heap { - - vector array; // actual binary heap - vector pos; // positions of elements in array - C less; // less-than for elements - - // Map an element to its position entry in the 'pos' map. - // - unsigned &index (unsigned e) { - if (e >= pos.size ()) - pos.resize (1 + (size_t) e, invalid_heap_position); - unsigned &res = pos[e]; - CADICAL_assert (res == invalid_heap_position || (size_t) res < array.size ()); - return res; - } - - bool has_parent (unsigned e) { return index (e) > 0; } - bool has_left (unsigned e) { - return (size_t) 2 * index (e) + 1 < size (); - } - bool has_right (unsigned e) { - return (size_t) 2 * index (e) + 2 < size (); - } - - unsigned parent (unsigned e) { - CADICAL_assert (has_parent (e)); - return array[(index (e) - 1) / 2]; - } - - unsigned left (unsigned e) { - CADICAL_assert (has_left (e)); - return array[2 * index (e) + 1]; - } - - unsigned right (unsigned e) { - CADICAL_assert (has_right (e)); - return array[2 * index (e) + 2]; - } - - // Exchange elements 'a' and 'b' in 'array' and fix their positions. - // - void exchange (unsigned a, unsigned b) { - unsigned &i = index (a), &j = index (b); - swap (array[i], array[j]); - swap (i, j); - } - - // Bubble up an element as far as necessary. - // - void up (unsigned e) { - unsigned p; - while (has_parent (e) && less ((p = parent (e)), e)) - exchange (p, e); - } - - // Bubble down an element as far as necessary. - // - void down (unsigned e) { - while (has_left (e)) { - unsigned c = left (e); - if (has_right (e)) { - unsigned r = right (e); - if (less (c, r)) - c = r; - } - if (!less (e, c)) - break; - exchange (e, c); - } - } - - // Very expensive checker for the main 'heap' invariant. Can be enabled - // to find violations of antisymmetry in the client implementation of - // 'less' and as well of course bugs in this heap implementation. It - // should be enabled during testing applications of the heap. - // - void check () { -#if 0 // EXPENSIVE HEAP CHECKING IF ENABLED -#warning "expensive checking in heap enabled" - CADICAL_assert (array.size () <= invalid_heap_position); - for (size_t i = 0; i < array.size (); i++) { - size_t l = 2*i + 1, r = 2*i + 2; - if (l < array.size ()) CADICAL_assert (!less (array[i], array[l])); - if (r < array.size ()) CADICAL_assert (!less (array[i], array[r])); - CADICAL_assert (array[i] >= 0); - { - CADICAL_assert ((size_t) array[i] < pos.size ()); - CADICAL_assert (i == (size_t) pos[array[i]]); - } - } - for (size_t i = 0; i < pos.size (); i++) { - if (pos[i] == invalid_heap_position) continue; - CADICAL_assert (pos[i] < array.size ()); - CADICAL_assert (array[pos[i]] == (unsigned) i); - } -#endif - } - -public: - heap (const C &c) : less (c) {} - - // Number of elements in the heap. - // - size_t size () const { return array.size (); } - - // Check if no more elements are in the heap. - // - bool empty () const { return array.empty (); } - - // Check whether 'e' is already in the heap. - // - bool contains (unsigned e) const { - if ((size_t) e >= pos.size ()) - return false; - return pos[e] != invalid_heap_position; - } - - // Add a new (not contained) element 'e' to the heap. - // - void push_back (unsigned e) { - CADICAL_assert (!contains (e)); - size_t i = array.size (); - CADICAL_assert (i < (size_t) invalid_heap_position); - array.push_back (e); - index (e) = (unsigned) i; - up (e); - down (e); - check (); - } - - // Returns the maximum element in the heap. - // - unsigned front () const { - CADICAL_assert (!empty ()); - return array[0]; - } - - // Removes the maximum element in the heap. - // - unsigned pop_front () { - CADICAL_assert (!empty ()); - unsigned res = array[0], last = array.back (); - if (size () > 1) - exchange (res, last); - index (res) = invalid_heap_position; - array.pop_back (); - if (size () > 1) - down (last); - check (); - return res; - } - - // Notify the heap, that evaluation of 'less' has changed for 'e'. - // - void update (unsigned e) { - CADICAL_assert (contains (e)); - up (e); - down (e); - check (); - } - - void clear () { - array.clear (); - pos.clear (); - } - - void erase () { - erase_vector (array); - erase_vector (pos); - } - - void shrink () { - shrink_vector (array); - shrink_vector (pos); - } - - // Standard iterators 'inherited' from 'vector'. - // - typedef typename vector::iterator iterator; - typedef typename vector::const_iterator const_iterator; - iterator begin () { return array.begin (); } - iterator end () { return array.end (); } - const_iterator begin () const { return array.begin (); } - const_iterator end () const { return array.end (); } -}; - -} // namespace CaDiCaL - -ABC_NAMESPACE_CXX_HEADER_END - -#endif diff --git a/src/sat/cadical/idruptracer.hpp b/src/sat/cadical/idruptracer.hpp deleted file mode 100644 index 4ea478705..000000000 --- a/src/sat/cadical/idruptracer.hpp +++ /dev/null @@ -1,116 +0,0 @@ -#ifndef _idruptracer_h_INCLUDED -#define _idruptracer_h_INCLUDED - -#include "global.h" - -ABC_NAMESPACE_CXX_HEADER_START - -class FileTracer; - -namespace CaDiCaL { - -struct IdrupClause { - IdrupClause *next; // collision chain link for hash table - uint64_t hash; // previously computed full 64-bit hash - int64_t id; // id of clause - unsigned size; - int literals[1]; -}; - -class IdrupTracer : public FileTracer { - - Internal *internal; - File *file; - bool binary; - bool piping; // The 'file' is a pipe and needs eagerly flushing. - - // hash table for conclusion - // - uint64_t num_clauses; // number of clauses in hash table - uint64_t size_clauses; // size of clause hash table - IdrupClause **clauses; // hash table of clauses - vector imported_clause; - vector assumptions; - - static const unsigned num_nonces = 4; - - uint64_t nonces[num_nonces]; // random numbers for hashing - uint64_t last_hash; // last computed hash value of clause - int64_t last_id; // id of the last added clause - IdrupClause *last_clause; - uint64_t compute_hash (int64_t); // compute and save hash value of clause - - IdrupClause *new_clause (); - void delete_clause (IdrupClause *); - - static uint64_t reduce_hash (uint64_t hash, uint64_t size); - - void enlarge_clauses (); // enlarge hash table for clauses - void insert (); // insert clause in hash table - bool - find_and_delete (const int64_t); // find clause position in hash table - -#ifndef CADICAL_QUIET - int64_t added, deleted, weakened, restore, original, solved; -#endif - - void flush_if_piping (); - - void put_binary_zero (); - void put_binary_lit (int external_lit); - void put_binary_id (int64_t id, bool = false); - - void idrup_add_derived_clause (const vector &clause); - void idrup_delete_clause (int64_t id, const vector &clause); - void idrup_add_restored_clause (const vector &clause); - void idrup_add_original_clause (const vector &clause); - void idrup_conclude_and_delete (const vector &conclusion); - void idrup_report_status (int status); - void idrup_conclude_sat (const vector &model); - void idrup_conclude_unknown (const vector &trail); - void idrup_solve_query (); - -public: - IdrupTracer (Internal *, File *file, bool); - ~IdrupTracer (); - - // proof section: - void add_derived_clause (int64_t, bool, const vector &, - const vector &) override; - void add_assumption_clause (int64_t, const vector &, - const vector &) override; - void weaken_minus (int64_t, const vector &) override; - void delete_clause (int64_t, bool, const vector &) override; - void add_original_clause (int64_t, bool, const vector &, - bool = false) override; - void report_status (int, int64_t) override; - void conclude_sat (const vector &) override; - void conclude_unsat (ConclusionType, const vector &) override; - void conclude_unknown (const vector &) override; - - void solve_query () override; - void add_assumption (int) override; - void reset_assumptions () override; - - // skip - void begin_proof (int64_t) override {} - void finalize_clause (int64_t, const vector &) override {} - void strengthen (int64_t) override {} - void add_constraint (const vector &) override {} - - // logging and file io - void connect_internal (Internal *i) override; - -#ifndef CADICAL_QUIET - void print_statistics (); -#endif - bool closed () override; - void close (bool) override; - void flush (bool) override; -}; - -} // namespace CaDiCaL - -ABC_NAMESPACE_CXX_HEADER_END - -#endif diff --git a/src/sat/cadical/instantiate.hpp b/src/sat/cadical/instantiate.hpp deleted file mode 100644 index f6c8767dd..000000000 --- a/src/sat/cadical/instantiate.hpp +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef _instantiate_hpp_INCLUDED -#define _instantiate_hpp_INCLUDED - -#include "global.h" - -ABC_NAMESPACE_CXX_HEADER_START - -namespace CaDiCaL { - -// We are trying to remove literals in clauses, which occur in few clauses -// and further restrict this removal to variables for which variable -// elimination failed. Thus if for instance we succeed in removing the -// single occurrence of a literal, pure literal elimination can -// eliminate the corresponding variable in the next variable elimination -// round. The set of such literal clause candidate pairs is collected at -// the end of a variable elimination round and tried before returning. The -// name of this technique is inspired by 'variable instantiation' as -// described in [AnderssonBjesseCookHanna-DAC'02] and apparently -// successfully used in the 'Oepir' SAT solver. - -struct Clause; -struct Internal; - -class Instantiator { - - friend struct Internal; - - struct Candidate { - int lit; - int size; - size_t negoccs; - Clause *clause; - Candidate (int l, Clause *c, int s, size_t n) - : lit (l), size (s), negoccs (n), clause (c) {} - }; - - vector candidates; - -public: - void candidate (int l, Clause *c, int s, size_t n) { - candidates.push_back (Candidate (l, c, s, n)); - } - - operator bool () const { return !candidates.empty (); } -}; - -} // namespace CaDiCaL - -ABC_NAMESPACE_CXX_HEADER_END - -#endif diff --git a/src/sat/cadical/internal.hpp b/src/sat/cadical/internal.hpp deleted file mode 100644 index d86479a52..000000000 --- a/src/sat/cadical/internal.hpp +++ /dev/null @@ -1,1866 +0,0 @@ -#ifndef _internal_hpp_INCLUDED -#define _internal_hpp_INCLUDED - -#include "global.h" - -/*------------------------------------------------------------------------*/ - -// Wrapped build specific headers which should go first. - -#include "inttypes.hpp" - -/*------------------------------------------------------------------------*/ - -// Common 'C' headers. - -#include -#include -#include -#include -#include -#include -#include -#include - -// Less common 'C' header. - -#ifndef WIN32 -extern "C" { -#include -} -#endif - -/*------------------------------------------------------------------------*/ - -// Common 'C++' headers. - -#include -#include -#include -#include -#include - -/*------------------------------------------------------------------------*/ - -// All internal headers are included here. This gives a nice overview on -// what is needed altogether. The 'Internal' class needs almost all the -// headers anyhow (since the idea is to avoid pointer references as much as -// possible). Most implementation files need to see the definition of the -// 'Internal' too. Thus there is no real advantage in trying to reduce the -// number of header files included here. The other benefit of having all -// header files here is that '.cpp' files then only need to include this. - -#include "arena.hpp" -#include "averages.hpp" -#include "bins.hpp" -#include "block.hpp" -#include "cadical.hpp" -#include "checker.hpp" -#include "clause.hpp" -#include "config.hpp" -#include "congruence.hpp" -#include "contract.hpp" -#include "cover.hpp" -#include "decompose.hpp" -#include "drattracer.hpp" -#include "elim.hpp" -#include "ema.hpp" -#include "external.hpp" -#include "factor.hpp" -#include "file.hpp" -#include "flags.hpp" -#include "format.hpp" -#include "frattracer.hpp" -#include "heap.hpp" -#include "idruptracer.hpp" -#include "instantiate.hpp" -#include "internal.hpp" -#include "level.hpp" -#include "lidruptracer.hpp" -#include "limit.hpp" -#include "logging.hpp" -#include "lratchecker.hpp" -#include "lrattracer.hpp" -#include "message.hpp" -#include "occs.hpp" -#include "options.hpp" -#include "parse.hpp" -#include "phases.hpp" -#include "profile.hpp" -#include "proof.hpp" -#include "queue.hpp" -#include "radix.hpp" -#include "random.hpp" -#include "range.hpp" -#include "reap.hpp" -#include "reluctant.hpp" -#include "resources.hpp" -#include "score.hpp" -#include "stats.hpp" -#include "sweep.hpp" -#include "terminal.hpp" -#include "tracer.hpp" -#include "util.hpp" -#include "var.hpp" -#include "veripbtracer.hpp" -#include "version.hpp" -#include "vivify.hpp" -#include "watch.hpp" - -// c headers -//extern "C" { -#include "kitten.h" -//} -/*------------------------------------------------------------------------*/ - -ABC_NAMESPACE_CXX_HEADER_START - -namespace CaDiCaL { - -using namespace std; - -struct Coveror; -struct External; -struct Walker; -class Tracer; -class FileTracer; -class StatTracer; - -struct CubesWithStatus { - int status = 0; - std::vector> cubes; -}; - -/*------------------------------------------------------------------------*/ - -struct Internal { - - /*----------------------------------------------------------------------*/ - - // The actual internal state of the solver is set and maintained in this - // section. This is currently only used for debugging and testing. - - enum Mode { - BLOCK = (1 << 0), - CONDITION = (1 << 1), - CONGRUENCE = (1 << 2), - COVER = (1 << 3), - DECOMP = (1 << 4), - DEDUP = (1 << 5), - ELIM = (1 << 6), - FACTOR = (1 << 7), - LUCKY = (1 << 8), - PROBE = (1 << 9), - SEARCH = (1 << 10), - SIMPLIFY = (1 << 11), - SUBSUME = (1 << 12), - SWEEP = (1 << 13), - TERNARY = (1 << 14), - TRANSRED = (1 << 15), - VIVIFY = (1 << 16), - WALK = (1 << 17), - }; - - bool in_mode (Mode m) const { return (mode & m) != 0; } - void set_mode (Mode m) { - CADICAL_assert (!(mode & m)); - mode |= m; - } - void reset_mode (Mode m) { - CADICAL_assert (mode & m); - mode &= ~m; - } - void require_mode (Mode m) const { CADICAL_assert (mode & m), (void) m; } - - /*----------------------------------------------------------------------*/ - - int mode; // current internal state - int tier1[2] = { - 2, 2}; // tier1 limit for 0=focused, 1=stable; aka tier1[stable] - int tier2[2] = { - 6, 6}; // tier2 limit for 0=focused, 1=stable; aka tier1[stable] - bool unsat; // empty clause found or learned - bool iterating; // report learned unit ('i' line) - bool localsearching; // true during local search - bool lookingahead; // true during look ahead - bool preprocessing; // true during preprocessing - bool protected_reasons; // referenced reasons are protected - bool force_saved_phase; // force saved phase in decision - bool searching_lucky_phases; // during 'lucky_phases' - bool stable; // true during stabilization phase - bool reported; // reported in this solving call - bool external_prop; // true if an external propagator is connected - bool did_external_prop; // true if ext. propagation happened - bool external_prop_is_lazy; // true if the external propagator is lazy - bool forced_backt_allowed; // external propagator can force backtracking - bool private_steps; // no notification of ext. prop during these steps - char rephased; // last type of resetting phases - Reluctant reluctant; // restart counter in stable mode - size_t vsize; // actually allocated variable data size - int max_var; // internal maximum variable index - int64_t clause_id; // last used id for clauses - int64_t original_id; // ids for original clauses to produce LRAT - int64_t reserved_ids; // number of reserved ids for original clauses - int64_t conflict_id; // store conflict id for finalize (frat) - int64_t saved_decisions; // to compute decision rate average - bool concluded; // keeps track of conclude - vector conclusion; // store ids of conclusion clauses - vector - unit_clauses_idx; // keep track of unit_clauses (LRAT/FRAT) - vector lrat_chain; // create LRAT in solver: option lratdirect - vector mini_chain; // used to create LRAT in minimize - vector minimize_chain; // used to create LRAT in minimize - vector unit_chain; // used to avoid duplicate units - vector inst_chain; // for LRAT in instantiate - vector>> - probehbr_chains; // only used if opts.probehbr=false - bool lrat; // generate LRAT internally - bool frat; // finalize non-deleted clauses in proof - int level; // decision level ('control.size () - 1') - Phases phases; // saved, target and best phases - signed char *vals; // assignment [-max_var,max_var] - vector marks; // signed marks [1,max_var] - vector frozentab; // frozen counters [1,max_var] - vector i2e; // maps internal 'idx' to external 'lit' - vector relevanttab; // Reference counts for observed variables. - Queue queue; // variable move to front decision queue - Links links; // table of links for decision queue - double score_inc; // current score increment - ScoreSchedule scores; // score based decision priority queue - vector stab; // table of variable scores [1,max_var] - vector vtab; // variable table [1,max_var] - vector parents; // parent literals during probing - vector ftab; // variable and literal flags - vector btab; // enqueue time stamps for queue - vector gtab; // time stamp table to recompute glue - vector otab; // table of occurrences for all literals - vector rtab; // table of redundant occurrences - vector ptab; // table for caching probing attempts - vector ntab; // number of one-sided occurrences table - vector big; // binary implication graph - vector wtab; // table of watches for all literals - Clause *conflict; // set in 'propagation', reset in 'analyze' - Clause *ignore; // ignored during 'vivify_propagate' - Clause *dummy_binary; // Dummy binary clause for subsumption - Clause *external_reason; // used as reason at external propagations - Clause *newest_clause; // used in external_propagate - bool force_no_backtrack; // for new clauses with external propagator - bool from_propagator; // differentiate new clauses... - bool ext_clause_forgettable; // Is new clause from propagator forgettable - int tainted_literal; // used for ILB - size_t notified; // next trail position to notify external prop - Clause *probe_reason; // set during probing - size_t propagated; // next trail position to propagate - size_t propagated2; // next binary trail position to propagate - size_t propergated; // propagated without blocking literals - size_t best_assigned; // best maximum assigned ever - size_t target_assigned; // maximum assigned without conflict - size_t no_conflict_until; // largest trail prefix without conflict - vector trail; // currently assigned literals - vector clause; // simplified in parsing & learning - vector assumptions; // assumed literals - vector constraint; // literals of the constraint - bool unsat_constraint; // constraint used for unsatisfiability? - bool marked_failed; // are the failed assumptions marked? - vector original; // original added literals - vector levels; // decision levels in learned clause - vector analyzed; // analyzed literals in 'analyze' - vector unit_analyzed; // to avoid duplicate units in lrat_chain - vector sign_marked; // literals skipped in 'decompose' - vector minimized; // removable or poison in 'minimize' - vector shrinkable; // removable or poison in 'shrink' - Reap reap; // radix heap for shrink - - vector sweep_schedule; // remember sweep varibles to reschedule - bool sweep_incomplete; // sweep - - cadical_kitten *citten; - - size_t num_assigned; // check for satisfied - - vector probes; // remaining scheduled probes - vector control; // 'level + 1 == control.size ()' - vector clauses; // ordered collection of all clauses - Averages averages; // glue, size, jump moving averages - Delay delay[2]; // Delay certain functions - Delay congruence_delay; // Delay congruence if not successful recently - Limit lim; // limits for various phases - Last last; // statistics at last occurrence - Inc inc; // increments on limits - - Delay delaying_vivify_irredundant; - Delay delaying_sweep; - - Proof *proof; // abstraction layer between solver and tracers - vector - tracers; // proof tracing objects (ie interpolant calculator) - vector - file_tracers; // file proof tracers (ie DRAT, LRAT...) - vector stat_tracers; // checkers - - Options opts; // run-time options - Stats stats; // statistics -#ifndef CADICAL_QUIET - Profiles profiles; // time profiles for various functions - bool force_phase_messages; // force 'phase (...)' messages -#endif - Arena arena; // memory arena for moving garbage collector - Format error_message; // provide persistent error message - string prefix; // verbose messages prefix - - Internal *internal; // proxy to 'this' in macros - External *external; // proxy to 'external' buddy in 'Solver' - - const unsigned max_used = 255; // must fix into the header of the clause! - /*----------------------------------------------------------------------*/ - - // Asynchronous termination flag written by 'terminate' and read by - // 'terminated_asynchronously' (the latter at the end of this header). - // - volatile bool termination_forced; - - /*----------------------------------------------------------------------*/ - - const Range vars; // Provides safe variable iteration. - const Sange lits; // Provides safe literal iteration. - - /*----------------------------------------------------------------------*/ - - Internal (); - ~Internal (); - - /*----------------------------------------------------------------------*/ - - // Internal delegates and helpers for corresponding functions in - // 'External' and 'Solver'. The 'init_vars' function initializes - // variables up to and including the requested variable index. - // - void init_vars (int new_max_var); - - void init_enqueue (int idx); - void init_queue (int old_max_var, int new_max_var); - - void init_scores (int old_max_var, int new_max_var); - - void add_original_lit (int lit); - - // only able to restore irredundant clause - void finish_added_clause_with_id (int64_t id, bool restore = false); - - // Reserve ids for original clauses to produce lrat - void reserve_ids (int number); - - // Enlarge tables. - // - void enlarge_vals (size_t new_vsize); - void enlarge (int new_max_var); - - // A variable is 'active' if it is not eliminated nor fixed. - // - bool active (int lit) { return flags (lit).active (); } - - int active () const { - int res = stats.active; -#ifndef CADICAL_NDEBUG - int tmp = max_var; - tmp -= stats.unused; - tmp -= stats.now.fixed; - tmp -= stats.now.eliminated; - tmp -= stats.now.substituted; - tmp -= stats.now.pure; - CADICAL_assert (tmp >= 0); - CADICAL_assert (tmp == res); -#endif - return res; - } - - void reactivate (int lit); // During 'restore'. - - // Currently remaining active redundant and irredundant clauses. - - int64_t redundant () const { return stats.current.redundant; } - - int64_t irredundant () const { return stats.current.irredundant; } - - double clause_variable_ratio () const { - return relative (irredundant (), active ()); - } - - // Scale values relative to clause variable ratio. - // - double scale (double v) const; - - // Unsigned literals (abs) with checks. - // - int vidx (int lit) const { - int idx; - CADICAL_assert (lit); - CADICAL_assert (lit != INT_MIN); - idx = abs (lit); - CADICAL_assert (idx <= max_var); - return idx; - } - - // Unsigned version with LSB denoting sign. This is used in indexing - // arrays by literals. The idea is to keep the elements in such an array - // for both the positive and negated version of a literal close together. - // - unsigned vlit (int lit) const { - return (lit < 0) + 2u * (unsigned) vidx (lit); - } - - int u2i (unsigned u) { - CADICAL_assert (u > 1); - int res = u / 2; - CADICAL_assert (res <= max_var); - if (u & 1) - res = -res; - return res; - } - - int citten2lit (unsigned ulit) { - int res = (ulit / 2) + 1; - CADICAL_assert (res <= max_var); - if (ulit & 1) - res = -res; - return res; - } - - unsigned lit2citten (int lit) { - int idx = vidx (lit) - 1; - return (lit < 0) + 2u * (unsigned) idx; - } - - int64_t unit_id (int lit) const { - CADICAL_assert (lrat || frat); - CADICAL_assert (val (lit) > 0); - const unsigned uidx = vlit (lit); - int64_t id = unit_clauses_idx[uidx]; - CADICAL_assert (id); - return id; - } - - inline int64_t &unit_clauses (int uidx) { - CADICAL_assert (lrat || frat); - CADICAL_assert (uidx > 0); - CADICAL_assert ((size_t) uidx < unit_clauses_idx.size ()); - return unit_clauses_idx[uidx]; - } - - // Helper functions to access variable and literal data. - // - Var &var (int lit) { return vtab[vidx (lit)]; } - Link &link (int lit) { return links[vidx (lit)]; } - Flags &flags (int lit) { return ftab[vidx (lit)]; } - int64_t &bumped (int lit) { return btab[vidx (lit)]; } - int &propfixed (int lit) { return ptab[vlit (lit)]; } - double &score (int lit) { return stab[vidx (lit)]; } - - const Flags &flags (int lit) const { return ftab[vidx (lit)]; } - - bool occurring () const { return !otab.empty (); } - bool watching () const { return !wtab.empty (); } - - Bins &bins (int lit) { return big[vlit (lit)]; } - Occs &occs (int lit) { return otab[vlit (lit)]; } - int64_t &noccs (int lit) { return ntab[vlit (lit)]; } - Watches &watches (int lit) { return wtab[vlit (lit)]; } - - // Variable bumping through exponential VSIDS (EVSIDS) as in MiniSAT. - // - bool use_scores () const { return opts.score && stable; } - void bump_variable_score (int lit); - void bump_variable_score_inc (); - void rescale_variable_scores (); - - // Marking variables with a sign (positive or negative). - // - signed char marked (int lit) const { - signed char res = marks[vidx (lit)]; - if (lit < 0) - res = -res; - return res; - } - void mark (int lit) { - CADICAL_assert (!marked (lit)); - marks[vidx (lit)] = sign (lit); - CADICAL_assert (marked (lit) > 0); - CADICAL_assert (marked (-lit) < 0); - } - void unmark (int lit) { - marks[vidx (lit)] = 0; - CADICAL_assert (!marked (lit)); - } - - // Use only bits 6 and 7 to store the sign or zero. The remaining - // bits can be used as additional flags. - // - signed char marked67 (int lit) const { - signed char res = marks[vidx (lit)] >> 6; - if (lit < 0) - res = -res; - return res; - } - void mark67 (int lit) { - signed char &m = marks[vidx (lit)]; - const signed char mask = 0x3f; -#ifndef CADICAL_NDEBUG - const signed char bits = m & mask; -#endif - m = (m & mask) | (sign (lit) << 6); - CADICAL_assert (marked (lit) > 0); - CADICAL_assert (marked (-lit) < 0); - CADICAL_assert ((m & mask) == bits); - CADICAL_assert (marked67 (lit) > 0); - CADICAL_assert (marked67 (-lit) < 0); - } - void unmark67 (int lit) { - signed char &m = marks[vidx (lit)]; - const signed char mask = 0x3f; -#ifndef CADICAL_NDEBUG - const signed bits = m & mask; -#endif - m &= mask; - CADICAL_assert ((m & mask) == bits); - } - - void unmark (vector &lits) { - for (const auto &lit : lits) - unmark (lit); - } - - // The other 6 bits of the 'marks' bytes can be used as additional - // (unsigned) marking bits. Currently we only use the least significant - // bit in 'condition' to mark variables in the conditional part. - // - bool getbit (int lit, int bit) const { - CADICAL_assert (0 <= bit), CADICAL_assert (bit < 6); - return marks[vidx (lit)] & (1 << bit); - } - void setbit (int lit, int bit) { - CADICAL_assert (0 <= bit), CADICAL_assert (bit < 6); - CADICAL_assert (!getbit (lit, bit)); - marks[vidx (lit)] |= (1 << bit); - CADICAL_assert (getbit (lit, bit)); - } - void unsetbit (int lit, int bit) { - CADICAL_assert (0 <= bit), CADICAL_assert (bit < 6); - CADICAL_assert (getbit (lit, bit)); - marks[vidx (lit)] &= ~(1 << bit); - CADICAL_assert (!getbit (lit, bit)); - } - - // Marking individual literals. - // - bool marked2 (int lit) const { - unsigned res = marks[vidx (lit)]; - CADICAL_assert (res <= 3); - unsigned bit = bign (lit); - return (res & bit) != 0; - } - void mark2 (int lit) { - marks[vidx (lit)] |= bign (lit); - CADICAL_assert (marked2 (lit)); - } - - // marks bits 1,2,3 and 4,5,6 depending on fact and sign of lit - // - bool getfact (int lit, int fact) const { - CADICAL_assert (fact == 1 || fact == 2 || fact == 4); - int res = marks[vidx (lit)]; - if (lit < 0) { - res >>= 3; - } else { - res &= 7; - } - // CADICAL_assert (!res || res == 1 || res == 2 || res == 4); - return res & fact; - } - - void markfact (int lit, int fact) { - CADICAL_assert (fact == 1 || fact == 2 || fact == 4); - CADICAL_assert (!getfact (lit, fact)); -#ifndef CADICAL_NDEBUG - int before = getfact (-lit, fact); -#endif - int res = marks[vidx (lit)]; - if (lit < 0) { - res |= fact << 3; - } else { - res |= fact; - } - marks[vidx (lit)] = res; - CADICAL_assert (getfact (lit, fact)); -#ifndef CADICAL_NDEBUG - CADICAL_assert (getfact (-lit, fact) == before); -#endif - } - - void unmarkfact (int lit, int fact) { - CADICAL_assert (fact == 1 || fact == 2 || fact == 4); - CADICAL_assert (getfact (lit, fact)); - int res = marks[vidx (lit)]; - if (lit < 0) { - res &= ~(fact << 3); - } else { - res &= ~fact; - } - marks[vidx (lit)] = res; - CADICAL_assert (!getfact (lit, fact)); - } - - // Marking and unmarking of all literals in a clause. - // - void mark_clause (); // mark 'this->clause' - void mark (Clause *); - void mark2 (Clause *); - void unmark_clause (); // unmark 'this->clause' - void unmark (Clause *); - - // Watch literal 'lit' in clause with blocking literal 'blit'. - // Inlined here, since it occurs in the tight inner loop of 'propagate'. - // - inline void watch_literal (int lit, int blit, Clause *c) { - CADICAL_assert (lit != blit); - Watches &ws = watches (lit); - ws.push_back (Watch (blit, c)); - LOG (c, "watch %d blit %d in", lit, blit); - } - - // Add two watches to a clause. This is used initially during allocation - // of a clause and during connecting back all watches after preprocessing. - // - inline void watch_clause (Clause *c) { - const int l0 = c->literals[0]; - const int l1 = c->literals[1]; - watch_literal (l0, l1, c); - watch_literal (l1, l0, c); - } - - inline void unwatch_clause (Clause *c) { - const int l0 = c->literals[0]; - const int l1 = c->literals[1]; - remove_watch (watches (l0), c); - remove_watch (watches (l1), c); - } - - // Update queue to point to last potentially still unassigned variable. - // All variables after 'queue.unassigned' in bump order are assumed to be - // assigned. Then update the 'queue.bumped' field and log it. This is - // inlined here since it occurs in several inner loops. - // - inline void update_queue_unassigned (int idx) { - CADICAL_assert (0 < idx); - CADICAL_assert (idx <= max_var); - queue.unassigned = idx; - queue.bumped = btab[idx]; - LOG ("queue unassigned now %d bumped %" PRId64 "", idx, btab[idx]); - } - - void bump_queue (int idx); - - // Mark (active) variables as eliminated, substituted, pure or fixed, - // which turns them into inactive variables. - // - void mark_eliminated (int); - void mark_substituted (int); - void mark_active (int); - void mark_fixed (int); - void mark_pure (int); - - // Managing clauses in 'clause.cpp'. Without explicit 'Clause' argument - // these functions work on the global temporary 'clause'. - // - Clause *new_clause (bool red, int glue = 0); - void promote_clause (Clause *, int new_glue); - void promote_clause_glue_only (Clause *, int new_glue); - size_t shrink_clause (Clause *, int new_size); - void minimize_sort_clause (); - void shrink_and_minimize_clause (); - void reset_shrinkable (); - void mark_shrinkable_as_removable (int, std::vector::size_type); - int shrink_literal (int, int, unsigned); - unsigned shrunken_block_uip (int, int, - std::vector::reverse_iterator &, - std::vector::reverse_iterator &, - std::vector::size_type, const int); - void shrunken_block_no_uip (const std::vector::reverse_iterator &, - const std::vector::reverse_iterator &, - unsigned &, const int); - void push_literals_of_block (const std::vector::reverse_iterator &, - const std::vector::reverse_iterator &, - int, unsigned); - unsigned shrink_next (int, unsigned &, unsigned &); - std::vector::reverse_iterator - minimize_and_shrink_block (std::vector::reverse_iterator &, - unsigned int &, unsigned int &, const int); - unsigned shrink_block (std::vector::reverse_iterator &, - std::vector::reverse_iterator &, int, - unsigned &, unsigned &, const int, unsigned); - unsigned shrink_along_reason (int, int, bool, bool &, unsigned); - - void deallocate_clause (Clause *); - void delete_clause (Clause *); - void mark_garbage (Clause *); - void assign_original_unit (int64_t, int); - void add_new_original_clause (int64_t); - Clause *new_learned_redundant_clause (int glue); - Clause *new_hyper_binary_resolved_clause (bool red, int glue); - Clause *new_clause_as (const Clause *orig); - Clause *new_resolved_irredundant_clause (); - - // Forward reasoning through propagation in 'propagate.cpp'. - // - int assignment_level (int lit, Clause *); - void build_chain_for_units (int lit, Clause *reason, bool forced); - void build_chain_for_empty (); - void search_assign (int lit, Clause *); - void search_assign_driving (int lit, Clause *reason); - void search_assign_external (int lit); - void search_assume_decision (int decision); - void assign_unit (int lit); - int64_t cache_lines (size_t bytes) { return (bytes + 127) / 128; } - int64_t cache_lines (size_t n, size_t bytes) { - return cache_lines (n * bytes); - } - bool propagate (); - -#ifdef PROFILE_MODE - bool propagate_wrapper (); - bool propagate_unstable (); - bool propagate_stable (); - void analyze_wrapper (); - void analyze_unstable (); - void analyze_stable (); - int decide_wrapper (); - int decide_stable (); - int decide_unstable (); -#else -#define propagate_wrapper propagate -#define analyze_wrapper analyze -#define decide_wrapper decide -#endif - - void propergate (); // Repropagate without blocking literals. - - // Undo and restart in 'backtrack.cpp'. - // - void unassign (int lit); - void update_target_and_best (); - void backtrack (int target_level = 0); - void backtrack_without_updating_phases (int target_level = 0); - - // Minimized learned clauses in 'minimize.cpp'. - // - bool minimize_literal (int lit, int depth = 0); - void minimize_clause (); - void calculate_minimize_chain (int lit, std::vector &stack); - - // Learning from conflicts in 'analyze.cc'. - // - void learn_empty_clause (); - void learn_unit_clause (int lit); - - void bump_variable (int lit); - void bump_variables (); - int recompute_glue (Clause *); - void bump_clause (Clause *); - void bump_clause2 (Clause *); - void clear_unit_analyzed_literals (); - void clear_analyzed_literals (); - void clear_analyzed_levels (); - void clear_minimized_literals (); - bool bump_also_reason_literal (int lit); - void bump_also_reason_literals (int lit, int depth_limit, - size_t size_limit); - void bump_also_all_reason_literals (); - void analyze_literal (int lit, int &open, int &resolvent_size, - int &antecedent_size); - void analyze_reason (int lit, Clause *, int &open, int &resolvent_size, - int &antecedent_size); - Clause *new_driving_clause (const int glue, int &jump); - int find_conflict_level (int &forced); - int determine_actual_backtrack_level (int jump); - void otfs_strengthen_clause (Clause *, int, int, - const std::vector &); - void otfs_subsume_clause (Clause *subsuming, Clause *subsumed); - int otfs_find_backtrack_level (int &forced); - Clause *on_the_fly_strengthen (Clause *conflict, int lit); - void update_decision_rate_average (); - void analyze (); - void iterate (); // report learned unit clause - - // Learning from external propagator in 'external_propagate.cpp' - // - bool external_propagate (); - bool external_check_solution (); - void add_external_clause (int propagated_lit = 0, - bool no_backtrack = false); - Clause *learn_external_reason_clause (int lit, int falsified_elit = 0, - bool no_backtrack = false); - Clause *wrapped_learn_external_reason_clause (int lit); - void explain_external_propagations (); - void explain_reason (int lit, Clause *, int &open); - void move_literals_to_watch (); - void handle_external_clause (Clause *); - void notify_assignments (); - void notify_decision (); - void notify_backtrack (size_t new_level); - void force_backtrack (size_t new_level); - int ask_decision (); - bool ask_external_clause (); - void add_observed_var (int ilit); - void remove_observed_var (int ilit); - bool observed (int ilit) const; - bool is_decision (int ilit); - void check_watched_literal_invariants (); - void set_tainted_literal (); - void renotify_trail_after_ilb (); - void renotify_trail_after_local_search (); - void renotify_full_trail (); - void connect_propagator (); - void mark_garbage_external_forgettable (int64_t id); - bool is_external_forgettable (int64_t id); -#ifndef CADICAL_NDEBUG - bool get_merged_literals (std::vector &); - void get_all_fixed_literals (std::vector &); -#endif - - void recompute_tier (); - // Use last learned clause to subsume some more. - // - void eagerly_subsume_recently_learned_clauses (Clause *); - - // Restarting policy in 'restart.cc'. - // - bool stabilizing (); - bool restarting (); - int reuse_trail (); - void restart (); - - // Functions to set and reset certain 'phases'. - // - void clear_phases (vector &); // reset argument to zero - void copy_phases (vector &); // copy 'saved' to argument - - // Resetting the saved phased in 'rephase.cpp'. - // - bool rephasing (); - char rephase_best (); - char rephase_flipping (); - char rephase_inverted (); - char rephase_original (); - char rephase_random (); - char rephase_walk (); - void shuffle_scores (); - void shuffle_queue (); - void rephase (); - - // Lucky feasible case checking. - // - int unlucky (int res); - bool lucky_propagate_discrepency (int); - int trivially_false_satisfiable (); - int trivially_true_satisfiable (); - int forward_false_satisfiable (); - int forward_true_satisfiable (); - int backward_false_satisfiable (); - int backward_true_satisfiable (); - int positive_horn_satisfiable (); - int negative_horn_satisfiable (); - - // Asynchronous terminating check. - // - bool terminated_asynchronously (int factor = 1); - - bool search_limits_hit (); - - void terminate () { - LOG ("forcing asynchronous termination"); - termination_forced = true; - } - - // Reducing means determining useless clauses with 'reduce' in - // 'reduce.cpp' as well as root level satisfied clause and then removing - // those which are not used as reason anymore with garbage collection. - // - bool flushing (); - bool reducing (); - void protect_reasons (); - void mark_clauses_to_be_flushed (); - void mark_useless_redundant_clauses_as_garbage (); - bool propagate_out_of_order_units (); - void unprotect_reasons (); - void reduce (); - - // Garbage collection in 'collect.cpp' called from 'reduce' and during - // inprocessing and preprocessing. - // - int clause_contains_fixed_literal (Clause *); - void remove_falsified_literals (Clause *); - void mark_satisfied_clauses_as_garbage (); - void copy_clause (Clause *); - void flush_watches (int lit, Watches &); - size_t flush_occs (int lit); - void flush_all_occs_and_watches (); - void update_reason_references (); - void copy_non_garbage_clauses (); - void delete_garbage_clauses (); - void check_clause_stats (); - void check_var_stats (); - bool arenaing (); - void garbage_collection (); - - // only remove binary clauses from the watches - void remove_garbage_binaries (); - - // Set-up occurrence list counters and containers. - // - void init_occs (); - void init_bins (); - void init_noccs (); - void clear_noccs (); - void clear_occs (); - void reset_occs (); - void reset_bins (); - void reset_noccs (); - - // Operators on watches. - // - void init_watches (); - void connect_watches (bool irredundant_only = false); - void connect_binary_watches (); - void sort_watches (); - void clear_watches (); - void reset_watches (); - - // Regular forward subsumption checking in 'subsume.cpp'. - // - void strengthen_clause (Clause *, int); - void subsume_clause (Clause *subsuming, Clause *subsumed); - int subsume_check (Clause *subsuming, Clause *subsumed); - int try_to_subsume_clause (Clause *, vector &shrunken); - void reset_subsume_bits (); - bool subsume_round (); - void subsume (); - - // Covered clause elimination of large clauses. - // - void covered_literal_addition (int lit, Coveror &); - void asymmetric_literal_addition (int lit, Coveror &); - void cover_push_extension (int lit, Coveror &); - bool cover_propagate_asymmetric (int lit, Clause *ignore, Coveror &); - bool cover_propagate_covered (int lit, Coveror &); - bool cover_clause (Clause *c, Coveror &); - int64_t cover_round (); - bool cover (); - - // Strengthening through vivification in 'vivify.cpp'. - // - void demote_clause (Clause *); - void flush_vivification_schedule (std::vector &, int64_t &); - void vivify_increment_stats (const Vivifier &vivifier); - void vivify_subsume_clause (Clause *subsuming, Clause *subsumed); - void compute_tier_limits (Vivifier &); - void vivify_initialize (Vivifier &vivifier, int64_t &ticks); - inline void vivify_prioritize_leftovers (char, size_t prioritized, - std::vector &schedule); - bool consider_to_vivify_clause (Clause *candidate); - void vivify_sort_watched (Clause *c); - bool vivify_instantiate ( - const std::vector &, Clause *, - std::vector> &lrat_stack, - int64_t &ticks); - void vivify_analyze_redundant (Vivifier &, Clause *start, bool &); - void vivify_build_lrat (int, Clause *, - std::vector> &); - void vivify_chain_for_units (int lit, Clause *reason); - void vivify_strengthen (Clause *candidate); - void vivify_assign (int lit, Clause *); - void vivify_assume (int lit); - bool vivify_propagate (int64_t &); - void vivify_deduce (Clause *candidate, Clause *conflct, int implied, - Clause **, bool &); - bool vivify_clause (Vivifier &, Clause *candidate); - void vivify_analyze (Clause *start, bool &, Clause **, - const Clause *const, int implied, bool &); - bool vivify_shrinkable (const std::vector &sorted, Clause *c); - void vivify_round (Vivifier &, int64_t delta); - bool vivify (); - - // Compacting (shrinking internal variable tables) in 'compact.cpp' - // - bool compacting (); - void compact (); - - // Transitive reduction of binary implication graph in 'transred.cpp' - // - void transred (); - - // We monitor the maximum size and glue of clauses during 'reduce' and - // thus can predict if a redundant extended clause is likely to be kept in - // the next 'reduce' phase. These clauses are target of subsumption and - // vivification checks, in addition to irredundant clauses. Their - // variables are also marked as being 'added'. - // - bool likely_to_be_kept_clause (Clause *c) { - if (!c->redundant) - return true; - if (c->glue <= tier2[false]) - return true; - if (c->glue > lim.keptglue) - return false; - if (c->size > lim.keptsize) - return false; - return true; - } - - // We mark variables in added or shrunken clauses as 'subsume' candidates - // if the clause is likely to be kept in the next 'reduce' phase (see last - // function above). This gives a persistent (across consecutive - // interleaved search and inprocessing phases) set of variables which have - // to be reconsidered in subsumption checks, i.e., only clauses with - // 'subsume' marked variables are checked to be forward subsumed. - // A similar technique is used to reduce the effort in hyper ternary - // resolution to focus on variables in new ternary clauses. - // - void mark_subsume (int lit) { - Flags &f = flags (lit); - if (f.subsume) - return; - LOG ("marking %d as subsuming literal candidate", abs (lit)); - stats.mark.subsume++; - f.subsume = true; - } - void mark_ternary (int lit) { - Flags &f = flags (lit); - if (f.ternary) - return; - LOG ("marking %d as ternary resolution literal candidate", abs (lit)); - stats.mark.ternary++; - f.ternary = true; - } - void mark_factor (int lit) { - Flags &f = flags (lit); - const unsigned bit = bign (lit); - if (f.factor & bit) - return; - LOG ("marking %d as factor literal candidate", lit); - stats.mark.factor++; - f.factor |= bit; - } - void mark_added (int lit, int size, bool redundant); - void mark_added (Clause *); - - bool marked_subsume (int lit) const { return flags (lit).subsume; } - - // If irredundant clauses are removed or literals in clauses are removed, - // then variables in such clauses should be reconsidered to be eliminated - // through bounded variable elimination. In contrast to 'subsume' the - // 'elim' flag is restricted to 'irredundant' clauses only. For blocked - // clause elimination it is better to have a more precise signed version, - // which allows to independently mark positive and negative literals. - // - void mark_elim (int lit) { - Flags &f = flags (lit); - if (f.elim) - return; - LOG ("marking %d as elimination literal candidate", lit); - stats.mark.elim++; - f.elim = true; - } - void mark_block (int lit) { - Flags &f = flags (lit); - const unsigned bit = bign (lit); - if (f.block & bit) - return; - LOG ("marking %d as blocking literal candidate", lit); - stats.mark.block++; - f.block |= bit; - } - void mark_removed (int lit) { - mark_elim (lit); - mark_block (-lit); - } - void mark_removed (Clause *, int except = 0); - - // The following two functions are only used for testing & debugging. - - bool marked_block (int lit) const { - const Flags &f = flags (lit); - const unsigned bit = bign (lit); - return (f.block & bit) != 0; - } - void unmark_block (int lit) { - Flags &f = flags (lit); - const unsigned bit = bign (lit); - f.block &= ~bit; - } - - // During scheduling literals for blocked clause elimination we skip those - // literals which occur negated in a too large clause. - // - void mark_skip (int lit) { - Flags &f = flags (lit); - const unsigned bit = bign (lit); - if (f.skip & bit) - return; - LOG ("marking %d to be skipped as blocking literal", lit); - f.skip |= bit; - } - bool marked_skip (int lit) { - const Flags &f = flags (lit); - const unsigned bit = bign (lit); - return (f.skip & bit) != 0; - } - - // During decompose ignore literals where we already built LRAT chains - // - void mark_decomposed (int lit) { - Flags &f = flags (lit); - const unsigned bit = bign (lit); - CADICAL_assert ((f.marked_signed & bit) == 0); - sign_marked.push_back (lit); - f.marked_signed |= bit; - } - void unmark_decomposed (int lit) { - Flags &f = flags (lit); - const unsigned bit = bign (lit); - f.marked_signed &= ~bit; - } - bool marked_decomposed (int lit) { - const Flags &f = flags (lit); - const unsigned bit = bign (lit); - return (f.marked_signed & bit) != 0; - } - void clear_sign_marked_literals (); - - // Blocked Clause elimination in 'block.cpp'. - // - bool is_blocked_clause (Clause *c, int pivot); - void block_schedule (Blocker &); - size_t block_candidates (Blocker &, int lit); - Clause *block_impossible (Blocker &, int lit); - void block_literal_with_at_least_two_negative_occs (Blocker &, int lit); - void block_literal_with_one_negative_occ (Blocker &, int lit); - void block_pure_literal (Blocker &, int lit); - void block_reschedule_clause (Blocker &, int lit, Clause *); - void block_reschedule (Blocker &, int lit); - void block_literal (Blocker &, int lit); - bool block (); - - // Find gates in 'gates.cpp' for bounded variable substitution. - // - int second_literal_in_binary_clause_lrat (Clause *, int first); - int second_literal_in_binary_clause (Eliminator &, Clause *, int first); - void mark_binary_literals (Eliminator &, int pivot); - void find_and_gate (Eliminator &, int pivot); - void find_equivalence (Eliminator &, int pivot); - - bool get_ternary_clause (Clause *, int &, int &, int &); - bool match_ternary_clause (Clause *, int, int, int); - Clause *find_ternary_clause (int, int, int); - - bool get_clause (Clause *, vector &); - bool is_clause (Clause *, const vector &); - Clause *find_clause (const vector &); - void find_xor_gate (Eliminator &, int pivot); - - void find_if_then_else (Eliminator &, int pivot); - - Clause *find_binary_clause (int, int); - void find_gate_clauses (Eliminator &, int pivot); - void unmark_gate_clauses (Eliminator &); - - // mine definitions for cadical_kitten in 'definition.cpp' - // - void find_definition (Eliminator &, int); - void init_citten (); - void reset_citten (); - void citten_clear_track_log_terminate (); - - // Bounded variable elimination in 'elim.cpp'. - // - bool ineliminating (); - double compute_elim_score (unsigned lit); - void mark_redundant_clauses_with_eliminated_variables_as_garbage (); - void unmark_binary_literals (Eliminator &); - bool resolve_clauses (Eliminator &, Clause *, int pivot, Clause *, bool); - void mark_eliminated_clauses_as_garbage (Eliminator &, int pivot, bool &); - bool elim_resolvents_are_bounded (Eliminator &, int pivot); - void elim_update_removed_lit (Eliminator &, int lit); - void elim_update_removed_clause (Eliminator &, Clause *, int except = 0); - void elim_update_added_clause (Eliminator &, Clause *); - void elim_add_resolvents (Eliminator &, int pivot); - void elim_backward_clause (Eliminator &, Clause *); - void elim_backward_clauses (Eliminator &); - void elim_propagate (Eliminator &, int unit); - void elim_on_the_fly_self_subsumption (Eliminator &, Clause *, int); - void try_to_eliminate_variable (Eliminator &, int pivot, bool &); - void increase_elimination_bound (); - int elim_round (bool &completed, bool &); - void elim (bool update_limits = true); - - int64_t flush_elimfast_occs (int lit); - void elimfast_add_resolvents (Eliminator &, int pivot); - bool elimfast_resolvents_are_bounded (Eliminator &, int pivot); - void try_to_fasteliminate_variable (Eliminator &, int pivot, bool &); - int elimfast_round (bool &completed, bool &); - void elimfast (); - - // sweeping in 'sweep.cpp' - int sweep_solve (); - void sweep_set_cadical_kitten_ticks_limit (Sweeper &sweeper); - bool cadical_kitten_ticks_limit_hit (Sweeper &sweeper, const char *when); - void init_sweeper (Sweeper &sweeper); - void release_sweeper (Sweeper &sweeper); - void clear_sweeper (Sweeper &sweeper); - int sweep_repr (Sweeper &sweeper, int lit); - void add_literal_to_environment (Sweeper &sweeper, unsigned depth, int); - void sweep_clause (Sweeper &sweeper, unsigned depth, Clause *); - void sweep_add_clause (Sweeper &sweeper, unsigned depth); - void add_core (Sweeper &sweeper, unsigned core_idx); - void save_core (Sweeper &sweeper, unsigned core); - void clear_core (Sweeper &sweeper, unsigned core_idx); - void save_add_clear_core (Sweeper &sweeper); - void init_backbone_and_partition (Sweeper &sweeper); - void sweep_empty_clause (Sweeper &sweeper); - void sweep_refine_partition (Sweeper &sweeper); - void sweep_refine_backbone (Sweeper &sweeper); - void sweep_refine (Sweeper &sweeper); - void flip_backbone_literals (struct Sweeper &sweeper); - bool sweep_backbone_candidate (Sweeper &sweeper, int lit); - int64_t add_sweep_binary (sweep_proof_clause, int lit, int other); - bool scheduled_variable (Sweeper &sweeper, int idx); - void schedule_inner (Sweeper &sweeper, int idx); - void schedule_outer (Sweeper &sweeper, int idx); - int next_scheduled (Sweeper &sweeper); - void substitute_connected_clauses (Sweeper &sweeper, int lit, int other, - int64_t id); - void sweep_remove (Sweeper &sweeper, int lit); - void flip_partition_literals (struct Sweeper &sweeper); - const char *sweep_variable (Sweeper &sweeper, int idx); - bool scheduable_variable (Sweeper &sweeper, int idx, size_t *occ_ptr); - unsigned schedule_all_other_not_scheduled_yet (Sweeper &sweeper); - bool sweep_equivalence_candidates (Sweeper &sweeper, int lit, int other); - unsigned reschedule_previously_remaining (Sweeper &sweeper); - unsigned incomplete_variables (); - void mark_incomplete (Sweeper &sweeper); - unsigned schedule_sweeping (Sweeper &sweeper); - void unschedule_sweeping (Sweeper &sweeper, unsigned swept, - unsigned scheduled); - bool sweep (); - void sweep_dense_propagate (Sweeper &sweeper); - void sweep_sparse_mode (); - void sweep_dense_mode_and_watch_irredundant (); - void sweep_substitute_lrat (Clause *c, int64_t id); - void sweep_substitute_new_equivalences (Sweeper &sweeper); - void sweep_update_noccs (Clause *c); - void delete_sweep_binary (const sweep_binary &sb); - bool can_sweep_clause (Clause *c); - bool sweep_flip (int); - int sweep_flip_and_implicant (int); - bool sweep_extract_fixed (Sweeper &sweeper, int lit); - - // factor - void factor_mode (); - void reset_factor_mode (); - double tied_next_factor_score (int); - Quotient *new_quotient (Factoring &, int); - void release_quotients (Factoring &); - size_t first_factor (Factoring &, int); - void clear_nounted (vector &); - void clear_flauses (vector &); - Quotient *best_quotient (Factoring &, size_t *); - int next_factor (Factoring &, unsigned *); - void factorize_next (Factoring &, int, unsigned); - void resize_factoring (Factoring &factoring, int lit); - void flush_unmatched_clauses (Quotient *); - void add_self_subsuming_factor (Quotient *, Quotient *); - bool self_subsuming_factor (Quotient *); - void add_factored_divider (Quotient *, int); - void blocked_clause (Quotient *q, int); - void add_factored_quotient (Quotient *, int not_fresh); - void eagerly_remove_from_occurences (Clause *c); - void delete_unfactored (Quotient *q); - void update_factored (Factoring &factoring, Quotient *q); - bool apply_factoring (Factoring &factoring, Quotient *q); - void update_factor_candidate (Factoring &, int); - void schedule_factorization (Factoring &); - bool run_factorization (int64_t limit); - bool factor (); - int get_new_extension_variable (); - Clause *new_factor_clause (); - - // instantiate - // - void inst_assign (int lit); - bool inst_propagate (); - void collect_instantiation_candidates (Instantiator &); - bool instantiate_candidate (int lit, Clause *); - void instantiate (Instantiator &); - - void new_trail_level (int lit); - - // Hyper ternary resolution. - // - bool ternary_find_binary_clause (int, int); - bool ternary_find_ternary_clause (int, int, int); - Clause *new_hyper_ternary_resolved_clause (bool red); - Clause *new_hyper_ternary_resolved_clause_and_watch (bool red, bool); - bool hyper_ternary_resolve (Clause *, int, Clause *); - void ternary_lit (int pivot, int64_t &steps, int64_t &htrs); - void ternary_idx (int idx, int64_t &steps, int64_t &htrs); - bool ternary_round (int64_t &steps, int64_t &htrs); - bool ternary (); - - // Probing in 'probe.cpp'. - // - bool inprobing (); - void failed_literal (int lit); - void probe_lrat_for_units (int lit); - void probe_assign_unit (int lit); - void probe_assign_decision (int lit); - void probe_assign (int lit, int parent); - void mark_duplicated_binary_clauses_as_garbage (); - int get_parent_reason_literal (int lit); - void set_parent_reason_literal (int lit, int reason); - void clean_probehbr_lrat (); - void init_probehbr_lrat (); - void get_probehbr_lrat (int lit, int uip); - void set_probehbr_lrat (int lit, int uip); - void probe_post_dominator_lrat (vector &, int, int); - void probe_dominator_lrat (int dom, Clause *reason); - int probe_dominator (int a, int b); - int hyper_binary_resolve (Clause *); - void probe_propagate2 (); - bool probe_propagate (); - bool is_binary_clause (Clause *c, int &, int &); - void generate_probes (); - void flush_probes (); - int next_probe (); - bool probe (); - void inprobe (bool update_limits = true); - - // ProbSAT/WalkSAT implementation called initially or from 'rephase'. - // - void walk_save_minimum (Walker &); - Clause *walk_pick_clause (Walker &); - unsigned walk_break_value (int lit); - int walk_pick_lit (Walker &, Clause *); - void walk_flip_lit (Walker &, int lit); - int walk_round (int64_t limit, bool prev); - void walk (); - - // Detect strongly connected components in the binary implication graph - // (BIG) and equivalent literal substitution (ELS) in 'decompose.cpp'. - // - void decompose_conflicting_scc_lrat (DFS *dfs, vector &); - void build_lrat_for_clause (const vector> &dfs_chains, - bool invert = false); - vector decompose_analyze_binary_clauses (DFS *dfs, int from); - void decompose_analyze_binary_chain (DFS *dfs, int); - bool decompose_round (); - void decompose (); - - void reset_limits (); // Reset after 'solve' call. - - // Try flipping a literal while not falsifying a model. - - bool flip (int lit); - bool flippable (int lit); - - // Assumption handling. - // - void assume_analyze_literal (int lit); - void assume_analyze_reason (int lit, Clause *reason); - void assume (int); // New assumption literal. - bool failed (int lit); // Literal failed assumption? - void reset_assumptions (); // Reset after 'solve' call. - void sort_and_reuse_assumptions (); // reorder the assumptions in order to - // reuse parts of the trail - void failing (); // Prepare failed assumptions. - - bool assumed (int lit) { // Marked as assumption. - Flags &f = flags (lit); - const unsigned bit = bign (lit); - return (f.assumed & bit) != 0; - } - - // Add temporary clause as constraint. - // - void constrain (int); // Add literal to constraint. - bool - failed_constraint (); // Was constraint used to proof unsatisfiablity? - void reset_constraint (); // Reset after 'solve' call. - - // Propagate the current set of assumptions and return the - // non-witness assigned literals - int propagate_assumptions (); - void implied (std::vector &entrailed); - - // Forcing decision variables to a certain phase. - // - void phase (int lit); - void unphase (int lit); - - // Globally blocked clause elimination. - // - bool is_autarky_literal (int lit) const; - bool is_conditional_literal (int lit) const; - void mark_as_conditional_literal (int lit); - void unmark_as_conditional_literal (int lit); - // - bool is_in_candidate_clause (int lit) const; - void mark_in_candidate_clause (int lit); - void unmark_in_candidate_clause (int lit); - // - void condition_assign (int lit); - void condition_unassign (int lit); - // - bool conditioning (); - long condition_round (long unassigned_literal_propagation_limit); - void condition (bool update_limits = true); - - // Part on picking the next decision in 'decide.cpp'. - // - bool satisfied (); - int next_decision_variable_on_queue (); - int next_decision_variable_with_best_score (); - int next_decision_variable (); - int decide_phase (int idx, bool target); - int likely_phase (int idx); - bool better_decision (int lit, int other); - int decide (); // 0=decision, 20=failed - - // Internal functions to enable explicit search limits. - // - void limit_terminate (int); - void limit_decisions (int); // Force decision limit. - void limit_conflicts (int); // Force conflict limit. - void limit_preprocessing (int); // Enable 'n' preprocessing rounds. - void limit_local_search (int); // Enable 'n' local search rounds. - - // External versions can access limits by 'name'. - // - static bool is_valid_limit (const char *name); - bool limit (const char *name, int); // 'true' if 'name' valid - - // Set all the CDCL search limits and increments for scheduling - // inprocessing, restarts, clause database reductions, etc. - // - void init_report_limits (); - void init_preprocessing_limits (); - void init_search_limits (); - - // The computed averages are local to the 'stable' and 'unstable' phase. - // Their main use is to be reported in 'report', except for the 'glue' - // averages, which are used to schedule (prohibit actually) restarts - // during 'unstable' phases ('stable' phases use reluctant doubling). - // - void init_averages (); - void swap_averages (); - - int try_to_satisfy_formula_by_saved_phases (); - void produce_failed_assumptions (); - - // Main solve & search functions in 'internal.cpp'. - // - // We have three pre-solving techniques. These consist of preprocessing, - // local search and searching for lucky phases, which in full solving - // mode except for the last are usually optional and then followed by - // the main CDCL search loop with inprocessing. If only preprocessing - // is requested from 'External::simplify' only preprocessing is called - // though. This is all orchestrated by the 'solve' function. - // - int already_solved (); - int restore_clauses (); - bool preprocess_round (int round); - void preprocess_quickly (); - int preprocess (); - int local_search_round (int round); - int local_search (); - int lucky_phases (); - int cdcl_loop_with_inprocessing (); - void reset_solving (); - int solve (bool preprocess_only = false); - void finalize (int); - - // - int lookahead (); - CubesWithStatus generate_cubes (int, int); - int most_occurring_literal (); - int lookahead_probing (); - int lookahead_next_probe (); - void lookahead_flush_probes (); - void lookahead_generate_probes (); - std::vector lookahead_populate_locc (); - int lookahead_locc (const std::vector &); - - bool terminating_asked (); - -#ifndef CADICAL_QUIET - // Built in profiling in 'profile.cpp' (see also 'profile.hpp'). - // - void start_profiling (Profile &p, double); - void stop_profiling (Profile &p, double); - - double update_profiles (); // Returns 'time ()'. - void print_profile (); -#endif - - // Get the value of an internal literal: -1=false, 0=unassigned, 1=true. - // We use a redundant table for both negative and positive literals. This - // allows a branch-less check for the value of literal and is considered - // substantially faster than negating the result if the argument is - // negative. We also avoid taking the absolute value. - // - signed char val (int lit) const { - CADICAL_assert (-max_var <= lit); - CADICAL_assert (lit); - CADICAL_assert (lit <= max_var); - return vals[lit]; - } - - // As suggested by Matt Ginsberg it might be useful to factor-out a common - // setter function for setting and resetting the value of a literal. - // - void set_val (int lit, signed char val) { - CADICAL_assert (-1 <= val); - CADICAL_assert (val <= 1); - CADICAL_assert (-max_var <= lit); - CADICAL_assert (lit); - CADICAL_assert (lit <= max_var); - vals[lit] = val; - vals[-lit] = -val; - } - - // As 'val' but restricted to the root-level value of a literal. - // It is not that time critical and also needs to check the decision level - // of the variable anyhow. - // - int fixed (int lit) { - CADICAL_assert (-max_var <= lit); - CADICAL_assert (lit); - CADICAL_assert (lit <= max_var); - const int idx = vidx (lit); - int res = vals[idx]; - if (res && vtab[idx].level) - res = 0; - if (lit < 0) - res = -res; - return res; - } - - // Map back an internal literal to an external. - // - int externalize (int lit) { - CADICAL_assert (lit != INT_MIN); - const int idx = abs (lit); - CADICAL_assert (idx); - CADICAL_assert (idx <= max_var); - int res = i2e[idx]; - if (lit < 0) - res = -res; - return res; - } - - // Explicit freezing and melting of variables. - // - void freeze (int lit) { - int idx = vidx (lit); - if ((size_t) idx >= frozentab.size ()) { - size_t new_vsize = vsize ? 2 * vsize : 1 + (size_t) max_var; - while (new_vsize <= (size_t) max_var) - new_vsize *= 2; - frozentab.resize (new_vsize); - } - unsigned &ref = frozentab[idx]; - if (ref < UINT_MAX) { - ref++; - LOG ("variable %d frozen %u times", idx, ref); - } else - LOG ("variable %d remains frozen forever", idx); - } - void melt (int lit) { - int idx = vidx (lit); - unsigned &ref = frozentab[idx]; - if (ref < UINT_MAX) { - if (!--ref) { - if (relevanttab[idx]) { - LOG ("variable %d is observed, can not be completely molten", - idx); - ref++; - } else - LOG ("variable %d completely molten", idx); - } else - LOG ("variable %d melted once but remains frozen %u times", lit, - ref); - } else - LOG ("variable %d remains frozen forever", idx); - } - bool frozen (int lit) { - return (size_t) vidx (lit) < frozentab.size () && - frozentab[vidx (lit)] > 0; - } - - // Congruence closure - bool extract_gates (); - - // Parsing functions in 'parse.cpp'. - // - const char *parse_dimacs (FILE *); - const char *parse_dimacs (const char *); - const char *parse_solution (const char *); - - // Enable and disable proof logging and checking. - // - void new_proof_on_demand (); - void force_lrat (); // sets lrat=true - void resize_unit_clauses_idx (); // resizes unit_clauses_idx - void close_trace (bool stats = false); // Stop proof tracing. - void flush_trace (bool stats = false); // Flush proof trace file. - void trace (File *); // Start write proof file. - void check (); // Enable online proof checking. - - void connect_proof_tracer (Tracer *tracer, bool antecedents, - bool finalize_clauses = false); - void connect_proof_tracer (InternalTracer *tracer, bool antecedents, - bool finalize_clauses = false); - void connect_proof_tracer (StatTracer *tracer, bool antecedents, - bool finalize_clauses = false); - void connect_proof_tracer (FileTracer *tracer, bool antecedents, - bool finalize_clauses = false); - bool disconnect_proof_tracer (Tracer *tracer); - bool disconnect_proof_tracer (StatTracer *tracer); - bool disconnect_proof_tracer (FileTracer *tracer); - void conclude_unsat (); - void reset_concluded (); - - // Dump to '' as DIMACS for debugging. - // - void dump (Clause *); - void dump (); - - // Export and traverse all irredundant (non-unit) clauses. - // - bool traverse_clauses (ClauseIterator &); - - // Export and traverse all irredundant (non-unit) clauses. - // - bool traverse_constraint (ClauseIterator &); - - /*----------------------------------------------------------------------*/ - - double solve_time (); // accumulated time spent in 'solve ()' - - double process_time () const; // since solver was initialized - double real_time () const; // since solver was initialized - - double time () { return opts.realtime ? real_time () : process_time (); } - - // Regularly reports what is going on in 'report.cpp'. - // - void report (char type, int verbose_level = 0); - void report_solving (int); - - void print_statistics (); - void print_resource_usage (); - - /*----------------------------------------------------------------------*/ - -#ifndef CADICAL_QUIET - - void print_prefix (); - - // Non-verbose messages and warnings, i.e., always printed unless 'quiet' - // is set, which disables messages at run-time, or even 'CADICAL_QUIET' is defined - // through the configuration option './configure --quiet', which disables - // such messages completely at compile-time. - // - void vmessage (const char *, va_list &); - void message (const char *, ...) CADICAL_ATTRIBUTE_FORMAT (2, 3); - void message (); // empty line - - // Verbose messages with explicit verbose 'level' controlled by - // 'opts.verbose' (verbose level '0' gives the same as 'message'). - // - void vverbose (int level, const char *fmt, va_list &); - void verbose (int level, const char *fmt, ...) - CADICAL_ATTRIBUTE_FORMAT (3, 4); - void verbose (int level); - - // This is for printing section headers in the form - // - // c ---- [ ] --------------------- - // - // nicely aligned (and of course is ignored if 'quiet' is set). - // - void section (const char *title); - - // Print verbose message about phases if 'opts.verbose > 1' (but not if - // 'quiet' is set). Note that setting 'log' or '-l' forces all verbose - // output (and also ignores 'quiet' set to true'). The 'phase' argument - // is used to print a 'phase' prefix for the message as follows: - // - // c [<phase>] ... - // - void phase (const char *phase, const char *, ...) - CADICAL_ATTRIBUTE_FORMAT (3, 4); - - // Same as the last 'phase' above except that the prefix gets a count: - // - // c [<phase>-<count>] ... - // - void phase (const char *phase, int64_t count, const char *, ...) - CADICAL_ATTRIBUTE_FORMAT (4, 5); -#endif - - // Print error messages which are really always printed (even if 'quiet' - // is set). This leads to exit the current process with exit status '1'. - // - // TODO add possibility to use a call back instead of calling exit. - // - void error_message_end (); - void verror (const char *, va_list &); - void error (const char *, ...) CADICAL_ATTRIBUTE_FORMAT (2, 3); - void error_message_start (); - - // Warning messages. - // - void warning (const char *, ...) CADICAL_ATTRIBUTE_FORMAT (2, 3); -}; - -// Fatal internal error which leads to abort. -// -void fatal_message_start (); -void fatal_message_end (); -void fatal (const char *, ...) CADICAL_ATTRIBUTE_FORMAT (1, 2); - -/*------------------------------------------------------------------------*/ - -// Has to be put here, i.e., not into 'score.hpp', since we need the -// definition of 'Internal::score' above (after '#include "score.hpp"'). - -inline bool score_smaller::operator() (unsigned a, unsigned b) { - - // Avoid computing twice 'abs' in 'score ()'. - // - CADICAL_assert (1 <= a); - CADICAL_assert (a <= (unsigned) internal->max_var); - CADICAL_assert (1 <= b); - CADICAL_assert (b <= (unsigned) internal->max_var); - double s = internal->stab[a]; - double t = internal->stab[b]; - - if (s < t) - return true; - if (s > t) - return false; - - return a > b; -} - -/*------------------------------------------------------------------------*/ - -// Implemented here for keeping it all inline (requires Internal::fixed). - -inline int External::fixed (int elit) const { - CADICAL_assert (elit); - CADICAL_assert (elit != INT_MIN); - int eidx = abs (elit); - if (eidx > max_var) - return 0; - int ilit = e2i[eidx]; - if (!ilit) - return 0; - if (elit < 0) - ilit = -ilit; - return internal->fixed (ilit); -} - -/*------------------------------------------------------------------------*/ - -// We want to have termination checks inlined, particularly the first -// function which appears in preprocessor loops. Even though this first -// 'termination_forced' is set asynchronously, this should not lead to a -// data race issue (it also has been declared 'volatile'). - -inline bool Internal::terminated_asynchronously (int factor) { - // First way of asynchronous termination is through 'terminate' which sets - // the 'termination_forced' flag directly. The second way is through a - // call back to a 'terminator' if it is non-zero, which however is costly. - // - if (termination_forced) { - LOG ("termination asynchronously forced"); - return true; - } - - // This is only for testing and debugging asynchronous termination calls. - // In production code this could be removed but then should not be costly - // and keeping it will allow to test correctness of asynchronous - // termination on the production platform too. After this triggers we - // have to set the 'termination_forced' flag, such that subsequent calls - // to this function do not check this again. - // - if (lim.terminate.forced) { - CADICAL_assert (lim.terminate.forced > 0); - if (lim.terminate.forced-- == 1) { - LOG ("internally forcing termination"); - termination_forced = true; - return true; - } - LOG ("decremented internal forced termination limit to %d", - lim.terminate.forced); - } - - // The second way of asynchronous termination is through registering and - // calling an external 'Terminator' object. This is of course more costly - // than just checking a (volatile though) boolean flag, particularly in - // tight loops. To avoid this cost we only call the terminator in - // intervals of 'opts.terminateint', which in addition can be scaled up by - // the argument 'factor'. If the terminator returns 'true' we set the - // 'termination_forced' flag to 'true' in order to remember the - // termination status and to avoid the terminator again. Setting this - // flag leads to the first test above to succeed in subsequent calls. - // - if (external->terminator && !lim.terminate.check--) { - CADICAL_assert (factor > 0); - CADICAL_assert (INT_MAX / factor > opts.terminateint); - lim.terminate.check = factor * opts.terminateint; - if (external->terminator->terminate ()) { - termination_forced = true; // Cache it. - LOG ("connected terminator forces termination"); - return true; - } - } - - return false; -} - -/*------------------------------------------------------------------------*/ - -inline bool Internal::search_limits_hit () { - CADICAL_assert (!preprocessing); - CADICAL_assert (!localsearching); - - if (lim.conflicts >= 0 && stats.conflicts >= lim.conflicts) { - LOG ("conflict limit %" PRId64 " reached", lim.conflicts); - return true; - } - - if (lim.decisions >= 0 && stats.decisions >= lim.decisions) { - LOG ("decision limit %" PRId64 " reached", lim.decisions); - return true; - } - - return false; -} - -/*------------------------------------------------------------------------*/ - -} // namespace CaDiCaL - -ABC_NAMESPACE_CXX_HEADER_END - -#endif diff --git a/src/sat/cadical/inttypes.hpp b/src/sat/cadical/inttypes.hpp deleted file mode 100644 index 2f7cb74a4..000000000 --- a/src/sat/cadical/inttypes.hpp +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef _inttypes_h_INCLUDED -#define _inttypes_h_INCLUDED - -#include "global.h" - -// This is an essence a wrapper around '<cinttypes>' respectively -// 'inttypes.h' in order to please the 'MinGW' cross-compiler (we are using -// 'i686-w64-mingw32-gcc') to produce correct 'printf' style formatting for -// 64-bit numbers as this does not work out-of-the-box (which is also very -// annoying). This also produces lots of warnings (through '-Wformat' and -// the corresponding 'attribute' declaration for 'printf' style functions). -// Again 'MinGW' is not fully standard compliant here and we have to cover -// up for that manually. - -// We repeat the code on making this work which is also contained in -// 'cadical.hpp' as we do not want to require users of the library to -// include another header file (like this one) beside 'cadical.hpp'. - -#ifndef PRINTF_FORMAT -#ifdef __MINGW32__ -#define __USE_MINGW_ANSI_STDIO 1 -#define PRINTF_FORMAT __MINGW_PRINTF_FORMAT -#else -#define PRINTF_FORMAT printf -#endif -#endif - -#include <cinttypes> - -#endif diff --git a/src/sat/cadical/ipasir.h b/src/sat/cadical/ipasir.h deleted file mode 100644 index ccb610130..000000000 --- a/src/sat/cadical/ipasir.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef _ipasir_h_INCLUDED -#define _ipasir_h_INCLUDED - -#include "global.h" - -/*------------------------------------------------------------------------*/ -ABC_NAMESPACE_HEADER_START -/*------------------------------------------------------------------------*/ - -// Here are the declarations for the actual IPASIR functions, which is the -// generic incremental reentrant SAT solver API used for instance in the SAT -// competition. The other 'C' API in 'ccadical.h' is (more) type safe and -// has additional functions only supported by the CaDiCaL library. Please -// also refer to our SAT Race 2015 article in the Journal of AI from 2016. - -const char *ipasir_signature (void); -void *ipasir_init (void); -void ipasir_release (void *solver); -void ipasir_add (void *solver, int lit); -void ipasir_assume (void *solver, int lit); -int ipasir_solve (void *solver); -int ipasir_val (void *solver, int lit); -int ipasir_failed (void *solver, int lit); - -void ipasir_set_terminate (void *solver, void *state, - int (*terminate) (void *state)); - -void ipasir_set_learn (void *solver, void *state, int max_length, - void (*learn) (void *state, int *clause)); - -/*------------------------------------------------------------------------*/ -ABC_NAMESPACE_HEADER_END -/*------------------------------------------------------------------------*/ - -#endif diff --git a/src/sat/cadical/kitten.h b/src/sat/cadical/kitten.h deleted file mode 100644 index c70d47b0d..000000000 --- a/src/sat/cadical/kitten.h +++ /dev/null @@ -1,95 +0,0 @@ -#ifndef _cadical_kitten_h_INCLUDED -#define _cadical_kitten_h_INCLUDED - -#include "global.h" - -#include <stdbool.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> - -ABC_NAMESPACE_HEADER_START - -typedef struct cadical_kitten cadical_kitten; - -cadical_kitten *cadical_kitten_init (void); -void cadical_kitten_clear (cadical_kitten *); -void cadical_kitten_release (cadical_kitten *); - -#ifdef LOGGING -void cadical_kitten_set_logging (cadical_kitten *cadical_kitten); -#endif - -void cadical_kitten_track_antecedents (cadical_kitten *); - -void cadical_kitten_shuffle_clauses (cadical_kitten *); -void cadical_kitten_flip_phases (cadical_kitten *); -void cadical_kitten_randomize_phases (cadical_kitten *); - -void cadical_kitten_assume (cadical_kitten *, unsigned lit); -void cadical_kitten_assume_signed (cadical_kitten *, int lit); - -void cadical_kitten_clause (cadical_kitten *, size_t size, unsigned *); -void citten_clause_with_id (cadical_kitten *, unsigned id, size_t size, int *); -void cadical_kitten_unit (cadical_kitten *, unsigned); -void cadical_kitten_binary (cadical_kitten *, unsigned, unsigned); - -void cadical_kitten_clause_with_id_and_exception (cadical_kitten *, unsigned id, - size_t size, const unsigned *, - unsigned except); - -void citten_clause_with_id_and_exception (cadical_kitten *, unsigned id, - size_t size, const int *, - unsigned except); -void citten_clause_with_id_and_equivalence (cadical_kitten *, unsigned id, - size_t size, const int *, - unsigned, unsigned); -void cadical_kitten_no_ticks_limit (cadical_kitten *); -void cadical_kitten_set_ticks_limit (cadical_kitten *, uint64_t); -uint64_t cadical_kitten_current_ticks (cadical_kitten *); - -void cadical_kitten_no_terminator (cadical_kitten *); -void cadical_kitten_set_terminator (cadical_kitten *, void *, int (*) (void *)); - -int cadical_kitten_solve (cadical_kitten *); -int cadical_kitten_status (cadical_kitten *); - -signed char cadical_kitten_value (cadical_kitten *, unsigned); -signed char cadical_kitten_signed_value (cadical_kitten *, int); // converts second argument -signed char cadical_kitten_fixed (cadical_kitten *, unsigned); -signed char cadical_kitten_fixed_signed (cadical_kitten *, int); // converts -bool cadical_kitten_failed (cadical_kitten *, unsigned); -bool cadical_kitten_flip_literal (cadical_kitten *, unsigned); -bool cadical_kitten_flip_signed_literal (cadical_kitten *, int); - -unsigned cadical_kitten_compute_clausal_core (cadical_kitten *, uint64_t *learned); -void cadical_kitten_shrink_to_clausal_core (cadical_kitten *); - -void cadical_kitten_traverse_core_ids (cadical_kitten *, void *state, - void (*traverse) (void *state, unsigned id)); - -void cadical_kitten_traverse_core_clauses (cadical_kitten *, void *state, - void (*traverse) (void *state, - bool learned, size_t, - const unsigned *)); -void cadical_kitten_traverse_core_clauses_with_id ( - cadical_kitten *, void *state, - void (*traverse) (void *state, unsigned, bool learned, size_t, - const unsigned *)); -void cadical_kitten_trace_core (cadical_kitten *, void *state, - void (*trace) (void *, unsigned, unsigned, bool, - size_t, const unsigned *, size_t, - const unsigned *)); - -int cadical_kitten_compute_prime_implicant (cadical_kitten *cadical_kitten, void *state, - bool (*ignore) (void *, unsigned)); - -void cadical_kitten_add_prime_implicant (cadical_kitten *cadical_kitten, void *state, int side, - void (*add_implicant) (void *, int, size_t, - const unsigned *)); - -int cadical_kitten_flip_and_implicant_for_signed_literal (cadical_kitten *cadical_kitten, int elit); - -ABC_NAMESPACE_HEADER_END - -#endif diff --git a/src/sat/cadical/level.hpp b/src/sat/cadical/level.hpp deleted file mode 100644 index bbfe774ff..000000000 --- a/src/sat/cadical/level.hpp +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef _level_hpp_INCLUDED -#define _level_hpp_INCLUDED - -#include "global.h" - -#include <climits> - -ABC_NAMESPACE_CXX_HEADER_START - -namespace CaDiCaL { - -// For each new decision we increase the decision level and push a 'Level' -// on the 'control' stack. The information gathered here is used in -// 'reuse_trail' and for early aborts in clause minimization. - -struct Level { - - int decision; // decision literal of this level - int trail; // trail start of this level - - struct { - int count; // how many variables seen during 'analyze' - int trail; // smallest trail position seen on this level - } seen; - - void reset () { - seen.count = 0; - seen.trail = INT_MAX; - } - - Level (int d, int t) : decision (d), trail (t) { reset (); } - Level () {} -}; - -} // namespace CaDiCaL - -ABC_NAMESPACE_CXX_HEADER_END - -#endif diff --git a/src/sat/cadical/lidruptracer.hpp b/src/sat/cadical/lidruptracer.hpp deleted file mode 100644 index 02cd33fcd..000000000 --- a/src/sat/cadical/lidruptracer.hpp +++ /dev/null @@ -1,123 +0,0 @@ -#ifndef _lidruptracer_h_INCLUDED -#define _lidruptracer_h_INCLUDED - -#include "global.h" - -ABC_NAMESPACE_CXX_HEADER_START - -class FileTracer; - -namespace CaDiCaL { - -struct LidrupClause { - LidrupClause *next; // collision chain link for hash table - uint64_t hash; // previously computed full 64-bit hash - int64_t id; // id of clause - std::vector<int64_t> chain; - std::vector<int> literals; -}; - -class LidrupTracer : public FileTracer { - - Internal *internal; - File *file; - bool binary; - bool piping; // The 'file' is a pipe and needs eagerly flushing. - - // hash table for conclusion - // - uint64_t num_clauses; // number of clauses in hash table - uint64_t size_clauses; // size of clause hash table - LidrupClause **clauses; // hash table of clauses - vector<int> imported_clause; - vector<int> assumptions; - vector<int64_t> imported_chain; - vector<int64_t> batch_weaken; - vector<int64_t> batch_delete; - vector<int64_t> batch_restore; - - static const unsigned num_nonces = 4; - - uint64_t nonces[num_nonces]; // random numbers for hashing - uint64_t last_hash; // last computed hash value of clause - int64_t last_id; // id of the last added clause - LidrupClause *last_clause; - uint64_t compute_hash (int64_t); // compute and save hash value of clause - - LidrupClause *new_clause (); - void delete_clause (LidrupClause *); - - static uint64_t reduce_hash (uint64_t hash, uint64_t size); - - void enlarge_clauses (); // enlarge hash table for clauses - void insert (); // insert clause in hash table - bool - find_and_delete (const int64_t); // find clause position in hash table - -#ifndef CADICAL_QUIET - int64_t added, deleted, weakened, restore, original, solved, batched; -#endif - - void flush_if_piping (); - - void put_binary_zero (); - void put_binary_lit (int external_lit); - void put_binary_id (int64_t id, bool = true); - - void lidrup_add_derived_clause (int64_t id, const vector<int> &clause, - const vector<int64_t> &chain); - void lidrup_delete_clause (int64_t id); //, const vector<int> &clause); - void - lidrup_add_restored_clause (int64_t id); //, const vector<int> &clause); - void lidrup_add_original_clause (int64_t id, const vector<int> &clause); - void lidrup_conclude_and_delete (const vector<int64_t> &conclusion); - void lidrup_report_status (int status); - void lidrup_conclude_sat (const vector<int> &model); - void lidrup_conclude_unknown (const vector<int> &trail); - void lidrup_solve_query (); - void lidrup_batch_weaken_restore_and_delete (); - -public: - LidrupTracer (Internal *, File *file, bool); - ~LidrupTracer (); - - // proof section: - void add_derived_clause (int64_t, bool, const vector<int> &, - const vector<int64_t> &) override; - void add_assumption_clause (int64_t, const vector<int> &, - const vector<int64_t> &) override; - void weaken_minus (int64_t, const vector<int> &) override; - void delete_clause (int64_t, bool, const vector<int> &) override; - void add_original_clause (int64_t, bool, const vector<int> &, - bool = false) override; - void report_status (int, int64_t) override; - void conclude_sat (const vector<int> &) override; - void conclude_unsat (ConclusionType, const vector<int64_t> &) override; - void conclude_unknown (const vector<int> &) override; - - void solve_query () override; - void add_assumption (int) override; - void reset_assumptions () override; - - // skip - void begin_proof (int64_t) override {} - void finalize_clause (int64_t, const vector<int> &) override {} - void strengthen (int64_t) override {} - void add_constraint (const vector<int> &) override {} - - // logging and file io - void connect_internal (Internal *i) override; - -#ifndef CADICAL_QUIET - void print_statistics (); -#endif - bool closed () override; - void close (bool) override; - void flush (bool) override; -}; - -} // namespace CaDiCaL - -ABC_NAMESPACE_CXX_HEADER_END - -#endif diff --git a/src/sat/cadical/limit.hpp b/src/sat/cadical/limit.hpp deleted file mode 100644 index 0f6923214..000000000 --- a/src/sat/cadical/limit.hpp +++ /dev/null @@ -1,162 +0,0 @@ -#ifndef _limit_hpp_INCLUDED -#define _limit_hpp_INCLUDED - -#include "global.h" - -#include <cstdint> -#include <limits> - -ABC_NAMESPACE_CXX_HEADER_START - -namespace CaDiCaL { - -struct Internal; - -struct Limit { - - bool initialized; - - int64_t conflicts; // conflict limit if non-negative - int64_t decisions; // decision limit if non-negative - int64_t preprocessing; // limit on preprocessing rounds - int64_t localsearch; // limit on local search rounds - - int64_t compact; // conflict limit for next 'compact' - int64_t condition; // conflict limit for next 'condition' - int64_t elim; // conflict limit for next 'elim' - int64_t flush; // conflict limit for next 'flush' - int64_t inprobe; // conflict limit for next 'inprobe' - int64_t reduce; // conflict limit for next 'reduce' - int64_t rephase; // conflict limit for next 'rephase' - int64_t report; // report limit for header - int64_t restart; // conflict limit for next 'restart' - int64_t stabilize; // conflict/ticks limit for next 'stabilize' - - int keptsize; // maximum kept size in 'reduce' - int keptglue; // maximum kept glue in 'reduce' - int64_t recompute_tier; // conflict limit for next tier recomputation - - // How often rephased during (1) or out (0) of stabilization. - // - int64_t rephased[2]; - - // Current elimination bound per eliminated variable. - // - int64_t elimbound; - - struct { - int check; // countdown to next terminator call - int forced; // forced termination for testing - } terminate; - - Limit (); -}; - -struct Delay { - struct { - int64_t interval = 0, limit = 0; - bool bypass = 0; - - bool delay () { - if (bypass) - return true; - if (limit) { - --limit; - return true; - } else { - return false; - } - } - - void bump_delay () { - interval += interval < INT64_MAX; - limit = interval; - } - - void reduce_delay () { - if (!interval) - return; - interval /= 2; - limit = interval; - } - - void bypass_delay () { bypass = 1; } - void unbypass_delay () { bypass = 0; } - } bumpreasons; -}; - -struct Last { - struct { - int64_t propagations; - } transred; - struct { - int64_t ticks; - } sweep, vivify, probe; - struct { - int64_t fixed, subsumephases, marked; - } elim; - struct { - int64_t reductions; - } inprobe; - struct { - int64_t conflicts; - } reduce, rephase; - struct { - int64_t ticks; - int64_t marked; - } ternary; - struct { - int64_t fixed; - } collect; - struct { - int64_t marked, ticks; - } factor; - struct { - int64_t conflicts; - int64_t ticks; - } stabilize; - Last (); -}; - -struct Inc { - int64_t flush; // flushing interval in terms of conflicts - int64_t stabilize; // base ticks limit after first mode switch - int64_t conflicts; // next conflict limit if non-negative - int64_t decisions; // next decision limit if non-negative - int64_t preprocessing; // next preprocessing limit if non-negative - int64_t localsearch; // next local search limit if non-negative - Inc (); -}; - -#define SET_EFFORT_LIMIT(LIMIT, NAME, THRESHHOLD) \ - int64_t LIMIT; \ - do { \ - const int64_t OLD_LIMIT = stats.ticks.NAME; \ - const int64_t TICKS = stats.ticks.search[0] + stats.ticks.search[1]; \ - const int64_t LAST = last.NAME.ticks; \ - int64_t REFERENCE = TICKS - LAST; \ - if (!REFERENCE || !stats.conflicts) { \ - VERBOSE (2, "last %" PRId64 " current %" PRId64 " delta %" PRId64, \ - LAST, TICKS, REFERENCE); \ - REFERENCE = opts.preprocessinit; \ - } \ - const double EFFORT = (double) opts.NAME##effort * 1e-3; \ - const int64_t DELTA = EFFORT * REFERENCE; \ - const int64_t THRESH = opts.NAME##thresh * clauses.size (); \ - if (THRESHHOLD && DELTA < THRESH) { \ - VERBOSE (2, \ - "delaying %s with ticklimit %" PRId64 \ - " and threshhold %" PRId64, \ - #NAME, DELTA, THRESH); \ - return false; \ - } \ - last.NAME.ticks = TICKS; \ - const int64_t NEW_LIMIT = OLD_LIMIT + DELTA; \ - LIMIT = NEW_LIMIT; \ - } while (0) - -} // namespace CaDiCaL - -ABC_NAMESPACE_CXX_HEADER_END - -#endif diff --git a/src/sat/cadical/logging.hpp b/src/sat/cadical/logging.hpp deleted file mode 100644 index edbd60f8c..000000000 --- a/src/sat/cadical/logging.hpp +++ /dev/null @@ -1,104 +0,0 @@ -#ifndef _logging_hpp_INCLUDED -#define _logging_hpp_INCLUDED - -#include "global.h" - -/*------------------------------------------------------------------------*/ -#ifdef LOGGING -/*------------------------------------------------------------------------*/ - -#include <cstdint> -#include <vector> - -ABC_NAMESPACE_CXX_HEADER_START - -namespace CaDiCaL { - -// For debugging purposes and to help understanding what the solver is doing -// there is a logging facility which is compiled in by './configure -l'. It -// still has to be enabled at run-time though (again using the '-l' option -// in the stand-alone solver). It produces quite a bit of information. - -using namespace std; - -struct Clause; -struct Gate; -struct Internal; - -struct Logger { - - static void print_log_prefix (Internal *); - - // Simple logging of a C-style format string. - // - static void log (Internal *, const char *fmt, ...) - CADICAL_ATTRIBUTE_FORMAT (2, 3); - - // Prints the format string (with its argument) and then the clause. The - // clause can also be a zero pointer and then is interpreted as a decision - // (current decision level > 0) or unit clause (zero decision level) and - // printed accordingly. - // - static void log (Internal *, const Clause *, const char *fmt, ...) - CADICAL_ATTRIBUTE_FORMAT (3, 4); - - // Same as before, except that this is meant for the global 'clause' stack - // used for new clauses (and not for reasons). - // - static void log (Internal *, const vector<int> &, const char *fmt, ...) - CADICAL_ATTRIBUTE_FORMAT (3, 4); - - // Another variant, to avoid copying (without logging). - // - static void log (Internal *, const vector<int>::const_iterator &begin, - const vector<int>::const_iterator &end, const char *fmt, - ...) CADICAL_ATTRIBUTE_FORMAT (4, 5); - - // used for logging LRAT proof chains - // - static void log (Internal *, const vector<int64_t> &, const char *fmt, - ...) CADICAL_ATTRIBUTE_FORMAT (3, 4); - - static void log (Internal *, const int *, const unsigned, const char *fmt, - ...) CADICAL_ATTRIBUTE_FORMAT (4, 5); - - static void log_empty_line (Internal *); - - static void log (Internal *, const Gate *, const char *fmt, ...) - CADICAL_ATTRIBUTE_FORMAT (3, 4); - - static string loglit (Internal *, int lit); -}; - -} // namespace CaDiCaL - -/*------------------------------------------------------------------------*/ - -// Make sure that 'logging' code is really not included (second case of the -// '#ifdef') if logging code is not included. - -#define LOG(...) \ - do { \ - if (!internal->opts.log) \ - break; \ - Logger::log (internal, __VA_ARGS__); \ - } while (0) - -#define LOGLIT(lit) Logger::loglit (internal, lit).c_str () - -ABC_NAMESPACE_CXX_HEADER_END - -/*------------------------------------------------------------------------*/ -#else // end of 'then' part of 'ifdef LOGGING' -/*------------------------------------------------------------------------*/ - -#define LOG(...) \ - do { \ - } while (0) - -#define LOGLIT(...) - -/*------------------------------------------------------------------------*/ -#endif // end of 'else' part of 'ifdef LOGGING' -/*------------------------------------------------------------------------*/ -#endif diff --git a/src/sat/cadical/lratchecker.hpp b/src/sat/cadical/lratchecker.hpp deleted file mode 100644 index 0e791e9f4..000000000 --- a/src/sat/cadical/lratchecker.hpp +++ /dev/null @@ -1,170 +0,0 @@ -#ifndef _lratchecker_hpp_INCLUDED -#define _lratchecker_hpp_INCLUDED - -#include "global.h" - -/*------------------------------------------------------------------------*/ -#include <unordered_map> - -ABC_NAMESPACE_CXX_HEADER_START - -namespace CaDiCaL { - -/*------------------------------------------------------------------------*/ - -// This checker implements an LRUP checker. -// It requires LRAT-style proof chains for each learned clause -// -// Most of the infrastructure is taken from checker, but without the -// propagation - -/*------------------------------------------------------------------------*/ - -struct LratCheckerClause { - LratCheckerClause *next; // collision chain link for hash table - uint64_t hash; // previously computed full 64-bit hash - int64_t id; // id of clause - bool garbage; // for garbage clauses - unsigned size; - bool used; - bool tautological; - int literals[1]; // 'literals' of length 'size' -}; - -/*------------------------------------------------------------------------*/ - -class LratChecker : public StatTracer { - - Internal *internal; - - // Capacity of variable values. - // - int64_t size_vars; - - // The 'watchers' and 'marks' data structures are not that time critical - // and thus we access them by first mapping a literal to 'unsigned'. - // - static unsigned l2u (int lit); - - signed char &checked_lit (int lit); - signed char &mark (int lit); - - vector<signed char> checked_lits; - vector<signed char> marks; // mark bits of literals - unordered_map<int64_t, vector<int>> clauses_to_reconstruct; - vector<int> assumptions; - vector<int> constraint; - bool concluded; - - uint64_t num_clauses; // number of clauses in hash table - uint64_t num_finalized; - uint64_t num_garbage; // number of garbage clauses - uint64_t size_clauses; // size of clause hash table - LratCheckerClause **clauses; // hash table of clauses - LratCheckerClause *garbage; // linked list of garbage clauses - - vector<int> imported_clause; // original clause for reporting - vector<int64_t> assumption_clauses; - - void enlarge_vars (int64_t idx); - void import_literal (int lit); - void import_clause (const vector<int> &); - - static const unsigned num_nonces = 4; - - uint64_t nonces[num_nonces]; // random numbers for hashing - uint64_t last_hash; // last computed hash value of clause - int64_t last_id; // id of the last added/deleted clause - int64_t current_id; // id of the last added clause - uint64_t compute_hash (int64_t); // compute and save hash value of clause - - // Reduce hash value to the actual size. - // - static uint64_t reduce_hash (uint64_t hash, uint64_t size); - - void enlarge_clauses (); // enlarge hash table for clauses - void insert (); // insert clause in hash table - LratCheckerClause ** - find (const int64_t); // find clause position in hash table - - void add_clause (const char *type); - - void collect_garbage_clauses (); - - LratCheckerClause *new_clause (); - void delete_clause (LratCheckerClause *); - - bool check (vector<int64_t>); // check RUP - bool check_resolution (vector<int64_t>); // check resolution - bool check_blocked (vector<int64_t>); // check ER - - struct { - - int64_t added; // number of added clauses - int64_t original; // number of added original clauses - int64_t derived; // number of added derived clauses - - int64_t deleted; // number of deleted clauses - int64_t finalized; // number of finalized clauses - - int64_t insertions; // number of clauses added to hash table - int64_t collisions; // number of hash collisions in 'find' - int64_t searches; // number of searched clauses in 'find' - - int64_t checks; // number of implication checks - - int64_t collections; // garbage collections - - } stats; - -public: - LratChecker (Internal *); - virtual ~LratChecker (); - - void connect_internal (Internal *i) override; - void begin_proof (int64_t) override; - - void add_original_clause (int64_t, bool, const vector<int> &, - bool restore) override; - void restore_clause (int64_t, const vector<int> &); - - // check the proof chain for the new clause and add it to the checker - void add_derived_clause (int64_t, bool, const vector<int> &, - const vector<int64_t> &) override; - - // check if the clause is present and delete it from the checker - void delete_clause (int64_t, bool, const vector<int> &) override; - // check if the clause is present and delete it from the checker - void weaken_minus (int64_t, const vector<int> &) override; - - // check if the clause is present and delete it from the checker - void finalize_clause (int64_t, const vector<int> &) override; - - // check the proof chain of the assumption clause and delete it - // immediately also check that they contain only assumptions and - // constraints - void add_assumption_clause (int64_t, const vector<int> &, - const vector<int64_t> &) override; - - // mark lit as assumption - void add_assumption (int) override; - - // mark lits as constraint - void add_constraint (const vector<int> &) override; - - void reset_assumptions () override; - - // check if all clauses have been deleted - void report_status (int, int64_t) override; - - void conclude_unsat (ConclusionType, const vector<int64_t> &) override; - - void print_stats () override; - void dump (); // for debugging purposes only -}; - -} // namespace CaDiCaL - -ABC_NAMESPACE_CXX_HEADER_END - -#endif diff --git a/src/sat/cadical/lrattracer.hpp b/src/sat/cadical/lrattracer.hpp deleted file mode 100644 index 9d8e92b6a..000000000 --- a/src/sat/cadical/lrattracer.hpp +++ /dev/null @@ -1,63 +0,0 @@ -#ifndef _lrattracer_h_INCLUDED -#define _lrattracer_h_INCLUDED - -#include "global.h" - -ABC_NAMESPACE_CXX_HEADER_START - -namespace CaDiCaL { - -class LratTracer : public FileTracer { - - Internal *internal; - File *file; - bool binary; - -#ifndef CADICAL_QUIET - int64_t added, deleted; -#endif - int64_t latest_id; - vector<int64_t> delete_ids; - - void put_binary_zero (); - void put_binary_lit (int external_lit); - void put_binary_id (int64_t id); - - // support LRAT - void lrat_add_clause (int64_t, const vector<int> &, - const vector<int64_t> &); - void lrat_delete_clause (int64_t); - -public: - // own and delete 'file' - LratTracer (Internal *, File *file, bool binary); - ~LratTracer (); - - void connect_internal (Internal *i) override; - void begin_proof (int64_t) override; - - void add_original_clause (int64_t, bool, const vector<int> &, - bool = false) override {} // skip - - void add_derived_clause (int64_t, bool, const vector<int> &, - const vector<int64_t> &) override; - - void delete_clause (int64_t, bool, const vector<int> &) override; - - void finalize_clause (int64_t, const vector<int> &) override {} // skip - - void report_status (int, int64_t) override {} // skip - -#ifndef CADICAL_QUIET - void print_statistics (); -#endif - bool closed () override; - void close (bool) override; - void flush (bool) override; -}; - -} // namespace CaDiCaL - -ABC_NAMESPACE_CXX_HEADER_END - -#endif diff --git a/src/sat/cadical/message.hpp b/src/sat/cadical/message.hpp deleted file mode 100644 index e0209fed8..000000000 --- a/src/sat/cadical/message.hpp +++ /dev/null @@ -1,71 +0,0 @@ -#ifndef _message_h_INCLUDED -#define _message_h_INCLUDED - -#include "global.h" - -ABC_NAMESPACE_CXX_HEADER_START - -/*------------------------------------------------------------------------*/ - -// Macros for compact message code. - -#ifndef CADICAL_QUIET - -#define LINE() \ - do { \ - if (internal) \ - internal->message (); \ - } while (0) - -#define MSG(...) \ - do { \ - if (internal) \ - internal->message (__VA_ARGS__); \ - } while (0) - -#define PHASE(...) \ - do { \ - if (internal) \ - internal->phase (__VA_ARGS__); \ - } while (0) - -#define SECTION(...) \ - do { \ - if (internal) \ - internal->section (__VA_ARGS__); \ - } while (0) - -#define VERBOSE(...) \ - do { \ - if (internal) \ - internal->verbose (__VA_ARGS__); \ - } while (0) - -#else - -#define LINE() \ - do { \ - } while (0) -#define MSG(...) \ - do { \ - } while (0) -#define PHASE(...) \ - do { \ - } while (0) -#define SECTION(...) \ - do { \ - } while (0) -#define VERBOSE(...) \ - do { \ - } while (0) - -#endif - -#define FATAL fatal -#define WARNING(...) internal->warning (__VA_ARGS__) - -/*------------------------------------------------------------------------*/ - -ABC_NAMESPACE_CXX_HEADER_END - -#endif // ifndef _message_h_INCLUDED diff --git a/src/sat/cadical/module.make b/src/sat/cadical/module.make deleted file mode 100644 index 74f5d23cb..000000000 --- a/src/sat/cadical/module.make +++ /dev/null @@ -1,91 +0,0 @@ -SRC +=src/sat/cadical/cadicalSolver.c \ -src/sat/cadical/cadicalTest.c \ -src/sat/cadical/cadical_analyze.cpp \ -src/sat/cadical/cadical_arena.cpp \ -src/sat/cadical/cadical_assume.cpp \ -src/sat/cadical/cadical_averages.cpp \ -src/sat/cadical/cadical_backtrack.cpp \ -src/sat/cadical/cadical_backward.cpp \ -src/sat/cadical/cadical_bins.cpp \ -src/sat/cadical/cadical_block.cpp \ -src/sat/cadical/cadical_ccadical.cpp \ -src/sat/cadical/cadical_checker.cpp \ -src/sat/cadical/cadical_clause.cpp \ -src/sat/cadical/cadical_collect.cpp \ -src/sat/cadical/cadical_compact.cpp \ -src/sat/cadical/cadical_condition.cpp \ -src/sat/cadical/cadical_config.cpp \ -src/sat/cadical/cadical_congruence.cpp \ -src/sat/cadical/cadical_constrain.cpp \ -src/sat/cadical/cadical_contract.cpp \ -src/sat/cadical/cadical_cover.cpp \ -src/sat/cadical/cadical_decide.cpp \ -src/sat/cadical/cadical_decompose.cpp \ -src/sat/cadical/cadical_deduplicate.cpp \ -src/sat/cadical/cadical_definition.cpp \ -src/sat/cadical/cadical_drattracer.cpp \ -src/sat/cadical/cadical_elim.cpp \ -src/sat/cadical/cadical_elimfast.cpp \ -src/sat/cadical/cadical_ema.cpp \ -src/sat/cadical/cadical_extend.cpp \ -src/sat/cadical/cadical_external.cpp \ -src/sat/cadical/cadical_external_propagate.cpp \ -src/sat/cadical/cadical_factor.cpp \ -src/sat/cadical/cadical_file.cpp \ -src/sat/cadical/cadical_flags.cpp \ -src/sat/cadical/cadical_flip.cpp \ -src/sat/cadical/cadical_format.cpp \ -src/sat/cadical/cadical_frattracer.cpp \ -src/sat/cadical/cadical_gates.cpp \ -src/sat/cadical/cadical_idruptracer.cpp \ -src/sat/cadical/cadical_instantiate.cpp \ -src/sat/cadical/cadical_internal.cpp \ -src/sat/cadical/cadical_ipasir.cpp \ -src/sat/cadical/cadical_lidruptracer.cpp \ -src/sat/cadical/cadical_limit.cpp \ -src/sat/cadical/cadical_logging.cpp \ -src/sat/cadical/cadical_lookahead.cpp \ -src/sat/cadical/cadical_lratchecker.cpp \ -src/sat/cadical/cadical_lrattracer.cpp \ -src/sat/cadical/cadical_lucky.cpp \ -src/sat/cadical/cadical_message.cpp \ -src/sat/cadical/cadical_minimize.cpp \ -src/sat/cadical/cadical_occs.cpp \ -src/sat/cadical/cadical_options.cpp \ -src/sat/cadical/cadical_parse.cpp \ -src/sat/cadical/cadical_phases.cpp \ -src/sat/cadical/cadical_probe.cpp \ -src/sat/cadical/cadical_profile.cpp \ -src/sat/cadical/cadical_proof.cpp \ -src/sat/cadical/cadical_propagate.cpp \ -src/sat/cadical/cadical_queue.cpp \ -src/sat/cadical/cadical_random.cpp \ -src/sat/cadical/cadical_reap.cpp \ -src/sat/cadical/cadical_reduce.cpp \ -src/sat/cadical/cadical_rephase.cpp \ -src/sat/cadical/cadical_report.cpp \ -src/sat/cadical/cadical_resources.cpp \ -src/sat/cadical/cadical_restart.cpp \ -src/sat/cadical/cadical_restore.cpp \ -src/sat/cadical/cadical_score.cpp \ -src/sat/cadical/cadical_shrink.cpp \ -src/sat/cadical/cadical_signal.cpp \ -src/sat/cadical/cadical_solution.cpp \ -src/sat/cadical/cadical_solver.cpp \ -src/sat/cadical/cadical_stable.cpp \ -src/sat/cadical/cadical_stats.cpp \ -src/sat/cadical/cadical_subsume.cpp \ -src/sat/cadical/cadical_sweep.cpp \ -src/sat/cadical/cadical_terminal.cpp \ -src/sat/cadical/cadical_ternary.cpp \ -src/sat/cadical/cadical_tier.cpp \ -src/sat/cadical/cadical_transred.cpp \ -src/sat/cadical/cadical_unstable.cpp \ -src/sat/cadical/cadical_util.cpp \ -src/sat/cadical/cadical_var.cpp \ -src/sat/cadical/cadical_veripbtracer.cpp \ -src/sat/cadical/cadical_version.cpp \ -src/sat/cadical/cadical_vivify.cpp \ -src/sat/cadical/cadical_walk.cpp \ -src/sat/cadical/cadical_watch.cpp \ -src/sat/cadical/cadical_kitten.c diff --git a/src/sat/cadical/occs.hpp b/src/sat/cadical/occs.hpp deleted file mode 100644 index 28a9246bc..000000000 --- a/src/sat/cadical/occs.hpp +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef _occs_h_INCLUDED -#define _occs_h_INCLUDED - -#include "global.h" - -#include <vector> - -ABC_NAMESPACE_CXX_HEADER_START - -namespace CaDiCaL { - -// Full occurrence lists used in a one-watch scheme for all clauses in -// subsumption checking and for irredundant clauses in variable elimination. - -struct Clause; -using namespace std; - -typedef vector<Clause *> Occs; - -inline void shrink_occs (Occs &os) { shrink_vector (os); } -inline void erase_occs (Occs &os) { erase_vector (os); } - -inline void remove_occs (Occs &os, Clause *c) { - const auto end = os.end (); - auto i = os.begin (); - for (auto j = i; j != end; j++) { - const Clause *d = *i++ = *j; - if (c == d) - i--; - } - CADICAL_assert (i + 1 == end); - os.resize (i - os.begin ()); -} - -typedef Occs::iterator occs_iterator; -typedef Occs::const_iterator const_occs_iterator; - -} // namespace CaDiCaL - -ABC_NAMESPACE_CXX_HEADER_END - -#endif diff --git a/src/sat/cadical/options.hpp b/src/sat/cadical/options.hpp deleted file mode 100644 index 1527da2e1..000000000 --- a/src/sat/cadical/options.hpp +++ /dev/null @@ -1,422 +0,0 @@ -#ifndef _options_hpp_INCLUDED -#define _options_hpp_INCLUDED - -#include "global.h" - -ABC_NAMESPACE_CXX_HEADER_START - -/*------------------------------------------------------------------------*/ - -// In order to add a new option, simply add a new line below. Make sure that -// options are sorted correctly (with '!}sort -k 2' in 'vi'). Otherwise -// initializing the options will trigger an internal error. For the model -// based tester 'mobical' the policy is that options which become redundant -// because another one is disabled (set to zero) should have the name of the -// latter as prefix. The 'O' column determines the options which are -// target to 'optimize' them ('-O[1-3]'). A zero value in the 'O' column -// means that this option is not optimized. A value of '1' results in -// optimizing its value exponentially with exponent base '2', and a value -// of '2' uses base '10'. The 'P' column determines simplification -// options (disabled with '--plain') and 'R' which values can be reset. - -// clang-format off - -#define OPTIONS \ -\ -/* NAME DEFAULT, LO, HI,O,P,R, USAGE */ \ -\ -OPTION( arena, 1, 0, 1,0,0,1, "allocate clauses in arena") \ -OPTION( arenacompact, 1, 0, 1,0,0,1, "keep clauses compact") \ -OPTION( arenasort, 1, 0, 1,0,0,1, "sort clauses in arena") \ -OPTION( arenatype, 3, 1, 3,0,0,1, "1=clause, 2=var, 3=queue") \ -OPTION( binary, 1, 0, 1,0,0,1, "use binary proof format") \ -OPTION( block, 0, 0, 1,0,1,1, "blocked clause elimination") \ -OPTION( blockmaxclslim, 1e5, 1,2e9,2,0,1, "maximum clause size") \ -OPTION( blockminclslim, 2, 2,2e9,0,0,1, "minimum clause size") \ -OPTION( blockocclim, 1e2, 1,2e9,2,0,1, "occurrence limit") \ -OPTION( bump, 1, 0, 1,0,0,1, "bump variables") \ -OPTION( bumpreason, 1, 0, 1,0,0,1, "bump reason literals too") \ -OPTION( bumpreasondepth, 1, 1, 3,0,0,1, "bump reason depth") \ -OPTION( bumpreasonlimit, 10, 1,2e9,0,0,1, "bump reason limit") \ -OPTION( bumpreasonrate, 100, 1,2e9,0,0,1, "bump reason decision rate") \ -OPTION( check, 0, 0, 1,0,0,0, "enable internal checking") \ -OPTION( checkassumptions, 1, 0, 1,0,0,0, "check assumptions satisfied") \ -OPTION( checkconstraint, 1, 0, 1,0,0,0, "check constraint satisfied") \ -OPTION( checkfailed, 1, 0, 1,0,0,0, "check failed literals form core") \ -OPTION( checkfrozen, 0, 0, 1,0,0,0, "check all frozen semantics") \ -OPTION( checkproof, 3, 0, 3,0,0,0, "1=drat, 2=lrat, 3=both") \ -OPTION( checkwitness, 1, 0, 1,0,0,0, "check witness internally") \ -OPTION( chrono, 1, 0, 2,0,0,1, "chronological backtracking") \ -OPTION( chronoalways, 0, 0, 1,0,0,1, "force always chronological") \ -OPTION( chronolevelim, 1e2, 0,2e9,0,0,1, "chronological level limit") \ -OPTION( chronoreusetrail, 1, 0, 1,0,0,1, "reuse trail chronologically") \ -OPTION( compact, 1, 0, 1,0,1,1, "compact internal variables") \ -OPTION( compactint, 2e3, 1,2e9,0,0,1, "compacting interval") \ -OPTION( compactlim, 1e2, 0,1e3,0,0,1, "inactive limit per mille") \ -OPTION( compactmin, 1e2, 1,2e9,0,0,1, "minimum inactive limit") \ -OPTION( condition, 0, 0, 1,0,1,1, "globally blocked clause elim") \ -OPTION( conditioneffort, 100, 1,1e5,0,0,1, "relative efficiency per mille") \ -OPTION( conditionint, 1e4, 1,2e9,0,0,1, "initial conflict interval") \ -OPTION( conditionmaxeff, 1e7, 0,2e9,1,0,1, "maximum condition efficiency") \ -OPTION( conditionmaxrat, 100, 1,2e9,1,0,1, "maximum clause variable ratio") \ -OPTION( conditionmineff, 0, 0,2e9,1,0,1, "minimum condition efficiency") \ -OPTION( congruence, 1, 0, 1,0,0,1, "congruence closure") \ -OPTION( congruenceand, 1, 0, 1,0,0,1, "extract AND gates") \ -OPTION( congruenceandarity,1e6,2,5e7,0,0,1, "AND gate arity limit") \ -OPTION( congruencebinaries,1, 0, 1,0,0,1, "extract binary and strengthen ternary clauses") \ -OPTION( congruenceite, 1, 0, 1,0,0,1, "extract ITE gates") \ -OPTION( congruencexor, 1, 0, 1,0,0,1, "extract XOR gates") \ -OPTION( congruencexorarity,4, 2, 31,0,0,1, "XOR gate arity limit") \ -OPTION( congruencexorcounts,1, 1,5e6,0,0,1, "XOR gate round") \ -OPTION( cover, 0, 0, 1,0,1,1, "covered clause elimination") \ -OPTION( covereffort, 4, 1,1e5,1,0,1, "relative efficiency per mille") \ -OPTION( covermaxclslim, 1e5, 1,2e9,2,0,1, "maximum clause size") \ -OPTION( covermaxeff, 1e8, 0,2e9,1,0,1, "maximum cover efficiency") \ -OPTION( coverminclslim, 2, 2,2e9,0,0,1, "minimum clause size") \ -OPTION( covermineff, 0, 0,2e9,1,0,1, "minimum cover efficiency") \ -OPTION( decompose, 1, 0, 1,0,1,1, "decompose BIG in SCCs and ELS") \ -OPTION( decomposerounds, 2, 1, 16,1,0,1, "number of decompose rounds") \ -OPTION( deduplicate, 1, 0, 1,0,1,1, "remove duplicated binaries") \ -OPTION( eagersubsume, 1, 0, 1,0,1,1, "subsume recently learned") \ -OPTION( eagersubsumelim, 20, 1,1e3,0,0,1, "limit on subsumed candidates") \ -OPTION( elim, 1, 0, 1,0,1,1, "bounded variable elimination") \ -OPTION( elimands, 1, 0, 1,0,0,1, "find AND gates") \ -OPTION( elimbackward, 1, 0, 1,0,0,1, "eager backward subsumption") \ -OPTION( elimboundmax, 16, -1,2e6,1,0,1, "maximum elimination bound") \ -OPTION( elimboundmin, 0, -1,2e6,0,0,1, "minimum elimination bound") \ -OPTION( elimclslim, 1e2, 2,2e9,2,0,1, "resolvent size limit") \ -OPTION( elimdef, 0, 0, 1,0,0,1, "mine definitions with cadical_kitten") \ -OPTION( elimdefcores, 1, 1,100,0,0,1, "number of unsat cores") \ -OPTION( elimdefticks, 2e5, 0,2e9,1,0,1, "cadical_kitten ticks limit") \ -OPTION( elimeffort, 1e3, 1,1e5,1,0,1, "relative efficiency per mille") \ -OPTION( elimequivs, 1, 0, 1,0,0,1, "find equivalence gates") \ -OPTION( elimint, 2e3, 1,2e9,0,0,1, "elimination interval") \ -OPTION( elimites, 1, 0, 1,0,0,1, "find if-then-else gates") \ -OPTION( elimlimited, 1, 0, 1,0,0,1, "limit resolutions") \ -OPTION( elimmaxeff, 2e9, 0,2e9,1,0,1, "maximum elimination efficiency") \ -OPTION( elimmineff, 1e7, 0,2e9,1,0,1, "minimum elimination efficiency") \ -OPTION( elimocclim, 1e2, 0,2e9,2,0,1, "occurrence limit") \ -OPTION( elimprod, 1, 0,1e4,0,0,1, "elim score product weight") \ -OPTION( elimrounds, 2, 1,512,1,0,1, "usual number of rounds") \ -OPTION( elimsubst, 1, 0, 1,0,0,1, "elimination by substitution") \ -OPTION( elimsum, 1, 0,1e4,0,0,1, "elimination score sum weight") \ -OPTION( elimxorlim, 5, 2, 27,1,0,1, "maximum XOR size") \ -OPTION( elimxors, 1, 0, 1,0,0,1, "find XOR gates") \ -OPTION( emadecisions, 1e5, 1,2e9,0,0,1, "window decision rate") \ -OPTION( emagluefast, 33, 1,2e9,0,0,1, "window fast glue") \ -OPTION( emaglueslow, 1e5, 1,2e9,0,0,1, "window slow glue") \ -OPTION( emajump, 1e5, 1,2e9,0,0,1, "window back-jump level") \ -OPTION( emalevel, 1e5, 1,2e9,0,0,1, "window back-track level") \ -OPTION( emasize, 1e5, 1,2e9,0,0,1, "window learned clause size") \ -OPTION( ematrailfast, 1e2, 1,2e9,0,0,1, "window fast trail") \ -OPTION( ematrailslow, 1e5, 1,2e9,0,0,1, "window slow trail") \ -OPTION( exteagerreasons, 1, 0, 1,0,0,1, "eagerly ask for all reasons (0: only when needed)") \ -OPTION( exteagerrecalc, 1, 0, 1,0,0,1, "after eagerly asking for reasons recalculate all levels (0: trust the external tool)") \ -OPTION( externallrat, 0, 0, 1,0,0,1, "external lrat") \ -OPTION( factor, 1, 0, 1,0,1,1, "bounded variable addition") \ -OPTION( factorcandrounds, 2, 0,2e9,0,0,1, "candidates reduction rounds") \ -OPTION( factoreffort, 50, 0,1e6,0,0,1, "relative effort per mille") \ -OPTION( factoriniticks, 300, 1,1e6,0,0,1, "initial effort in millions") \ -OPTION( factorsize, 5, 2,2e9,0,0,1, "clause size limit") \ -OPTION( factorthresh, 7, 0,100,1,0,1, "delay if ticks smaller thresh*clauses") \ -OPTION( fastelim, 1, 0, 1,0,1,1, "fast BVE during preprocessing") \ -OPTION( fastelimbound, 8, 1,1e3,1,0,1, "fast BVE bound during preprocessing") \ -OPTION( fastelimclslim, 1e2, 2,2e9,2,0,1, "fast BVE resolvent size limit") \ -OPTION( fastelimocclim, 100, 1,2e9,2,0,1, "fast BVE occurence limit during preprocessing") \ -OPTION( fastelimrounds, 4, 1,512,1,0,1, "number of fastelim rounds") \ -OPTION( flush, 0, 0, 1,0,1,1, "flush redundant clauses") \ -OPTION( flushfactor, 3, 1,1e3,0,0,1, "interval increase") \ -OPTION( flushint, 1e5, 1,2e9,0,0,1, "initial limit") \ -OPTION( forcephase, 0, 0, 1,0,0,1, "always use initial phase") \ -OPTION( frat, 0, 0, 2,0,0,1, "1=frat(lrat), 2=frat(drat)") \ -OPTION( idrup, 0, 0, 1,0,0,1, "incremental proof format") \ -OPTION( ilb, 0, 0, 1,0,0,1, "ILB (incremental lazy backtrack)") \ -OPTION( ilbassumptions, 0, 0, 1,0,0,1, "trail reuse for assumptions (ILB-like)") \ -OPTION( inprobeint, 100, 1,2e9,0,0,1, "inprobing interval" ) \ -OPTION( inprobing, 1, 0, 1,0,1,1, "enable probe inprocessing") \ -OPTION( inprocessing, 1, 0, 1,0,1,1, "enable general inprocessing") \ -OPTION( instantiate, 0, 0, 1,0,1,1, "variable instantiation") \ -OPTION( instantiateclslim, 3, 2,2e9,0,0,1, "minimum clause size") \ -OPTION( instantiateocclim, 1, 1,2e9,2,0,1, "maximum occurrence limit") \ -OPTION( instantiateonce, 1, 0, 1,0,0,1, "instantiate each clause once") \ -OPTION( lidrup, 0, 0, 1,0,0,1, "linear incremental proof format") \ -LOGOPT( log, 0, 0, 1,0,0,0, "enable logging") \ -LOGOPT( logsort, 0, 0, 1,0,0,0, "sort logged clauses") \ -OPTION( lrat, 0, 0, 1,0,0,1, "use LRAT proof format") \ -OPTION( lucky, 1, 0, 1,0,0,1, "search for lucky phases") \ -OPTION( minimize, 1, 0, 1,0,0,1, "minimize learned clauses") \ -OPTION( minimizedepth, 1e3, 0,1e3,0,0,1, "minimization depth") \ -OPTION( minimizeticks, 1, 0, 1,0,0,1, "increment ticks in minimization") \ -OPTION( otfs, 1, 0, 1,0,0,1, "on-the-fly self subsumption") \ -OPTION( phase, 1, 0, 1,0,0,1, "initial phase") \ -OPTION( preprocessinit, 2e6, 0,2e9,2,0,1, "initial preprocessing base limit" ) \ -OPTION( preprocesslight, 1, 0, 1,0,1,1, "lightweight preprocessing" ) \ -OPTION( probe, 1, 0, 1,0,1,1, "failed literal probing" ) \ -OPTION( probeeffort, 8, 1,1e5,1,0,1, "relative efficiency per mille") \ -OPTION( probehbr, 1, 0, 1,0,0,1, "learn hyper binary clauses") \ -OPTION( probethresh, 0, 0,100,1,0,1, "delay if ticks smaller thresh*clauses") \ -OPTION( profile, 2, 0, 4,0,0,0, "profiling level") \ -QUTOPT( quiet, 0, 0, 1,0,0,0, "disable all messages") \ -OPTION( radixsortlim, 32, 0,2e9,0,0,1, "radix sort limit") \ -OPTION( realtime, 0, 0, 1,0,0,0, "real instead of process time") \ -OPTION( recomputetier, 1, 0, 1,0,0,1, "recompute tiers") \ -OPTION( reduce, 1, 0, 1,0,0,1, "reduce useless clauses") \ -OPTION( reduceinit, 300, 1,1e6,0,0,1, "initial interval") \ -OPTION( reduceint, 25, 2,1e6,0,0,1, "reduce interval") \ -OPTION( reduceopt, 1, 0, 2,0,0,1, "0=prct,1=sqrt,2=max") \ -OPTION( reducetarget, 75, 10,1e2,0,0,1, "reduce fraction in percent") \ -OPTION( reducetier1glue, 2, 1,2e9,0,0,1, "glue of kept learned clauses") \ -OPTION( reducetier2glue, 6, 1,2e9,0,0,1, "glue of tier two clauses") \ -OPTION( reluctant, 1024, 0,2e9,0,0,1, "reluctant doubling period") \ -OPTION( reluctantmax,1048576, 0,2e9,0,0,1, "reluctant doubling period") \ -OPTION( rephase, 1, 0, 1,0,0,1, "enable resetting phase") \ -OPTION( rephaseint, 1e3, 1,2e9,0,0,1, "rephase interval") \ -OPTION( report,reportdefault, 0, 1,0,0,1, "enable reporting") \ -OPTION( reportall, 0, 0, 1,0,0,1, "report even if not successful") \ -OPTION( reportsolve, 0, 0, 1,0,0,1, "use solving not process time") \ -OPTION( restart, 1, 0, 1,0,0,1, "enable restarts") \ -OPTION( restartint, 2, 1,2e9,0,0,1, "restart interval") \ -OPTION( restartmargin, 10, 0,1e2,0,0,1, "slow fast margin in percent") \ -OPTION( restartreusetrail, 1, 0, 1,0,0,1, "enable trail reuse") \ -OPTION( restoreall, 0, 0, 2,0,0,1, "restore all clauses (2=really)") \ -OPTION( restoreflush, 0, 0, 1,0,0,1, "remove satisfied clauses") \ -OPTION( reverse, 0, 0, 1,0,0,1, "reverse variable ordering") \ -OPTION( score, 1, 0, 1,0,0,1, "use EVSIDS scores") \ -OPTION( scorefactor, 950,500,1e3,0,0,1, "score factor per mille") \ -OPTION( seed, 0, 0,2e9,0,0,1, "random seed") \ -OPTION( shrink, 3, 0, 3,0,0,1, "shrink conflict clause (1=only with binary, 2=minimize when pulling, 3=full)") \ -OPTION( shrinkreap, 1, 0, 1,0,0,1, "use a reap for shrinking") \ -OPTION( shuffle, 0, 0, 1,0,0,1, "shuffle variables") \ -OPTION( shufflequeue, 1, 0, 1,0,0,1, "shuffle variable queue") \ -OPTION( shufflerandom, 0, 0, 1,0,0,1, "not reverse but random") \ -OPTION( shufflescores, 1, 0, 1,0,0,1, "shuffle variable scores") \ -OPTION( stabilize, 1, 0, 1,0,0,1, "enable stabilizing phases") \ -OPTION( stabilizeinit, 1e3, 1,2e9,0,0,1, "stabilizing interval") \ -OPTION( stabilizeonly, 0, 0, 1,0,0,1, "only stabilizing phases") \ -OPTION( stats, 0, 0, 1,0,0,1, "print all statistics at the end of the run") \ -OPTION( subsume, 1, 0, 1,0,1,1, "enable clause subsumption") \ -OPTION( subsumebinlim, 1e4, 0,2e9,1,0,1, "watch list length limit") \ -OPTION( subsumeclslim, 1e2, 0,2e9,2,0,1, "clause length limit") \ -OPTION( subsumeeffort, 1e3, 1,1e5,1,0,1, "relative efficiency per mille") \ -OPTION( subsumelimited, 1, 0, 1,0,0,1, "limit subsumption checks") \ -OPTION( subsumemaxeff, 1e8, 0,2e9,1,0,1, "maximum subsuming efficiency") \ -OPTION( subsumemineff, 0, 0,2e9,1,0,1, "minimum subsuming efficiency") \ -OPTION( subsumeocclim, 1e2, 0,2e9,1,0,1, "watch list length limit") \ -OPTION( subsumestr, 1, 0, 1,0,0,1, "subsume strenghten") \ -OPTION( sweep, 1, 0, 1,0,1,1, "enable SAT sweeping") \ -OPTION( sweepclauses, 1024, 0,2e9,1,0,1, "environment clauses") \ -OPTION( sweepcomplete, 0, 0, 1,0,0,1, "run SAT sweeping to completion") \ -OPTION( sweepcountbinary, 1, 0, 1,0,0,1, "count binaries to environment") \ -OPTION( sweepdepth, 2, 0,2e9,1,0,1, "environment depth") \ -OPTION( sweepeffort, 1e2, 0,1e4,0,0,1, "relative effort in ticks per mille") \ -OPTION( sweepfliprounds, 1, 0,2e9,1,0,1, "flipping rounds") \ -OPTION( sweepmaxclauses, 3e5, 2,2e9,1,0,1, "maximum environment clauses") \ -OPTION( sweepmaxdepth, 3, 1,2e9,1,0,1, "maximum environment depth") \ -OPTION( sweepmaxvars, 8192, 2,2e9,1,0,1, "maximum environment variables") \ -OPTION( sweeprand, 0, 0, 1,0,0,1, "randomize sweeping environment") \ -OPTION( sweepthresh, 5, 0,100,1,0,1, "delay if ticks smaller thresh*clauses") \ -OPTION( sweepvars, 256, 0,2e9,1,0,1, "environment variables") \ -OPTION( target, 1, 0, 2,0,0,1, "target phases (1=stable only)") \ -OPTION( terminateint, 10, 0,1e4,0,0,1, "termination check interval") \ -OPTION( ternary, 1, 0, 1,0,1,1, "hyper ternary resolution") \ -OPTION( ternaryeffort, 8, 1,1e5,1,0,1, "relative efficiency per mille") \ -OPTION( ternarymaxadd, 1e3, 0,1e4,1,0,1, "max clauses added in percent") \ -OPTION( ternaryocclim, 1e2, 1,2e9,2,0,1, "ternary occurrence limit") \ -OPTION( ternaryrounds, 2, 1, 16,1,0,1, "maximum ternary rounds") \ -OPTION( ternarythresh, 6, 0,100,1,0,1, "delay if ticks smaller thresh*clauses") \ -OPTION( tier1limit, 50, 0,100,0,0,1, "limit of tier1 usage in percentage") \ -OPTION( tier2limit, 90, 0,100,0,0,1, "limit of tier2 usage in percentage") \ -OPTION( transred, 1, 0, 1,0,1,1, "transitive reduction of BIG") \ -OPTION( transredeffort, 1e2, 1,1e5,1,0,1, "relative efficiency per mille") \ -OPTION( transredmaxeff, 1e8, 0,2e9,1,0,1, "maximum efficiency") \ -OPTION( transredmineff, 0, 0,2e9,1,0,1, "minimum efficiency") \ -QUTOPT( verbose, 0, 0, 3,0,0,0, "more verbose messages") \ -OPTION( veripb, 0, 0, 4,0,0,1, "odd=checkdeletions, > 2=drat") \ -OPTION( vivify, 1, 0, 1,0,1,1, "vivification") \ -OPTION( vivifycalctier, 0, 0, 1,0,0,1, "recalculate tier limits") \ -OPTION( vivifydemote, 0, 0, 1,0,1,1, "demote irredundant or delete directly") \ -OPTION( vivifyeffort, 50, 0,1e5,1,0,1, "overall efficiency per mille") \ -OPTION( vivifyflush, 1, 0, 1,1,0,1, "flush subsumed before vivification rounds") \ -OPTION( vivifyinst, 1, 0, 1,0,0,1, "instantiate last literal when vivify") \ -OPTION( vivifyirred, 1, 0, 1,0,1,1, "vivification irred") \ -OPTION( vivifyirredeff, 3, 1,100,1,0,1, "irredundant efficiency per mille") \ -OPTION( vivifyonce, 0, 0, 2,0,0,1, "vivify once: 1=red, 2=red+irr") \ -OPTION( vivifyretry, 0, 0, 5,0,0,1, "re-vivify clause if vivify was successful") \ -OPTION( vivifyschedmax, 5e3, 10,2e9,0,0,1, "maximum schedule size") \ -OPTION( vivifythresh, 20, 0,100,1,0,1, "delay if ticks smaller thresh*clauses") \ -OPTION( vivifytier1, 1, 0, 1,0,1,1, "vivification tier1") \ -OPTION( vivifytier1eff, 4, 0,100,1,0,1, "relative tier1 effort") \ -OPTION( vivifytier2, 1, 0, 1,0,1,1, "vivification tier2") \ -OPTION( vivifytier2eff, 2, 1,100,1,0,1, "relative tier2 effort") \ -OPTION( vivifytier3, 1, 0, 1,0,1,1, "vivification tier3") \ -OPTION( vivifytier3eff, 1, 1,100,1,0,1, "relative tier3 effort") \ -OPTION( walk, 1, 0, 1,0,0,1, "enable random walks") \ -OPTION( walkeffort, 20, 1,1e5,1,0,1, "relative efficiency per mille") \ -OPTION( walkmaxeff, 1e7, 0,2e9,1,0,1, "maximum efficiency") \ -OPTION( walkmineff, 0, 0,1e7,1,0,1, "minimum efficiency") \ -OPTION( walknonstable, 1, 0, 1,0,0,1, "walk in non-stabilizing phase") \ -OPTION( walkredundant, 0, 0, 1,0,0,1, "walk redundant clauses too") \ - -// Note, keep an empty line right before this line because of the last '\'! -// Also keep those single spaces after 'OPTION(' for proper sorting. - -// clang-format on - -/*------------------------------------------------------------------------*/ - -// Some of the 'OPTION' macros above should only be included if certain -// compile time options are enabled. This has the effect, that for instance -// if 'LOGGING' is defined, and thus logging code is included, then also the -// 'log' option is defined. Otherwise the 'log' option is not included. - -#ifdef LOGGING -#define LOGOPT OPTION -#else -#define LOGOPT(...) /**/ -#endif - -#ifdef CADICAL_QUIET -#define QUTOPT(...) /**/ -#else -#define QUTOPT OPTION -#endif - -/*------------------------------------------------------------------------*/ - -namespace CaDiCaL { - -struct Internal; - -/*------------------------------------------------------------------------*/ - -class Options; - -struct Option { - const char *name; - int def, lo, hi; - int optimizable; - bool preprocessing; - const char *description; - int &val (Options *); -}; - -/*------------------------------------------------------------------------*/ - -// Produce a compile time constant for the number of options. - -static const size_t number_of_options = -#define OPTION(N, V, L, H, O, P, R, D) 1 + - OPTIONS -#undef OPTION - + 0; - -/*------------------------------------------------------------------------*/ - -class Options { - - Internal *internal; - - void set (Option *, int val); // Force to [lo,hi] interval. - - friend struct Option; - static Option table[]; - - static void initialize_from_environment (int &val, const char *name, - const int L, const int H); - - friend Config; - - void reset_default_values (); - void disable_preprocessing (); - -public: - // For library usage we disable reporting by default while for the stand - // alone SAT solver we enable it by default. This default value has to - // be set before the constructor of 'Options' is called (which in turn is - // called from the constructor of 'Solver'). If we would simply overwrite - // its initial value while initializing the stand alone solver, we will - // get that change of the default value (from 'false' to 'true') shown - // during calls to 'print ()', which is confusing to the user. - // - static int reportdefault; - - Options (Internal *); - - // Makes options directly accessible, e.g., for instance declares the - // member 'int restart' here. This will give fast access to option values - // internally in the solver and thus can also be used in tight loops. - // -private: - int __start_of_options__; // Used by 'val' below. -public: -#define OPTION(N, V, L, H, O, P, R, D) \ - int N; // Access option values by name. - OPTIONS -#undef OPTION - - // It would be more elegant to use an anonymous 'struct' of the actual - // option values overlayed with an 'int values[number_of_options]' array - // but that is not proper ISO C++ and produces a warning. Instead we use - // the following construction which relies on '__start_of_options__' and - // that the following options are really allocated directly after it. - // - inline int &val (size_t idx) { - CADICAL_assert (idx < number_of_options); - return (&__start_of_options__ + 1)[idx]; - } - - // With the following function we can get rather fast access to the option - // limits, the default value and the description. The code uses binary - // search over the sorted option 'table'. This static data is shared - // among different instances of the solver. The actual current option - // values are here in the 'Options' class. They can be accessed by the - // offset of the static options using 'Option::val' if you have an - // 'Option' or to have even faster access directly by the member function - // (the 'N' above, e.g., 'restart'). - // - static Option *has (const char *name); - - bool set (const char *name, int); // Explicit version. - int get (const char *name); // Get current value. - - void print (); // Print current values in command line form - static void usage (); // Print usage message for all options. - - void optimize (int val); // increase some limits (val=0..31) - - static bool is_preprocessing_option (const char *name); - - // Parse long option argument - // - // --<name> - // --<name>=<val> - // --no-<name> - // - // where '<val>' is as in 'parse_option_value'. If parsing succeeds, - // 'true' is returned and the string will be set to the name of the - // option. Additionally the parsed value is set (last argument). - // - static bool parse_long_option (const char *, string &, int &); - - // Iterating options. - - typedef Option *iterator; - typedef const Option *const_iterator; - - static iterator begin () { return table; } - static iterator end () { return table + number_of_options; } - - void copy (Options &other) const; // Copy 'this' into 'other'. -}; - -inline int &Option::val (Options *opts) { - CADICAL_assert (Options::table <= this && - this < Options::table + number_of_options); - return opts->val (this - Options::table); -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_CXX_HEADER_END - -#endif diff --git a/src/sat/cadical/parse.hpp b/src/sat/cadical/parse.hpp deleted file mode 100644 index a37117f43..000000000 --- a/src/sat/cadical/parse.hpp +++ /dev/null @@ -1,78 +0,0 @@ -#ifndef _parse_hpp_INCLUDED -#define _parse_hpp_INCLUDED - -#include "global.h" - -#include <cassert> -#include <vector> - -ABC_NAMESPACE_CXX_HEADER_START - -namespace CaDiCaL { - -// Factors out common functions for parsing of DIMACS and solution files. - -class File; -struct External; -struct Internal; - -class Parser { - - Solver *solver; - Internal *internal; - External *external; - File *file; - - void perr (const char *fmt, ...) CADICAL_ATTRIBUTE_FORMAT (2, 3); - int parse_char (); - - enum { - FORCED = 0, // Force reading even if header is broken. - RELAXED = 1, // Relaxed white space treatment in header. - STRICT = 2, // Strict white space and header compliance. - }; - - const char *parse_string (const char *str, char prev); - const char *parse_positive_int (int &ch, int &res, const char *name); - const char *parse_lit (int &ch, int &lit, int &vars, int strict); - const char *parse_dimacs_non_profiled (int &vars, int strict); - const char *parse_solution_non_profiled (); - - bool *parse_inccnf_too; - vector<int> *cubes; - -public: - // Parse a DIMACS CNF or ICNF file. - // - // Return zero if successful. Otherwise parse error. - Parser (Solver *s, File *f, bool *i, vector<int> *c) - : solver (s), internal (s->internal), external (s->external), - file (f), parse_inccnf_too (i), cubes (c) {} - - // Parse a DIMACS file. Return zero if successful. Otherwise a parse - // error is return. The parsed clauses are added to the solver and the - // maximum variable index found is returned in the 'vars' argument. The - // 'strict' argument can be '0' in which case the numbers in the header - // can be arbitrary, e.g., 'p cnf 0 0' all the time, without producing a - // parse error. Only for this setting the parsed literals are not checked - // to overflow the maximum variable index of the header. The strictest - // form of parsing is enforced for the value '2' of 'strict', in which - // case the header can not have additional white space, while a value of - // '1' exactly relaxes this, e.g., 'p cnf \t 1 3 \r\n' becomes legal. - // - const char *parse_dimacs (int &vars, int strict); - - // Parse a solution file as used in the SAT competition, e.g., with - // comment lines 'c ...', a status line 's ...' and value lines 'v ...'. - // Returns zero if successful. Otherwise a string is returned describing - // the parse error. The parsed solution is saved in 'solution' and can be - // accessed with 'sol (int lit)'. We use it for checking learned clauses. - // - const char *parse_solution (); -}; - -} // namespace CaDiCaL - -ABC_NAMESPACE_CXX_HEADER_END - -#endif diff --git a/src/sat/cadical/phases.hpp b/src/sat/cadical/phases.hpp deleted file mode 100644 index 98e54d439..000000000 --- a/src/sat/cadical/phases.hpp +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef _phases_hpp_INCLUDED -#define _phases_hpp_INCLUDED - -#include "global.h" - -ABC_NAMESPACE_CXX_HEADER_START - -namespace CaDiCaL { - -struct Phases { - - vector<signed char> best; // The current largest trail phase. - vector<signed char> forced; // Forced through 'phase'. - vector<signed char> min; // The current minimum unsatisfied phase. - vector<signed char> prev; // Previous during local search. - vector<signed char> saved; // The actual saved phase. - vector<signed char> target; // The current target phase. -}; - -} // namespace CaDiCaL - -ABC_NAMESPACE_CXX_HEADER_END - -#endif diff --git a/src/sat/cadical/profile.hpp b/src/sat/cadical/profile.hpp deleted file mode 100644 index f3799389b..000000000 --- a/src/sat/cadical/profile.hpp +++ /dev/null @@ -1,280 +0,0 @@ -#ifndef _profiles_h_INCLUDED -#define _profiles_h_INCLUDED - -#include "global.h" - -ABC_NAMESPACE_CXX_HEADER_START - -/*------------------------------------------------------------------------*/ -#ifndef CADICAL_QUIET -/*------------------------------------------------------------------------*/ - -namespace CaDiCaL { - -struct Internal; - -/*------------------------------------------------------------------------*/ - -// The solver contains some built in profiling (even for optimized code). -// The idea is that even without using external tools it is possible to get -// an overview of where time is spent. This is enabled with the option -// 'profile', e.g., you might want to use '--profile=3', or even higher -// values for more detailed profiling information. Currently the default is -// '--profile=2', which should only induce a tiny profiling overhead. -// -// Profiling has a Heisenberg effect, since we rely on calling 'getrusage' -// instead of using profile counters and sampling. For functions which are -// executed many times, this overhead is substantial (say 10%-20%). For -// functions which are not executed many times there is in essence no -// overhead in measuring time spent in them. These get a smaller profiling -// level, which is the second argument in the 'PROFILE' macro below. Thus -// using '--profile=1' for instance should not add any penalty to the -// run-time, while '--profile=3' and higher levels slow down the solver. -// -// To profile say 'foo', just add another line 'PROFILE(foo,LEVEL)' and wrap -// the code to be profiled within a 'START (foo)' / 'STOP (foo)' block. - -/*------------------------------------------------------------------------*/ - -// Profile counters for functions which are not compiled in should be -// removed. This is achieved by adding a wrapper macro for them here. - -/*------------------------------------------------------------------------*/ - -#ifdef PROFILE_MODE -#define MROFILE PROFILE -#else -#define MROFILE(...) /**/ -#endif - -#define PROFILES \ - PROFILE (analyze, 3) \ - MROFILE (analyzestable, 4) \ - MROFILE (analyzeunstable, 4) \ - PROFILE (backward, 3) \ - PROFILE (block, 2) \ - PROFILE (bump, 4) \ - PROFILE (checking, 2) \ - PROFILE (cdcl, 1) \ - PROFILE (collect, 3) \ - PROFILE (compact, 3) \ - PROFILE (condition, 2) \ - PROFILE (congruence, 2) \ - PROFILE (congruencemerge, 4) \ - PROFILE (congruencematching, 4) \ - PROFILE (connect, 3) \ - PROFILE (copy, 4) \ - PROFILE (cover, 2) \ - PROFILE (decide, 3) \ - PROFILE (decompose, 3) \ - PROFILE (definition, 2) \ - PROFILE (elim, 2) \ - PROFILE (factor, 2) \ - PROFILE (fastelim, 2) \ - PROFILE (extend, 3) \ - PROFILE (extract, 3) \ - PROFILE (extractands, 4) \ - PROFILE (extractbinaries, 4) \ - PROFILE (extractites, 4) \ - PROFILE (extractxors, 4) \ - PROFILE (instantiate, 2) \ - PROFILE (lucky, 2) \ - PROFILE (lookahead, 2) \ - PROFILE (minimize, 4) \ - PROFILE (shrink, 4) \ - PROFILE (parse, 0) /* As 'opts.profile' might change in parsing*/ \ - PROFILE (probe, 2) \ - PROFILE (deduplicate, 3) \ - PROFILE (propagate, 4) \ - MROFILE (propstable, 4) \ - MROFILE (propunstable, 4) \ - PROFILE (reduce, 3) \ - PROFILE (restart, 3) \ - PROFILE (restore, 2) \ - PROFILE (search, 1) \ - PROFILE (solve, 0) \ - PROFILE (stable, 2) \ - PROFILE (sweep, 2) \ - PROFILE (sweepbackbone, 3) \ - PROFILE (sweepequivalences, 3) \ - PROFILE (sweepflip, 4) \ - PROFILE (sweepimplicant, 4) \ - PROFILE (sweepsolve, 4) \ - PROFILE (preprocess, 2) \ - PROFILE (simplify, 1) \ - PROFILE (subsume, 2) \ - PROFILE (ternary, 2) \ - PROFILE (transred, 3) \ - PROFILE (unstable, 2) \ - PROFILE (vivify, 2) \ - PROFILE (walk, 2) - -/*------------------------------------------------------------------------*/ - -// See 'START' and 'STOP' in 'macros.hpp' too. - -struct Profile { - - bool active; - double value; // accumulated time - double started; // started time if active - const char *name; // name of the profiled function (or 'phase') - const int level; // allows to cheaply test if profiling is enabled - - Profile (const char *n, int l) - : active (false), value (0), name (n), level (l) {} -}; - -struct Profiles { - Internal *internal; -#define PROFILE(NAME, LEVEL) Profile NAME; - PROFILES -#undef PROFILE - Profiles (Internal *); -}; - -} // namespace CaDiCaL - -#define NON_CADICAL_QUIET_PROFILE_CODE(CODE) CODE - -#else // !defined(CADICAL_QUIET) - -#define NON_CADICAL_QUIET_PROFILE_CODE(CODE) /**/ - -#endif - -/*------------------------------------------------------------------------*/ - -// Macros for Profiling support and checking and changing the mode. - -#define START(P) \ - do { \ - NON_CADICAL_QUIET_PROFILE_CODE ( \ - if (internal->profiles.P.level <= internal->opts.profile) \ - internal->start_profiling (internal->profiles.P, \ - internal->time ());) \ - } while (0) - -#define STOP(P) \ - do { \ - NON_CADICAL_QUIET_PROFILE_CODE ( \ - if (internal->profiles.P.level <= internal->opts.profile) \ - internal->stop_profiling (internal->profiles.P, \ - internal->time ());) \ - } while (0) - -#define PROFILE_ACTIVE(P) \ - ((internal->profiles.P.level <= internal->opts.profile) && \ - (internal->profiles.P.active)) - -/*------------------------------------------------------------------------*/ - -#define START_SIMPLIFIER(S, M) \ - do { \ - NON_CADICAL_QUIET_PROFILE_CODE (const double N = time (); \ - const int L = internal->opts.profile;) \ - if (!preprocessing && !lookingahead) { \ - NON_CADICAL_QUIET_PROFILE_CODE ( \ - if (stable && internal->profiles.stable.level <= L) \ - internal->stop_profiling (internal->profiles.stable, N); \ - if (!stable && internal->profiles.unstable.level <= L) \ - internal->stop_profiling (internal->profiles.unstable, N); \ - if (internal->profiles.search.level <= L) \ - internal->stop_profiling (internal->profiles.search, N);) \ - reset_mode (SEARCH); \ - } \ - NON_CADICAL_QUIET_PROFILE_CODE ( \ - if (internal->profiles.simplify.level <= L) \ - internal->start_profiling (internal->profiles.simplify, N); \ - if (internal->profiles.S.level <= L) \ - internal->start_profiling (internal->profiles.S, N);) \ - set_mode (SIMPLIFY); \ - set_mode (M); \ - } while (0) - -/*------------------------------------------------------------------------*/ - -#define STOP_SIMPLIFIER(S, M) \ - do { \ - NON_CADICAL_QUIET_PROFILE_CODE ( \ - const double N = time (); const int L = internal->opts.profile; \ - if (internal->profiles.S.level <= L) \ - internal->stop_profiling (internal->profiles.S, N); \ - if (internal->profiles.simplify.level <= L) \ - internal->stop_profiling (internal->profiles.simplify, N);) \ - reset_mode (M); \ - reset_mode (SIMPLIFY); \ - if (!preprocessing && !lookingahead) { \ - NON_CADICAL_QUIET_PROFILE_CODE ( \ - if (internal->profiles.search.level <= L) \ - internal->start_profiling (internal->profiles.search, N); \ - if (stable && internal->profiles.stable.level <= L) \ - internal->start_profiling (internal->profiles.stable, N); \ - if (!stable && internal->profiles.unstable.level <= L) \ - internal->start_profiling (internal->profiles.unstable, N);) \ - set_mode (SEARCH); \ - } \ - } while (0) - -/*------------------------------------------------------------------------*/ -// Used in 'walk' before calling 'walk_round' within the CDCL loop. - -#define START_INNER_WALK() \ - do { \ - require_mode (SEARCH); \ - CADICAL_assert (!preprocessing); \ - NON_CADICAL_QUIET_PROFILE_CODE ( \ - const double N = time (); const int L = internal->opts.profile; \ - if (stable && internal->profiles.stable.level <= L) \ - internal->stop_profiling (internal->profiles.stable, N); \ - if (!stable && internal->profiles.unstable.level <= L) \ - internal->stop_profiling (internal->profiles.unstable, N); \ - if (internal->profiles.walk.level <= L) \ - internal->start_profiling (internal->profiles.walk, N);) \ - set_mode (WALK); \ - } while (0) - -/*------------------------------------------------------------------------*/ -// Used in 'walk' after calling 'walk_round' within the CDCL loop. - -#define STOP_INNER_WALK() \ - do { \ - require_mode (SEARCH); \ - CADICAL_assert (!preprocessing); \ - reset_mode (WALK); \ - NON_CADICAL_QUIET_PROFILE_CODE ( \ - const double N = time (); const int L = internal->opts.profile; \ - if (internal->profiles.walk.level <= L) \ - internal->stop_profiling (internal->profiles.walk, N); \ - if (stable && internal->profiles.stable.level <= L) \ - internal->start_profiling (internal->profiles.stable, N); \ - if (!stable && internal->profiles.unstable.level <= L) \ - internal->start_profiling (internal->profiles.unstable, N); \ - internal->profiles.walk.started = (N);) \ - } while (0) - -/*------------------------------------------------------------------------*/ -// Used in 'local_search' before calling 'walk_round'. - -#define START_OUTER_WALK() \ - do { \ - require_mode (SEARCH); \ - CADICAL_assert (!preprocessing); \ - NON_CADICAL_QUIET_PROFILE_CODE (START (walk);) \ - set_mode (WALK); \ - } while (0) - -/*------------------------------------------------------------------------*/ -// Used in 'local_search' after calling 'walk_round'. - -#define STOP_OUTER_WALK() \ - do { \ - require_mode (SEARCH); \ - CADICAL_assert (!preprocessing); \ - reset_mode (WALK); \ - NON_CADICAL_QUIET_PROFILE_CODE (STOP (walk);) \ - } while (0) - -ABC_NAMESPACE_CXX_HEADER_END - -#endif // ifndef _profiles_h_INCLUDED diff --git a/src/sat/cadical/proof.hpp b/src/sat/cadical/proof.hpp deleted file mode 100644 index 69be6b080..000000000 --- a/src/sat/cadical/proof.hpp +++ /dev/null @@ -1,120 +0,0 @@ -#ifndef _proof_h_INCLUDED -#define _proof_h_INCLUDED - -#include "global.h" - -ABC_NAMESPACE_CXX_HEADER_START - -namespace CaDiCaL { - -/*------------------------------------------------------------------------*/ - -class File; -struct Clause; -struct Internal; -class Tracer; -class FileTracer; - -/*------------------------------------------------------------------------*/ - -// Provides proof checking and writing. - -class Proof { - - Internal *internal; - - vector<int> clause; // of external literals - vector<int64_t> proof_chain; // LRAT style proof chain of clause - int64_t clause_id; // id of added clause - bool redundant; - - // the 'tracers' - vector<Tracer *> tracers; // tracers (ie checker) - vector<FileTracer *> file_tracers; // file tracers (ie LRAT tracer) - - void add_literal (int internal_lit); // add to 'clause' - void add_literals (Clause *); // add to 'clause' - - void add_literals (const vector<int> &); // ditto - - void add_original_clause ( - bool restore = false); // notify observers of original clauses - void add_derived_clause (); - void add_assumption_clause (); - void delete_clause (); - void demote_clause (); - void weaken_minus (); - void strengthen (); - void finalize_clause (); - void add_assumption (); - void add_constraint (); - -public: - Proof (Internal *); - ~Proof (); - - void connect (Tracer *t) { tracers.push_back (t); } - void disconnect (Tracer *t); - // Add original clauses to the proof (for online proof checking). - // - void add_original_clause (int64_t, bool, const vector<int> &); - - void add_assumption_clause (int64_t, const vector<int> &, - const vector<int64_t> &); - void add_assumption_clause (int64_t, int, const vector<int64_t> &); - void add_assumption (int); - void add_constraint (const vector<int> &); - void reset_assumptions (); - - // Add/delete original clauses to/from the proof using their original - // external literals (from external->eclause) - // - void add_external_original_clause (int64_t, bool, const vector<int> &, - bool restore = false); - void delete_external_original_clause (int64_t, bool, const vector<int> &); - - // Add derived (such as learned) clauses to the proof. - // - void add_derived_empty_clause (int64_t, const vector<int64_t> &); - void add_derived_unit_clause (int64_t, int unit, const vector<int64_t> &); - void add_derived_clause (Clause *c, const vector<int64_t> &); - void add_derived_clause (int64_t, bool, const vector<int> &, - const vector<int64_t> &); - - // deletion of clauses. It comes in several variants, depending if the - // clause should be restored or not - void delete_clause (int64_t, bool, const vector<int> &); - void weaken_minus (int64_t, const vector<int> &); - void weaken_plus (int64_t, const vector<int> &); - void delete_unit_clause (int64_t id, const int lit); - void delete_clause (Clause *); - void weaken_minus (Clause *); - void weaken_plus (Clause *); - void strengthen (int64_t); - - void finalize_unit (int64_t, int); - void finalize_external_unit (int64_t, int); - void finalize_clause (int64_t, const vector<int> &c); - void finalize_clause (Clause *); - - void report_status (int, int64_t); - void begin_proof (int64_t); - void conclude_unsat (ConclusionType, const vector<int64_t> &); - void conclude_sat (const vector<int> &model); - void conclude_unknown (const vector<int> &trace); - void solve_query (); - // These two actually pretend to add and remove a clause. - // - void flush_clause (Clause *); // remove falsified literals - void strengthen_clause (Clause *, int, const vector<int64_t> &); - void otfs_strengthen_clause (Clause *, const vector<int> &, - const vector<int64_t> &); - - void flush (); -}; - -} // namespace CaDiCaL - -ABC_NAMESPACE_CXX_HEADER_END - -#endif diff --git a/src/sat/cadical/queue.hpp b/src/sat/cadical/queue.hpp deleted file mode 100644 index 14e1f2da7..000000000 --- a/src/sat/cadical/queue.hpp +++ /dev/null @@ -1,70 +0,0 @@ -#ifndef _queue_hpp_INCLUDED -#define _queue_hpp_INCLUDED - -#include "global.h" - -#include <vector> - -ABC_NAMESPACE_CXX_HEADER_START - -namespace CaDiCaL { - -// Links for double linked decision queue. - -struct Link { - - int prev, next; // variable indices - - // initialized explicitly in 'init_queue' -}; - -typedef std::vector<Link> Links; - -// Variable move to front (VMTF) decision queue ordered by 'bumped'. See -// our SAT'15 paper for an explanation on how this works. - -struct Queue { - - // We use integers instead of variable pointers. This is more compact and - // also avoids issues due to moving the variable table during 'resize'. - - int first, last; // anchors (head/tail) for doubly linked list - int unassigned; // all variables after this one are assigned - int64_t bumped; // see 'Internal.update_queue_unassigned' - - Queue () : first (0), last (0), unassigned (0), bumped (0) {} - - // We explicitly provide the mapping of integer indices to links to the - // following two (inlined) functions. This avoids including - // 'internal.hpp' and breaks a cyclic dependency, so we can keep their - // code here in this header file. Otherwise they are just ordinary doubly - // linked list 'dequeue' and 'enqueue' operations. - - inline void dequeue (Links &links, int idx) { - Link &l = links[idx]; - if (l.prev) - links[l.prev].next = l.next; - else - first = l.next; - if (l.next) - links[l.next].prev = l.prev; - else - last = l.prev; - } - - inline void enqueue (Links &links, int idx) { - Link &l = links[idx]; - if ((l.prev = last)) - links[last].next = idx; - else - first = idx; - last = idx; - l.next = 0; - } -}; - -} // namespace CaDiCaL - -ABC_NAMESPACE_CXX_HEADER_END - -#endif diff --git a/src/sat/cadical/radix.hpp b/src/sat/cadical/radix.hpp deleted file mode 100644 index 4c4d7b574..000000000 --- a/src/sat/cadical/radix.hpp +++ /dev/null @@ -1,186 +0,0 @@ -#ifndef _radix_hpp_INCLUDED -#define _radix_hpp_INCLUDED - -#include "global.h" - -#include <cassert> -#include <cstring> -#include <iterator> -#include <vector> - -ABC_NAMESPACE_CXX_HEADER_START - -namespace CaDiCaL { - -using namespace std; - -// This provides an implementation of a generic radix sort algorithm. The -// reason for having it is that for certain benchmarks and certain parts of -// CaDiCaL where sorting is used, the standard sorting algorithm 'sort' -// turned out to be a hot-spot. Up to 30% of the total running time was for -// instance used for some benchmarks in sorting variables during bumping -// to make sure to bump them in 'enqueued' order. -// -// Further, in most cases, where we need to sort something, sorting is -// actually performed on positive numbers (such as the 'enqueued' time stamp -// during bumping), which allows to use radix sort or variants. At least -// starting with medium sized arrays to be sorted (say above 1000 elements, -// but see discussion on 'MSORT' below), radix sort can be way faster. -// -// Finally it is stable, which is actually preferred most of the time too. -// -// This template algorithm 'rsort' takes as first template parameter the -// iterator class similar to the standard 'sort' algorithm template, but -// then as second parameter a function class (similar to the second 'less -// than' parameter of 'sort') which can obtain a 'rank' from each element, -// on which they are compared. The 'rank' should be able to turn an element -// into a number. The type of these ranks is determined automatically but -// should be 'unsigned'. - -struct pointer_rank { - typedef size_t Type; - Type operator() (void *ptr) { return (size_t) ptr; } -}; - -template <class I, class Rank> void rsort (I first, I last, Rank rank) { - typedef typename iterator_traits<I>::value_type T; - typedef typename Rank::Type R; - - CADICAL_assert (first <= last); - const size_t n = last - first; - if (n <= 1) - return; - - const size_t l = 8; // Radix 8, thus byte-wise. - const size_t w = (1 << l); // So many buckets. - - const unsigned mask = w - 1; // Fast mod 'w'. - -// Uncomment the following define for large values of 'w' in order to keep -// the large bucket array 'count' on the heap instead of the stack. -// -// #define CADICAL_RADIX_BUCKETS_ON_THE_HEAP -// -#ifdef CADICAL_RADIX_BUCKETS_ON_THE_HEAP - size_t *count = new size_t[w]; // Put buckets on the heap. -#else - size_t count[w]; // Put buckets on the stack. -#endif - - I a = first, b = last, c = a; - bool initialized = false; - std::vector<T> v; - - R upper = 0, lower = ~upper; - R shifted = mask; - bool bounded = false; - - R masked_lower = 0, masked_upper = mask; - - for (size_t i = 0; i < 8 * sizeof (rank (*first)); - i += l, shifted <<= l) { - - if (bounded && (lower & shifted) == (upper & shifted)) - continue; - - memset (count + masked_lower, 0, - (masked_upper - masked_lower + 1) * sizeof *count); - - const I end = c + n; - bool sorted = true; - R last = 0; - - for (I p = c; p != end; p++) { - const auto r = rank (*p); - if (!bounded) - lower &= r, upper |= r; - const auto s = r >> i; - const auto m = s & mask; - if (sorted && last > m) - sorted = false; - else - last = m; - count[m]++; - } - - masked_lower = (lower >> i) & mask; - masked_upper = (upper >> i) & mask; - - if (!bounded) { - bounded = true; - if ((lower & shifted) == (upper & shifted)) - continue; - } - - if (sorted) - continue; - - size_t pos = 0; - for (R j = masked_lower; j <= masked_upper; j++) { - const size_t delta = count[j]; - count[j] = pos; - pos += delta; - } - - if (!initialized) { - CADICAL_assert (&*c == &*a); // MS VC++ - v.resize (n); - b = v.begin (); - initialized = true; - } - - I d = (&*c == &*a) ? b : a; // MS VC++ - - for (I p = c; p != end; p++) { - const auto r = rank (*p); - const auto s = r >> i; - const auto m = s & mask; - d[count[m]++] = *p; - } - c = d; - } - - if (c == b) { - for (size_t i = 0; i < n; i++) - a[i] = b[i]; - } - -#ifdef CADICAL_RADIX_BUCKETS_ON_THE_HEAP - delete[] count; -#endif - -#ifndef CADICAL_NDEBUG - for (I p = first; p + 1 != last; p++) - CADICAL_assert (rank (p[0]) <= rank (p[1])); -#endif -} - -// It turns out that for small number of elements (like '100') and in -// particular for large value ranges the standard sorting function is -// considerably faster than our radix sort (like 2.5x). This negative effect -// vanishes at around 800 elements (sorting integers) and thus we provide a -// function 'MSORT' which selects between standard sort and radix sort based -// on the number of elements. However we failed to put this into proper C++ -// style template code and thus have to use a macro instead. We also do not -// use it everywhere instead of 'rsort' since it requires a fourth -// parameter, which is awkward, particular in those situation where we -// expect large arrays to be sorted anyhow (such as during sorting the -// clauses in an arena or the probes during probing). The first argument -// is the limit up to which we use the standard sort. Above the limit we -// use radix sort. As usual we do not want to hard code it here (default -// is '800') in order to make fuzzing and delta debugging more effective. - -#define MSORT(LIMIT, FIRST, LAST, RANK, LESS) \ - do { \ - const size_t N = LAST - FIRST; \ - if (N <= (size_t) (LIMIT)) \ - sort (FIRST, LAST, LESS); \ - else \ - rsort (FIRST, LAST, RANK); \ - } while (0) - -} // namespace CaDiCaL - -ABC_NAMESPACE_CXX_HEADER_END - -#endif diff --git a/src/sat/cadical/random.h b/src/sat/cadical/random.h deleted file mode 100644 index 62fe5ed19..000000000 --- a/src/sat/cadical/random.h +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef _random_h_INCLUDED -#define _random_h_INCLUDED - -#include "global.h" - -#include <assert.h> -#include <stdbool.h> -#include <stdint.h> - -ABC_NAMESPACE_HEADER_START - -typedef uint64_t generator; - -static inline uint64_t kissat_next_random64 (generator *rng) { - *rng *= 6364136223846793005ul; - *rng += 1442695040888963407ul; - return *rng; -} - -static inline unsigned kissat_next_random32 (generator *rng) { - return kissat_next_random64 (rng) >> 32; -} - -static inline unsigned kissat_pick_random (generator *rng, unsigned l, - unsigned r) { - CADICAL_assert (l <= r); - if (l == r) - return l; - const unsigned delta = r - l; - const unsigned tmp = kissat_next_random32 (rng); - const double fraction = tmp / 4294967296.0; - CADICAL_assert (0 <= fraction), CADICAL_assert (fraction < 1); - const unsigned scaled = delta * fraction; - CADICAL_assert (scaled < delta); - const unsigned res = l + scaled; - CADICAL_assert (l <= res), CADICAL_assert (res < r); - return res; -} - -static inline bool kissat_pick_bool (generator *rng) { - return kissat_pick_random (rng, 0, 2); -} - -static inline double kissat_pick_double (generator *rng) { - return kissat_next_random32 (rng) / 4294967296.0; -} - -ABC_NAMESPACE_HEADER_END - -#endif diff --git a/src/sat/cadical/random.hpp b/src/sat/cadical/random.hpp deleted file mode 100644 index a5c78d38a..000000000 --- a/src/sat/cadical/random.hpp +++ /dev/null @@ -1,104 +0,0 @@ -#ifndef _random_hpp_INCLUDED -#define _random_hpp_INCLUDED - -#include "global.h" - -#include <cstdint> - -ABC_NAMESPACE_CXX_HEADER_START - -// Random number generator. - -namespace CaDiCaL { - -class Random { - - uint64_t state; - - void add (uint64_t a) { - if (!(state += a)) - state = 1; - next (); - } - -public: - // Without argument use a machine, process and time dependent seed. - // - Random (); - - Random (uint64_t seed) : state (seed) {} - void operator= (uint64_t seed) { state = seed; } - Random (const Random &other) : state (other.seed ()) {} - - void operator+= (uint64_t a) { add (a); } - uint64_t seed () const { return state; } - - uint64_t next () { - state *= 6364136223846793005ul; - state += 1442695040888963407ul; - CADICAL_assert (state); - return state; - } - - uint32_t generate () { - next (); - return state >> 32; - } - int generate_int () { return (int) generate (); } - bool generate_bool () { return generate () < 2147483648u; } - - // Generate 'double' value in the range '[0,1]' excluding '1'. - // - double generate_double () { return generate () / 4294967295.0; } - - // Generate 'int' value in the range '[l,r]'. - // - int pick_int (int l, int r) { - CADICAL_assert (l <= r); - const unsigned delta = 1 + r - (unsigned) l; - unsigned tmp = generate (), scaled; - if (delta) { - const double fraction = tmp / 4294967296.0; - scaled = delta * fraction; - } else - scaled = tmp; - const int res = scaled + l; - CADICAL_assert (l <= res); - CADICAL_assert (res <= r); - return res; - } - - int pick_log (int l, int r) { - CADICAL_assert (l <= r); - const unsigned delta = 1 + r - (unsigned) l; - int log_delta = delta ? 0 : 32; - while (log_delta < 32 && (1u << log_delta) < delta) - log_delta++; - const int log_res = pick_int (0, log_delta); - unsigned tmp = generate (); - if (log_res < 32) - tmp &= (1u << log_res) - 1; - if (delta) - tmp %= delta; - const int res = l + tmp; - CADICAL_assert (l <= res), CADICAL_assert (res <= r); - return res; - } - - // Generate 'double' value in the range '[l,r]'. - // - double pick_double (double l, double r) { - CADICAL_assert (l <= r); - double res = (r - l) * generate_double (); - res += l; - CADICAL_assert (l <= res); - CADICAL_assert (res <= r); - return res; - } -}; - -} // namespace CaDiCaL - -ABC_NAMESPACE_CXX_HEADER_END - -#endif diff --git a/src/sat/cadical/range.hpp b/src/sat/cadical/range.hpp deleted file mode 100644 index 7049dab42..000000000 --- a/src/sat/cadical/range.hpp +++ /dev/null @@ -1,105 +0,0 @@ -#ifndef _range_hpp_INCLUDED -#define _range_hpp_INCLUDED - -#include "global.h" - -#include <cassert> - -ABC_NAMESPACE_CXX_HEADER_START - -namespace CaDiCaL { - -struct Clause; - -/*----------------------------------------------------------------------*/ - -// Used for compact and safe iteration over positive ranges of integers, -// particularly for iterating over all variable indices. -// -// Range vars (max_var); -// for (auto idx : vars) ... -// -// This iterates over '1, ..., max_var' and is safe for non-negative -// numbers, thus also for 'max_var == 0' or 'max_var == INT_MAX'. -// -// Note that -// -// for (int idx = 1; idx <= max_var; idx++) ... -// -// leads to an overflow if 'max_var == INT_MAX' and thus depending on what -// the compiler does ('int' overflow is undefined) might lead to any -// behaviour (infinite loop or worse array access way out of bounds). -// -// If we make 'idx' in this last 'for' loop an 'unsigned' then it is safe to -// use this idiom, but we would need to cast 'max_var' explicitly to 'int' -// in order to avoid a warning in the loop condition and actually everywhere -// where 'idx' is compared to a 'signed' expression. Worse for instance -// 'vals[-idx]' will lead to out of bounds access too. This is awkward and -// using the range iterator provided here is safer in general. -// -// Another issue is that the dereferencing operator '*' below is required to -// return a reference to the internal index of the iterator. Thus the 'idx' -// in the auto loop is actually of the same type as the internal state of -// the iterator. To keep it 'signed' and still avoid overflow issues we -// just have to make sure to use the proper increment (with two implicit -// casts, i.e., from 'int' to 'unsigned', then 'unsigned' addition and the -// result is cast back from 'unsigned' to 'int'). -// -// For simplicity we keep a reference to the actual maximum integer, e.g., -// 'max_var', which makes the idiom 'for (auto idx : vars) ...' possible. -// Further note that the referenced integer has to be non-negative before -// starting to iterate (it can be zero though), otherwise it breaks. - -class Range { - static unsigned inc (unsigned u) { return u + 1u; } - class iterator { - int idx; - - public: - iterator (int i) : idx (i) {} - void operator++ () { idx = inc (idx); } - const int &operator* () const { return idx; } - friend bool operator!= (const iterator &a, const iterator &b) { - return a.idx != b.idx; - } - }; - int &n; - -public: - iterator begin () const { return CADICAL_assert (n >= 0), iterator (inc (0)); } - iterator end () const { return CADICAL_assert (n >= 0), iterator (inc (n)); } - Range (int &m) : n (m) { CADICAL_assert (m >= 0); } -}; - -// Same, but iterating over literals '-1,1,-2,2,....,-max_var,max_var'. -// -// The only difference to 'Range' is the 'inc' function, but I am too lazy -// to figure out how to properly factor the code into a generic range -// template with 'inc' as only parameter. This gives at least clean code. - -class Sange { - static unsigned inc (unsigned u) { return ~u + (u >> 31); } - class iterator { - int lit; - - public: - iterator (int i) : lit (i) {} - void operator++ () { lit = inc (lit); } - const int &operator* () const { return lit; } - friend bool operator!= (const iterator &a, const iterator &b) { - return a.lit != b.lit; - } - }; - int &n; - -public: - iterator begin () const { return CADICAL_assert (n >= 0), iterator (inc (0)); } - iterator end () const { return CADICAL_assert (n >= 0), iterator (inc (n)); } - Sange (int &m) : n (m) { CADICAL_assert (m >= 0); } -}; - -} // namespace CaDiCaL - -ABC_NAMESPACE_CXX_HEADER_END - -#endif diff --git a/src/sat/cadical/reap.hpp b/src/sat/cadical/reap.hpp deleted file mode 100644 index 1ea10e6e3..000000000 --- a/src/sat/cadical/reap.hpp +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef _reap_h_INCLUDED -#define _reap_h_INCLUDED - -#include "global.h" - -#include <cstddef> -#include <vector> - -ABC_NAMESPACE_CXX_HEADER_START - -class Reap { -public: - Reap (); - void init (); - void release (); - inline bool empty () { return !num_elements; } - - inline size_t size () { return num_elements; } - - void push (unsigned); - void clear (); - unsigned pop (); - -private: - size_t num_elements; - unsigned last_deleted; - unsigned min_bucket; - unsigned max_bucket; - std::vector<unsigned> buckets[33]; -}; - -ABC_NAMESPACE_CXX_HEADER_END - -#endif diff --git a/src/sat/cadical/reluctant.hpp b/src/sat/cadical/reluctant.hpp deleted file mode 100644 index 495382b56..000000000 --- a/src/sat/cadical/reluctant.hpp +++ /dev/null @@ -1,88 +0,0 @@ -#ifndef _reluctant_hpp_INCLUDED -#define _reluctant_hpp_INCLUDED - -#include "global.h" - -#include <cassert> -#include <cstdint> - -ABC_NAMESPACE_CXX_HEADER_START - -namespace CaDiCaL { - -// This is Donald Knuth's version of the Luby restart sequence which he -// called 'reluctant doubling'. His bit-twiddling formulation in line (DK) -// requires to keep two words around which are updated every time the -// reluctant doubling sequence is advanced. The original version in the -// literature uses a complex recursive function which computes the length of -// the next inactive sub-sequence every time (but is state-less). -// -// In our code we incorporate a base interval 'period' and only after period -// many calls to 'tick' times the current sequence value we update the -// reluctant doubling sequence value. The 'tick' call is decoupled from -// the activation signal of the sequence (the 'bool ()' operator) through -// 'trigger'. It is also possible to set an upper limit to the length of an -// inactive sub-sequence. If that limit is reached the whole reluctant -// doubling sequence starts over with the initial values. - -class Reluctant { - - uint64_t u, v, limit; - uint64_t period, countdown; - bool trigger, limited; - -public: - Reluctant () : period (0), trigger (false) {} - - void enable (int p, int64_t l) { - CADICAL_assert (p > 0); - u = v = 1; - period = countdown = p; - trigger = false; - if (l <= 0) - limited = false; - else - limited = true, limit = l; - }; - - void disable () { period = 0, trigger = false; } - - // Increments the count until the 'period' is hit. Then it performs the - // actual increment of reluctant doubling. This gives the common 'Luby' - // sequence with the specified base interval period. As soon the limit is - // reached (countdown goes to zero) we remember this event and then - // disable updating the reluctant sequence until the signal is delivered. - - void tick () { - - if (!period) - return; // disabled - if (trigger) - return; // already triggered - if (--countdown) - return; // not there yet - - if ((u & -u) == v) - u = u + 1, v = 1; - else - v = 2 * v; // (DK) - - if (limited && v >= limit) - u = v = 1; - countdown = v * period; - trigger = true; - } - - operator bool () { - if (!trigger) - return false; - trigger = false; - return true; - } -}; - -} // namespace CaDiCaL - -ABC_NAMESPACE_CXX_HEADER_END - -#endif diff --git a/src/sat/cadical/resources.hpp b/src/sat/cadical/resources.hpp deleted file mode 100644 index 852668b32..000000000 --- a/src/sat/cadical/resources.hpp +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef _resources_hpp_INCLUDED -#define _resources_hpp_INCLUDED - -#include "global.h" - -#include <cstdint> - -ABC_NAMESPACE_CXX_HEADER_START - -namespace CaDiCaL { - -double absolute_real_time (); -double absolute_process_time (); - -uint64_t maximum_resident_set_size (); -uint64_t current_resident_set_size (); - -} // namespace CaDiCaL - -ABC_NAMESPACE_CXX_HEADER_END - -#endif // ifndef _resources_hpp_INCLUDED diff --git a/src/sat/cadical/score.hpp b/src/sat/cadical/score.hpp deleted file mode 100644 index 88196121e..000000000 --- a/src/sat/cadical/score.hpp +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef _score_hpp_INCLUDED -#define _score_hpp_INCLUDED - -#include "global.h" - -ABC_NAMESPACE_CXX_HEADER_START - -namespace CaDiCaL { - -struct score_smaller { - Internal *internal; - score_smaller (Internal *i) : internal (i) {} - bool operator() (unsigned a, unsigned b); -}; - -typedef heap<score_smaller> ScoreSchedule; - -} // namespace CaDiCaL - -ABC_NAMESPACE_CXX_HEADER_END - -#endif diff --git a/src/sat/cadical/signal.hpp b/src/sat/cadical/signal.hpp deleted file mode 100644 index 1dc2fb3b7..000000000 --- a/src/sat/cadical/signal.hpp +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef _signal_hpp_INCLUDED -#define _signal_hpp_INCLUDED - -#include "global.h" - -ABC_NAMESPACE_CXX_HEADER_START - -namespace CaDiCaL { - -// Helper class for handling signals in applications. - -class Handler { -public: - Handler () {} - virtual ~Handler () {} - virtual void catch_signal (int sig) = 0; -#ifndef WIN32 - virtual void catch_alarm (); -#endif -}; - -class Signal { - -public: - static void set (Handler *); - static void reset (); -#ifndef WIN32 - static void alarm (int seconds); - static void reset_alarm (); -#endif - - static const char *name (int sig); -}; - -} // namespace CaDiCaL - -ABC_NAMESPACE_CXX_HEADER_END - -#endif diff --git a/src/sat/cadical/stack.h b/src/sat/cadical/stack.h deleted file mode 100644 index 89f270388..000000000 --- a/src/sat/cadical/stack.h +++ /dev/null @@ -1,116 +0,0 @@ -#ifndef _stack_h_INCLUDED -#define _stack_h_INCLUDED - -#include "global.h" - -#include <stdlib.h> - -ABC_NAMESPACE_HEADER_START - -#define STACK(TYPE) \ - struct { \ - TYPE *begin; \ - TYPE *end; \ - TYPE *allocated; \ - } - -#define FULL_STACK(S) ((S).end == (S).allocated) -#define EMPTY_STACK(S) ((S).begin == (S).end) -#define SIZE_STACK(S) ((size_t) ((S).end - (S).begin)) -#define CAPACITY_STACK(S) ((size_t) ((S).allocated - (S).begin)) - -#define INIT_STACK(S) \ - do { \ - (S).begin = (S).end = (S).allocated = 0; \ - } while (0) - -#define TOP_STACK(S) (END_STACK (S)[CADICAL_assert (!EMPTY_STACK (S)), -1]) - -#define PEEK_STACK(S, N) \ - (BEGIN_STACK (S)[CADICAL_assert ((N) < SIZE_STACK (S)), (N)]) - -#define POKE_STACK(S, N, E) \ - do { \ - PEEK_STACK (S, N) = (E); \ - } while (0) - -#define POP_STACK(S) (CADICAL_assert (!EMPTY_STACK (S)), *--(S).end) - -#define PUSH_STACK(S, E) \ - do { \ - if (FULL_STACK (S)) \ - ENLARGE_STACK (S); \ - *(S).end++ = (E); \ - } while (0) - -#define BEGIN_STACK(S) (S).begin - -#define END_STACK(S) (S).end - -#define CLEAR_STACK(S) \ - do { \ - (S).end = (S).begin; \ - } while (0) - -#define RESIZE_STACK(S, NEW_SIZE) \ - do { \ - const size_t TMP_NEW_SIZE = (NEW_SIZE); \ - CADICAL_assert (TMP_NEW_SIZE <= SIZE_STACK (S)); \ - (S).end = (S).begin + TMP_NEW_SIZE; \ - } while (0) - -#define SET_END_OF_STACK(S, P) \ - do { \ - CADICAL_assert (BEGIN_STACK (S) <= (P)); \ - CADICAL_assert ((P) <= END_STACK (S)); \ - if ((P) == END_STACK (S)) \ - break; \ - (S).end = (P); \ - } while (0) - -#define RELEASE_STACK(S) \ - do { \ - DEALLOC ((S).begin, CAPACITY_STACK (S)); \ - INIT_STACK (S); \ - } while (0) - -#define REMOVE_STACK(T, S, E) \ - do { \ - CADICAL_assert (!EMPTY_STACK (S)); \ - T *END_REMOVE_STACK = END_STACK (S); \ - T *P_REMOVE_STACK = BEGIN_STACK (S); \ - while (*P_REMOVE_STACK != (E)) { \ - P_REMOVE_STACK++; \ - CADICAL_assert (P_REMOVE_STACK != END_REMOVE_STACK); \ - } \ - P_REMOVE_STACK++; \ - while (P_REMOVE_STACK != END_REMOVE_STACK) { \ - P_REMOVE_STACK[-1] = *P_REMOVE_STACK; \ - P_REMOVE_STACK++; \ - } \ - (S).end--; \ - } while (0) - -#define all_stack(T, E, S) \ - T E, *E##_PTR = BEGIN_STACK (S), *const E##_END = END_STACK (S); \ - E##_PTR != E##_END && (E = *E##_PTR, true); \ - ++E##_PTR - -#define all_pointers(T, E, S) \ - T *E, *const *E##_PTR = BEGIN_STACK (S), \ - *const *const E##_END = END_STACK (S); \ - E##_PTR != E##_END && (E = *E##_PTR, true); \ - ++E##_PTR - -// clang-format off - -typedef STACK (char) chars; -typedef STACK (int) ints; -typedef STACK (size_t) sizes; -typedef STACK (unsigned) unsigneds; - -// clang-format on - -ABC_NAMESPACE_HEADER_END - -#endif diff --git a/src/sat/cadical/stats.hpp b/src/sat/cadical/stats.hpp deleted file mode 100644 index 4a6afa9c9..000000000 --- a/src/sat/cadical/stats.hpp +++ /dev/null @@ -1,376 +0,0 @@ -#ifndef _stats_hpp_INCLUDED -#define _stats_hpp_INCLUDED - -#include "global.h" - -#include <cstdint> -#include <cstdlib> -#include <vector> - -ABC_NAMESPACE_CXX_HEADER_START - -namespace CaDiCaL { - -struct Internal; - -struct Stats { - - Internal *internal; - - int64_t vars = 0; // internal initialized variables - - int64_t conflicts = 0; // generated conflicts in 'propagate' - int64_t decisions = 0; // number of decisions in 'decide' - - struct { - int64_t cover = 0; // propagated during covered clause elimination - int64_t instantiate = 0; // propagated during variable instantiation - int64_t probe = 0; // propagated during probing - int64_t search = 0; // propagated literals during search - int64_t transred = 0; // propagated during transitive reduction - int64_t vivify = 0; // propagated during vivification - int64_t walk = 0; // propagated during local search - } propagations; - - struct { - int64_t search[2] = {0}; - int64_t factor = 0; - int64_t probe = 0; - int64_t sweep = 0; - int64_t ternary = 0; - int64_t vivify = 0; - } ticks; - - struct { - int64_t ext_cb = 0; // number of times any external callback was called - int64_t eprop_call = 0; // number of times external_propagate was called - int64_t eprop_prop = 0; // number of times external propagate propagated - int64_t eprop_conf = - 0; // number of times ex-propagate was already falsified - int64_t eprop_expl = - 0; // number of times external propagate was explained - int64_t elearn_call = - 0; // number of times external clause learning was tried - int64_t elearned = - 0; // learned external clauses (incl. eprop explanations) - int64_t elearn_prop = - 0; // number of learned and propagating external clauses - int64_t elearn_conf = - 0; // number of learned and conflicting external clauses - int64_t echeck_call = 0; // number of checking found complete solutions - } ext_prop; - - int64_t condassinit = 0; // initial assigned literals - int64_t condassirem = 0; // initial assigned literals for blocked - int64_t condassrem = 0; // remaining assigned literals for blocked - int64_t condassvars = 0; // sum of active variables at initial assignment - int64_t condautinit = 0; // initial literals in autarky part - int64_t condautrem = 0; // remaining literals in autarky part for blocked - int64_t condcands = 0; // globally blocked candidate clauses - int64_t condcondinit = 0; // initial literals in conditional part - int64_t condcondrem = - 0; // remaining literals in conditional part for blocked - int64_t conditioned = 0; // globally blocked clauses eliminated - int64_t conditionings = 0; // globally blocked clause eliminations - int64_t condprops = 0; // propagated unassigned literals - - struct { - int64_t block = 0; // block marked literals - int64_t elim = 0; // elim marked variables - int64_t subsume = 0; // subsume marked variables - int64_t ternary = 0; // ternary marked variables - int64_t factor = 0; - } mark; - - struct { - int64_t total = 0; - int64_t redundant = 0; - int64_t irredundant = 0; - } current, added; // Clauses. - - struct { - double process = 0, real = 0; - } time; - - struct { - int64_t count = 0; // number of covered clause elimination rounds - int64_t asymmetric = 0; // number of asymmetric tautologies in CCE - int64_t blocked = 0; // number of blocked covered tautologies - int64_t total = 0; // total number of eliminated clauses - } cover; - - struct { - int64_t tried = 0; - int64_t succeeded = 0; - struct { - int64_t one = 0, zero = 0; - } constant, forward, backward; - struct { - int64_t positive = 0, negative = 0; - } horn; - } lucky; - - struct { - int64_t total = 0; // total number of happened rephases - int64_t best = 0; // how often reset to best phases - int64_t flipped = 0; // how often reset phases by flipping - int64_t inverted = 0; // how often reset to inverted phases - int64_t original = 0; // how often reset to original phases - int64_t random = 0; // how often randomly reset phases - int64_t walk = 0; // phases improved through random walked - } rephased; - - struct { - int64_t count = 0; - int64_t broken = 0; - int64_t flips = 0; - int64_t minimum = 0; - } walk; - - struct { - int64_t count = 0; // flushings of learned clauses counter - int64_t learned = 0; // flushed learned clauses - int64_t hyper = 0; // flushed hyper binary/ternary clauses - } flush; - - int64_t compacts = 0; // number of compactifications - int64_t shuffled = 0; // shuffled queues and scores - int64_t restarts = 0; // actual number of happened restarts - int64_t restartlevels = 0; // levels at restart - int64_t restartstable = 0; // actual number of happened restarts - int64_t stabphases = 0; // number of stabilization phases - int64_t stabconflicts = - 0; // number of search conflicts during stabilizing - int64_t rescored = 0; // number of times scores were rescored - int64_t reused = 0; // number of reused trails - int64_t reusedlevels = 0; // reused levels at restart - int64_t reusedstable = 0; // number of reused trails during stabilizing - int64_t sections = 0; // 'section' counter - int64_t chrono = 0; // chronological backtracks - int64_t backtracks = 0; // number of backtracks - int64_t improvedglue = 0; // improved glue during bumping - int64_t promoted1 = 0; // promoted clauses to tier one - int64_t promoted2 = 0; // promoted clauses to tier two - int64_t bumped = 0; // seen and bumped variables in 'analyze' - int64_t recomputed = 0; // recomputed glues 'recompute_glue' - int64_t searched = 0; // searched decisions in 'decide' - int64_t reductions = 0; // 'reduce' counter - int64_t reduced = 0; // number of reduced clauses - int64_t reduced_sqrt = 0; - int64_t reduced_prct = 0; - int64_t collected = 0; // number of collected bytes - int64_t collections = 0; // number of garbage collections - int64_t hbrs = 0; // hyper binary resolvents - int64_t hbrsizes = 0; // sum of hyper resolved base clauses - int64_t hbreds = 0; // redundant hyper binary resolvents - int64_t hbrsubs = 0; // subsuming hyper binary resolvents - int64_t instried = 0; // number of tried instantiations - int64_t instantiated = 0; // number of successful instantiations - int64_t instrounds = 0; // number of instantiation rounds - int64_t subsumed = 0; // number of subsumed clauses - int64_t deduplicated = 0; // number of removed duplicated binary clauses - int64_t deduplications = 0; // number of deduplication phases - int64_t strengthened = 0; // number of strengthened clauses - - int64_t eliminated_equi = - 0; // number of successful equivalence eliminations - int64_t eliminated_and = 0; // number of successful AND gate eliminations - int64_t eliminated_ite = 0; // number of successful ITE gate eliminations - int64_t eliminated_xor = 0; // number of successful XOR gate eliminations - int64_t eliminated_def = - 0; // number of successful definition eliminations - - int64_t definitions_checked = 0; - int64_t definitions_extracted = 0; - int64_t definition_units = 0; - int64_t definition_ticks = 0; - - int64_t factor = 0; - int64_t factored = 0; - int64_t factor_added = 0; - int64_t variables_extension = 0; - int64_t variables_original = 0; - int64_t literals_factored = 0; - int64_t clauses_unfactored = 0; - int64_t literals_unfactored = 0; - - int64_t elimotfstr = - 0; // number of on-the-fly strengthened during elimination - int64_t subirr = 0; // number of subsumed irredundant clauses - int64_t subred = 0; // number of subsumed redundant clauses - int64_t subtried = 0; // number of tried subsumptions - int64_t subchecks = 0; // number of pair-wise subsumption checks - int64_t subchecks2 = 0; // same but restricted to binary clauses - int64_t elimotfsub = - 0; // number of on-the-fly subsumed during elimination - int64_t subsumerounds = 0; // number of subsumption rounds - int64_t subsumephases = 0; // number of scheduled subsumption phases - int64_t eagertried = 0; // number of traversed eager subsumed candidates - int64_t eagersub = - 0; // number of eagerly subsumed recently learned clauses - int64_t elimres = 0; // number of resolved clauses in BVE - int64_t elimrestried = 0; // number of tried resolved clauses in BVE - int64_t elimfastrounds = 0; // number of elimination rounds - int64_t elimrounds = 0; // number of elimination rounds - int64_t elimphases = 0; // number of scheduled elimination phases - int64_t elimfastphases = 0; // number of scheduled elimination phases - int64_t elimcompleted = 0; // number complete elimination procedures - int64_t elimtried = 0; // number of variable elimination attempts - int64_t elimsubst = 0; // number of eliminations through substitutions - int64_t elimgates = 0; // number of gates found during elimination - int64_t elimequivs = 0; // number of equivalences found during elimination - int64_t elimands = 0; // number of AND gates found during elimination - int64_t elimites = 0; // number of ITE gates found during elimination - int64_t elimxors = 0; // number of XOR gates found during elimination - int64_t elimbwsub = 0; // number of eager backward subsumed clauses - int64_t elimbwstr = 0; // number of eager backward strengthened clauses - int64_t ternary = 0; // number of ternary resolution phases - int64_t ternres = 0; // number of ternary resolutions - int64_t htrs = 0; // number of hyper ternary resolvents - int64_t htrs2 = 0; // number of binary hyper ternary resolvents - int64_t htrs3 = 0; // number of ternary hyper ternary resolvents - int64_t decompositions = 0; // number of SCC + ELS - int64_t vivifications = 0; // number of vivifications - int64_t vivifychecks = 0; // checked clauses during vivification - int64_t vivifydecs = 0; // vivification decisions - int64_t vivifyreused = 0; // reused vivification decisions - int64_t vivifysched = 0; // scheduled clauses for vivification - int64_t vivifysubs = 0; // subsumed clauses during vivification - int64_t vivifysubred = 0; // subsumed clauses during vivification - int64_t vivifysubirr = 0; // subsumed clauses during vivification - int64_t vivifystrs = 0; // strengthened clauses during vivification - int64_t vivifystrirr = 0; // strengthened irredundant clause - int64_t vivifystred1 = 0; // strengthened redundant clause (1) - int64_t vivifystred2 = 0; // strengthened redundant clause (2) - int64_t vivifystred3 = 0; // strengthened redundant clause (3) - int64_t vivifyunits = 0; // units during vivification - int64_t vivifyimplied = 0; // implied during vivification - int64_t vivifyinst = 0; // instantiation during vivification - int64_t vivifydemote = 0; // demoting during vivification - int64_t transreds = 0; - int64_t transitive = 0; - struct { - int64_t literals = 0; - int64_t clauses = 0; - } learned; - int64_t minimized = 0; // minimized literals - int64_t shrunken = 0; // shrunken literals - int64_t minishrunken = 0; // shrunken during minimization literals - - int64_t irrlits = 0; // literals in irredundant clauses - struct { - int64_t bytes = 0; - int64_t clauses = 0; - int64_t literals = 0; - } garbage; - - int64_t sweep_units = 0; - int64_t sweep_flip_backbone = 0; - int64_t sweep_fixed_backbone = 0; - int64_t sweep_flipped_backbone = 0; - int64_t sweep_solved_backbone = 0; - int64_t sweep_sat_backbone = 0; - int64_t sweep_unsat_backbone = 0; - int64_t sweep_unknown_backbone = 0; - int64_t sweep_flip_equivalences = 0; - int64_t sweep_flipped_equivalences = 0; - int64_t sweep_sat_equivalences = 0; - int64_t sweep_unsat_equivalences = 0; - int64_t sweep_unknown_equivalences = 0; - int64_t sweep_solved_equivalences = 0; - int64_t sweep_equivalences = 0; - int64_t sweep_variables = 0; - int64_t sweep_completed = 0; - int64_t sweep_solved = 0; - int64_t sweep_sat = 0; - int64_t sweep_unsat = 0; - int64_t sweep_depth = 0; - int64_t sweep_environment = 0; - int64_t sweep_clauses = 0; - int64_t sweep = 0; - - int64_t units = 0; // learned unit clauses - int64_t binaries = 0; // learned binary clauses - int64_t inprobingphases = 0; // number of scheduled probing phases - int64_t probingrounds = 0; // number of probing rounds - int64_t inprobesuccess = 0; // number successful probing phases - int64_t probed = 0; // number of probed literals - int64_t failed = 0; // number of failed literals - int64_t hyperunary = 0; // hyper unary resolved unit clauses - int64_t probefailed = 0; // failed literals from probing - int64_t transredunits = 0; // units derived in transitive reduction - int64_t blockings = 0; // number of blocked clause eliminations - int64_t blocked = 0; // number of actually blocked clauses - int64_t blockres = 0; // number of resolutions during blocking - int64_t blockcands = 0; // number of clause / pivot pairs tried - int64_t blockpured = 0; // number of clauses blocked through pure literals - int64_t blockpurelits = 0; // number of pure literals - int64_t extensions = 0; // number of extended witnesses - int64_t extended = 0; // number of flipped literals during extension - int64_t weakened = 0; // number of clauses pushed to extension stack - int64_t weakenedlen = 0; // lengths of weakened clauses - int64_t restorations = 0; // number of restore calls - int64_t restored = 0; // number of restored clauses - int64_t reactivated = 0; // number of reactivated clauses - int64_t restoredlits = 0; // number of restored literals - - int64_t preprocessings = 0; - - int64_t ilbtriggers = 0; - int64_t ilbsuccess = 0; - int64_t levelsreused = 0; - int64_t literalsreused = 0; - int64_t assumptionsreused = 0; - int64_t tierecomputed = 0; // number of tier recomputation; - - struct { - int64_t fixed = 0; // number of top level assigned variables - int64_t eliminated = 0; // number of eliminated variables - int64_t fasteliminated = 0; // number of fast eliminated variables only - int64_t substituted = 0; // number of substituted variables - int64_t pure = 0; // number of pure literals - } all, now; - - struct { - int64_t strengthened = 0; // number of clauses strengthened during OTFS - int64_t subsumed = 0; // number of clauses subsumed by OTFS - } otfs; - - int64_t unused = 0; // number of unused variables - int64_t active = 0; // number of active variables - int64_t inactive = 0; // number of inactive variables - std::vector<uint64_t> bump_used = {0, 0}; - std::vector<std::vector<uint64_t>> used; // used clauses in focused mode - - struct { - int64_t gates = 0; - int64_t ands = 0; - int64_t ites = 0; - int64_t xors = 0; - int64_t units = 0; - int64_t congruent = 0; - int64_t rounds = 0; - int64_t unary_and = 0; - int64_t unaries = 0; - int64_t rewritten_ands = 0; - int64_t simplified = 0; - int64_t simplified_ands = 0; - int64_t simplified_xors = 0; - int64_t simplified_ites = 0; - int64_t subsumed = 0; - int64_t trivial_ite = 0; - int64_t unary_ites = 0; - } congruence; - - Stats (); - - void print (Internal *); -}; - -/*------------------------------------------------------------------------*/ - -} // namespace CaDiCaL - -ABC_NAMESPACE_CXX_HEADER_END - -#endif diff --git a/src/sat/cadical/sweep.hpp b/src/sat/cadical/sweep.hpp deleted file mode 100644 index ad093e070..000000000 --- a/src/sat/cadical/sweep.hpp +++ /dev/null @@ -1,67 +0,0 @@ -#ifndef _sweep_hpp_INCLUDED -#define _sweep_hpp_INCLUDED - -#include "global.h" - -ABC_NAMESPACE_CXX_HEADER_START - -namespace CaDiCaL { - -struct Internal; - -struct sweep_proof_clause { - unsigned sweep_id; // index for sweeper.clauses - int64_t cad_id; // cadical id - unsigned kit_id; // cadical_kitten id - bool learned; - vector<int> literals; - vector<unsigned> chain; // lrat -}; - -struct sweep_blocked_clause { - int blit; - int64_t id; - vector<int> literals; -}; - -struct sweep_binary { - int lit; - int other; - int64_t id; -}; - -struct Sweeper { - Sweeper (Internal *internal); - ~Sweeper (); - Internal *internal; - Random random; - vector<unsigned> depths; - int *reprs; - vector<int> next, prev; - int first, last, blit; - unsigned encoded; - unsigned save; - vector<int> vars; - vector<Clause *> clauses; - vector<sweep_blocked_clause> blocked_clauses; - bool flush_blocked_clauses; - vector<int> blockable; - vector<int> clause; - vector<int> propagate; - vector<int> backbone; - vector<int> partition; - vector<bool> prev_units; - vector<sweep_binary> binaries; - vector<sweep_proof_clause> core[2]; - uint64_t current_ticks; - struct { - uint64_t ticks; - unsigned clauses, depth, vars; - } limit; -}; - -} // namespace CaDiCaL - -ABC_NAMESPACE_CXX_HEADER_END - -#endif diff --git a/src/sat/cadical/terminal.hpp b/src/sat/cadical/terminal.hpp deleted file mode 100644 index a99346b7c..000000000 --- a/src/sat/cadical/terminal.hpp +++ /dev/null @@ -1,104 +0,0 @@ -#ifndef _terminal_hpp_INCLUDED -#define _terminal_hpp_INCLUDED - -#include "global.h" - -ABC_NAMESPACE_CXX_HEADER_START - -namespace CaDiCaL { - -class Terminal { - - FILE *file; // 'stdout' or 'stderr' - bool connected; // Connected to terminal. - bool use_colors; // Use colors. - bool reset_on_exit; // Reset on exit. - - void escape () { - CADICAL_assert (connected); - fputs ("\033[", file); - } - - void color (int color, bool bright) { - if (!use_colors) - return; - CADICAL_assert (connected); - escape (); - fputc (bright ? '1' : '0', file); - fprintf (file, ";%dm", color); - fflush (file); - } - - void code (const char *str) { - if (!use_colors) - return; - if (!connected) - return; - escape (); - fputs (str, file); - fflush (file); - } - -public: - Terminal (FILE *file); - ~Terminal (); - - void disable (); // Assume disconnected in any case. - void force_colors (); - void force_no_colors (); - void force_reset_on_exit (); - - bool colors () { return use_colors; } - - operator bool () const { return connected; } - - void red (bool bright = false) { color (31, bright); } - void green (bool bright = false) { color (32, bright); } - void yellow (bool bright = false) { color (33, bright); } - void blue (bool bright = false) { color (34, bright); } - void magenta (bool bright = false) { color (35, bright); } - void black (bool bright = false) { color (90, bright); } - void cyan (bool bright = false) { color (96, bright); } - - void bold () { code ("1m"); } - void normal () { code ("0m"); } - void inverse () { code ("7m"); } - void underline () { code ("4m"); } - -#define MODIFY(CODE) (use_colors ? "\033[" CODE "m" : "") - - const char *bright_magenta_code () { return MODIFY ("1;35"); } - const char *magenta_code () { return MODIFY ("0;35"); } - const char *blue_code () { return MODIFY ("0;34"); } - const char *bright_blue_code () { return MODIFY ("1;34"); } - const char *yellow_code () { return MODIFY ("0;33"); } - const char *bright_yellow_code () { return MODIFY ("1;33"); } - const char *green_code () { return MODIFY ("0;32"); } - const char *red_code () { return MODIFY ("0;31"); } - const char *cyan_code () { return MODIFY ("0;96"); } - const char *bright_red_code () { return MODIFY ("1;31"); } - const char *normal_code () { return MODIFY ("0"); } - const char *bold_code () { return MODIFY ("1"); } - - void cursor (bool on) { code (on ? "?25h" : "?25l"); } - - void erase_until_end_of_line () { code ("K"); } - - void erase_line_if_connected_otherwise_new_line () { - if (connected) - code ("1G"); - else - fputc ('\n', file), fflush (file); - } - - void reset (); -}; - -extern Terminal tout; // Terminal of 'stdout' (file descriptor '1') -extern Terminal terr; // Terminal of 'stderr' (file descriptor '2') - -} // namespace CaDiCaL - -ABC_NAMESPACE_CXX_HEADER_END - -#endif diff --git a/src/sat/cadical/testing.hpp b/src/sat/cadical/testing.hpp deleted file mode 100644 index f90569e5c..000000000 --- a/src/sat/cadical/testing.hpp +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef _testing_hpp_INCLUDED -#define _testing_hpp_INCLUDED - -#include "global.h" - -// This class provides access to 'internal' which should only be used for -// internal testing and not for any other purpose as 'internal' is supposed -// to be hidden. - -#include "cadical.hpp" - -ABC_NAMESPACE_CXX_HEADER_START - -namespace CaDiCaL { - -class Testing { - Solver *solver; - -public: - Testing (Solver &s) : solver (&s) {} - Testing (Solver *s) : solver (s) {} - Internal *internal () { return solver->internal; } - External *external () { return solver->external; } -}; - -} // namespace CaDiCaL - -ABC_NAMESPACE_CXX_HEADER_END - -#endif diff --git a/src/sat/cadical/tracer.hpp b/src/sat/cadical/tracer.hpp deleted file mode 100644 index d1a9f1137..000000000 --- a/src/sat/cadical/tracer.hpp +++ /dev/null @@ -1,183 +0,0 @@ -#ifndef _tracer_hpp_INCLUDED -#define _tracer_hpp_INCLUDED - -#include "global.h" - -#include <cstdint> -#include <vector> - -ABC_NAMESPACE_CXX_HEADER_START - -namespace CaDiCaL { - -struct Internal; - -enum ConclusionType { CONFLICT = 1, ASSUMPTIONS = 2, CONSTRAINT = 4 }; - -// Proof tracer class to observer all possible proof events, -// such as added or deleted clauses. -// An implementation can decide on which events to act. -// -class Tracer { - -public: - Tracer () {} - virtual ~Tracer () {} - - /*------------------------------------------------------------------------*/ - /* */ - /* Basic Events */ - /* */ - /*------------------------------------------------------------------------*/ - - // Notify the tracer that a original clause has been added. - // Includes ID and whether the clause is redundant or irredundant - // Arguments: ID, redundant, clause, restored - // - virtual void add_original_clause (int64_t, bool, const std::vector<int> &, - bool = false) {} - - // Notify the observer that a new clause has been derived. - // Includes ID and whether the clause is redundant or irredundant - // If antecedents are derived they will be included here. - // Arguments: ID, redundant, clause, antecedents - // - virtual void add_derived_clause (int64_t, bool, const std::vector<int> &, - const std::vector<int64_t> &) {} - - // Notify the observer that a clause is deleted. - // Includes ID and redundant/irredundant - // Arguments: ID, redundant, clause - // - virtual void delete_clause (int64_t, bool, const std::vector<int> &) {} - - // Notify the observer that a clause is deleted. - // Includes ID and redundant/irredundant - // Arguments: ID, redundant, clause - // - virtual void demote_clause (uint64_t, const std::vector<int> &) {} - - // Notify the observer to remember that the clause might be restored later - // Arguments: ID, clause - // - virtual void weaken_minus (int64_t, const std::vector<int> &) {} - - // Notify the observer that a clause is strengthened - // Arguments: ID - // - virtual void strengthen (int64_t) {} - - // Notify the observer that the solve call ends with status StatusType - // If the status is UNSAT and an empty clause has been derived, the second - // argument will contain its id. - // Note that the empty clause is already added through add_derived_clause - // and finalized with finalize_clause - // Arguments: int, ID - // - virtual void report_status (int, int64_t) {} - - /*------------------------------------------------------------------------*/ - /* */ - /* Specifically non-incremental */ - /* */ - /*------------------------------------------------------------------------*/ - - // Notify the observer that a clause is finalized. - // Arguments: ID, clause - // - virtual void finalize_clause (int64_t, const std::vector<int> &) {} - - // Notify the observer that the proof begins with a set of reserved ids - // for original clauses. Given ID is the first derived clause ID. - // Arguments: ID - // - virtual void begin_proof (int64_t) {} - - /*------------------------------------------------------------------------*/ - /* */ - /* Specifically incremental */ - /* */ - /*------------------------------------------------------------------------*/ - - // Notify the observer that an assumption has been added - // Arguments: assumption_literal - // - virtual void solve_query () {} - - // Notify the observer that an assumption has been added - // Arguments: assumption_literal - // - virtual void add_assumption (int) {} - - // Notify the observer that a constraint has been added - // Arguments: constraint_clause - // - virtual void add_constraint (const std::vector<int> &) {} - - // Notify the observer that assumptions and constraints are reset - // - virtual void reset_assumptions () {} - - // Notify the observer that this clause could be derived, which - // is the negation of a core of failing assumptions/constraints. - // If antecedents are derived they will be included here. - // Arguments: ID, clause, antecedents - // - virtual void add_assumption_clause (int64_t, const std::vector<int> &, - const std::vector<int64_t> &) {} - - // Notify the observer that conclude unsat was requested. - // will give either the id of the empty clause, the id of a failing - // assumption clause or the ids of the failing constrain clauses - // Arguments: conclusion_type, clause_ids - // - virtual void conclude_unsat (ConclusionType, - const std::vector<int64_t> &) {} - - // Notify the observer that conclude sat was requested. - // will give the complete model as a vector. - // - virtual void conclude_sat (const std::vector<int> &) {} - - // Notify the observer that conclude unknown was requested. - // will give the current trail as a vector. - // - virtual void conclude_unknown (const std::vector<int> &) {} -}; - -/*--------------------------------------------------------------------------*/ - -// Following tracers for internal use. - -struct InternalTracer : public Tracer { -public: - InternalTracer () {} - virtual ~InternalTracer () {} - - virtual void connect_internal (Internal *) {} -}; - -class StatTracer : public InternalTracer { -public: - StatTracer () {} - virtual ~StatTracer () {} - - virtual void print_stats () {} -}; - -class FileTracer : public InternalTracer { - -public: - FileTracer () {} - virtual ~FileTracer () {} - - virtual bool closed () = 0; - virtual void close (bool print = false) = 0; - virtual void flush (bool print = false) = 0; -}; - -} // namespace CaDiCaL - -ABC_NAMESPACE_CXX_HEADER_END - -#endif diff --git a/src/sat/cadical/util.hpp b/src/sat/cadical/util.hpp deleted file mode 100644 index 3882c6ede..000000000 --- a/src/sat/cadical/util.hpp +++ /dev/null @@ -1,173 +0,0 @@ -#ifndef _util_hpp_INCLUDED -#define _util_hpp_INCLUDED - -#include "global.h" - -#include <cassert> -#include <cstdint> -#include <vector> - -ABC_NAMESPACE_CXX_HEADER_START - -namespace CaDiCaL { - -using namespace std; - -// Common simple utility functions independent from 'Internal'. - -/*------------------------------------------------------------------------*/ - -inline double relative (double a, double b) { return b ? a / b : 0; } -inline double percent (double a, double b) { return relative (100 * a, b); } -inline int sign (int lit) { return (lit > 0) - (lit < 0); } -inline unsigned bign (int lit) { return 1 + (lit < 0); } - -/*------------------------------------------------------------------------*/ - -bool has_suffix (const char *str, const char *suffix); -bool has_prefix (const char *str, const char *prefix); - -/*------------------------------------------------------------------------*/ - -// Parse integer string in the form of -// -// true -// false -// [-]<mantissa>[e<exponent>] -// -// and in the latter case '<val>' has to be within [-INT_MAX,INT_MAX]. -// -// The function returns true if parsing is successful and then also sets -// the second argument to the parsed value. - -bool parse_int_str (const char *str, int &); - -/*------------------------------------------------------------------------*/ - -inline bool is_power_of_two (unsigned n) { return n && !(n & (n - 1)); } - -inline bool contained (int64_t c, int64_t l, int64_t u) { - return l <= c && c <= u; -} - -inline bool aligned (size_t n, size_t alignment) { - CADICAL_assert (is_power_of_two (alignment)); - const size_t mask = alignment - 1; - return !(n & mask); -} - -inline size_t align (size_t n, size_t alignment) { - size_t res = n; - CADICAL_assert (is_power_of_two (alignment)); - const size_t mask = alignment - 1; - if (res & mask) - res = (res | mask) + 1; - CADICAL_assert (aligned (res, alignment)); - return res; -} - -/*------------------------------------------------------------------------*/ - -inline bool parity (unsigned a) { - CADICAL_assert (sizeof a == 4); - unsigned tmp = a; - tmp ^= (tmp >> 16); - tmp ^= (tmp >> 8); - tmp ^= (tmp >> 4); - tmp ^= (tmp >> 2); - tmp ^= (tmp >> 1); - return tmp & 1; -} - -/*------------------------------------------------------------------------*/ - -// The standard 'Effective STL' way (though not guaranteed) to clear a -// vector and reduce its capacity to zero, thus deallocating all its -// internal memory. This is quite important for keeping the actual -// allocated size of watched and occurrence lists small particularly during -// bounded variable elimination where many clauses are added and removed. - -template <class T> void erase_vector (std::vector<T> &v) { - if (v.capacity ()) { - std::vector<T> ().swap (v); - } - CADICAL_assert (!v.capacity ()); // not guaranteed though -} - -// The standard 'Effective STL' way (though not guaranteed) to shrink the -// capacity of a vector to its size thus kind of releasing all the internal -// excess memory not needed at the moment any more. - -template <class T> void shrink_vector (std::vector<T> &v) { - if (v.capacity () > v.size ()) { - std::vector<T> (v).swap (v); - } - CADICAL_assert (v.capacity () == v.size ()); // not guaranteed though -} - -template <class T> -static void enlarge_init (vector<T> &v, size_t N, const T &i) { - if (v.size () < N) - v.resize (N, i); -} - -template <class T> static void enlarge_only (vector<T> &v, size_t N) { - if (v.size () < N) - v.resize (N, T ()); -} - -template <class T> static void enlarge_zero (vector<T> &v, size_t N) { - enlarge_init (v, N, (const T &) 0); -} - -// Clean-up class for bad_alloc error safety. - -template <typename T> struct DeferDeleteArray { - T *data; - DeferDeleteArray (T *t) : data (t) {} - ~DeferDeleteArray () { delete[] data; } - void release () { data = nullptr; } - void free () { - delete[] data; - data = nullptr; - } -}; - -template <typename T> struct DeferDeletePtr { - T *data; - DeferDeletePtr (T *t) : data (t) {} - ~DeferDeletePtr () { delete data; } - void release () { data = nullptr; } - void free () { - delete data; - data = nullptr; - } -}; - -/*------------------------------------------------------------------------*/ - -template <class T> inline void clear_n (T *base, size_t n) { - memset (base, 0, sizeof (T) * n); -} - -/*------------------------------------------------------------------------*/ - -// These are options both to 'cadical' and 'mobical'. After wasting some -// on not remembering the spelling (British vs American), nor singular vs -// plural and then wanted to use '--color=false', and '--colours=0' too, I -// just factored this out into these two utility functions. - -bool is_color_option (const char *arg); // --color, --colour, ... -bool is_no_color_option (const char *arg); // --no-color, --no-colour, ... - -/*------------------------------------------------------------------------*/ - -uint64_t hash_string (const char *str); - -/*------------------------------------------------------------------------*/ - -} // namespace CaDiCaL - -ABC_NAMESPACE_CXX_HEADER_END - -#endif diff --git a/src/sat/cadical/var.hpp b/src/sat/cadical/var.hpp deleted file mode 100644 index 8793afbc4..000000000 --- a/src/sat/cadical/var.hpp +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef _var_hpp_INCLUDED -#define _var_hpp_INCLUDED - -#include "global.h" - -ABC_NAMESPACE_CXX_HEADER_START - -namespace CaDiCaL { - -struct Clause; - -// This structure captures data associated with an assigned variable. - -struct Var { - - // Note that none of these members is valid unless the variable is - // assigned. During unassigning a variable we do not reset it. - - int level; // decision level - int trail; // trail height at assignment - Clause *reason; // implication graph edge during search -}; - -} // namespace CaDiCaL - -ABC_NAMESPACE_CXX_HEADER_END - -#endif diff --git a/src/sat/cadical/veripbtracer.hpp b/src/sat/cadical/veripbtracer.hpp deleted file mode 100644 index b9c47362f..000000000 --- a/src/sat/cadical/veripbtracer.hpp +++ /dev/null @@ -1,108 +0,0 @@ -#ifndef _veripbtracer_h_INCLUDED -#define _veripbtracer_h_INCLUDED - -#include "global.h" - -ABC_NAMESPACE_CXX_HEADER_START - -class FileTracer; - -namespace CaDiCaL { - -struct HashId { - HashId *next; // collision chain link for hash table - uint64_t hash; // previously computed full 64-bit hash - int64_t id; // id of clause -}; - -class VeripbTracer : public FileTracer { - - Internal *internal; - File *file; -#ifndef CADICAL_NDEBUG - bool binary; -#endif - bool with_antecedents; - bool checked_deletions; - - // hash table for checked deletions - // - uint64_t num_clauses; // number of clauses in hash table - uint64_t size_clauses; // size of clause hash table - HashId **clauses; // hash table of clauses - - static const unsigned num_nonces = 4; - - uint64_t nonces[num_nonces]; // random numbers for hashing - uint64_t last_hash; // last computed hash value of clause - int64_t last_id; // id of the last added clause - HashId *last_clause; - uint64_t compute_hash (int64_t); // compute and save hash value of clause - - HashId *new_clause (); - void delete_clause (HashId *); - - // Reduce hash value to the actual size. - // - static uint64_t reduce_hash (uint64_t hash, uint64_t size); - - void enlarge_clauses (); // enlarge hash table for clauses - void insert (); // insert clause in hash table - bool - find_and_delete (const int64_t); // find clause position in hash table - -#ifndef CADICAL_QUIET - int64_t added, deleted; -#endif - vector<int64_t> delete_ids; - - void put_binary_zero (); - void put_binary_lit (int external_lit); - void put_binary_id (int64_t id, bool = false); - - // support veriPB - void veripb_add_derived_clause (int64_t, bool redundant, - const vector<int> &clause, - const vector<int64_t> &chain); - void veripb_add_derived_clause (int64_t, bool redundant, - const vector<int> &clause); - void veripb_begin_proof (int64_t reserved_ids); - void veripb_delete_clause (int64_t id, bool redundant); - void veripb_report_status (bool unsat, int64_t conflict_id); - void veripb_strengthen (int64_t); - -public: - // own and delete 'file' - VeripbTracer (Internal *, File *file, bool, bool, bool); - ~VeripbTracer (); - - void connect_internal (Internal *i) override; - void begin_proof (int64_t) override; - - void add_original_clause (int64_t, bool, const vector<int> &, - bool = false) override {} // skip - - void add_derived_clause (int64_t, bool, const vector<int> &, - const vector<int64_t> &) override; - - void delete_clause (int64_t, bool, const vector<int> &) override; - void finalize_clause (int64_t, const vector<int> &) override {} // skip - - void report_status (int, int64_t) override; - - void weaken_minus (int64_t, const vector<int> &) override; - void strengthen (int64_t) override; - -#ifndef CADICAL_QUIET - void print_statistics (); -#endif - bool closed () override; - void close (bool) override; - void flush (bool) override; -}; - -} // namespace CaDiCaL - -ABC_NAMESPACE_CXX_HEADER_END - -#endif diff --git a/src/sat/cadical/version.hpp b/src/sat/cadical/version.hpp deleted file mode 100644 index d63aefa35..000000000 --- a/src/sat/cadical/version.hpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "global.h" - -ABC_NAMESPACE_CXX_HEADER_START - -namespace CaDiCaL { - -const char *version (); -const char *copyright (); -const char *authors (); -const char *affiliations (); -const char *signature (); -const char *identifier (); -const char *compiler (); -const char *date (); -const char *flags (); - -} // namespace CaDiCaL - -ABC_NAMESPACE_CXX_HEADER_END diff --git a/src/sat/cadical/vivify.hpp b/src/sat/cadical/vivify.hpp deleted file mode 100644 index a5c6c0e10..000000000 --- a/src/sat/cadical/vivify.hpp +++ /dev/null @@ -1,68 +0,0 @@ -#ifndef _vivify_hpp_INCLUDED -#define _vivify_hpp_INCLUDED - -#include "global.h" - -#include "util.hpp" - -#include <array> -#include <cstdint> -#include <vector> - -ABC_NAMESPACE_CXX_HEADER_START - -namespace CaDiCaL { - -struct Clause; - -enum class Vivify_Mode { TIER1, TIER2, TIER3, IRREDUNDANT }; - -#define COUNTREF_COUNTS 2 - -struct vivify_ref { - bool vivify; - std::size_t size; - uint64_t count[COUNTREF_COUNTS]; - Clause *clause; -}; - -// In the vivifier structure, we put the schedules in an array in order to -// be able to iterate over them, but we provide the reference to them to -// make sure that you do need to remember the order. -struct Vivifier { - std::array<std::vector<vivify_ref>, 4> refs_schedules; - std::vector<vivify_ref> &refs_schedule_tier1, &refs_schedule_tier2, - &refs_schedule_tier3, &refs_schedule_irred; - std::array<std::vector<Clause *>, 4> schedules; - std::vector<Clause *> &schedule_tier1, &schedule_tier2, &schedule_tier3, - &schedule_irred; - std::vector<int> sorted; - Vivify_Mode tier; - char tag; - int tier1_limit; - int tier2_limit; - int64_t ticks; - std::vector<std::tuple<int, Clause *, bool>> lrat_stack; - Vivifier (Vivify_Mode mode_tier) - : refs_schedule_tier1 (refs_schedules[0]), - refs_schedule_tier2 (refs_schedules[1]), - refs_schedule_tier3 (refs_schedules[2]), - refs_schedule_irred (refs_schedules[3]), - schedule_tier1 (schedules[0]), schedule_tier2 (schedules[1]), - schedule_tier3 (schedules[2]), schedule_irred (schedules[3]), - tier (mode_tier) {} - - void erase () { - erase_vector (refs_schedule_tier1); - erase_vector (refs_schedule_tier2); - erase_vector (refs_schedule_tier3); - erase_vector (refs_schedule_irred); - erase_vector (sorted); - } -}; - -} // namespace CaDiCaL - -ABC_NAMESPACE_CXX_HEADER_END - -#endif diff --git a/src/sat/cadical/watch.hpp b/src/sat/cadical/watch.hpp deleted file mode 100644 index 1acab094b..000000000 --- a/src/sat/cadical/watch.hpp +++ /dev/null @@ -1,78 +0,0 @@ -#ifndef _watch_hpp_INCLUDED -#define _watch_hpp_INCLUDED - -#include "global.h" - -#include <cassert> -#include <vector> - -ABC_NAMESPACE_CXX_HEADER_START - -namespace CaDiCaL { - -// Watch lists for CDCL search. The blocking literal (see also comments -// related to 'propagate') is a must and thus combining that with a 64 bit -// pointer will give a 16 byte (8 byte aligned) structure anyhow, which -// means the additional 4 bytes for the size come for free. As alternative -// one could use a 32-bit reference instead of the pointer which would -// however limit the number of clauses to '2^32 - 1'. One would also need -// to use at least one more bit (either taken away from the variable space -// or the clauses) to denote whether the watch is binary. - -// in fashion of Intel Sat 10.4230/LIPIcs.SAT.2022.8 we try to -// guarantee the following invariant: -// For both watches: -// if the watched literal is negatively assigned -// either it will be propagated in the future -// or the corresponding blocking literal is positively assigned -// and its level is smaller than the level of the watched literal -// - -struct Clause; - -struct Watch { - - Clause *clause; - int blit; - int size; - - Watch (int b, Clause *c) : clause (c), blit (b), size (c->size) {} - Watch () {} - - bool binary () const { return size == 2; } -}; - -typedef vector<Watch> Watches; // of one literal - -typedef Watches::iterator watch_iterator; -typedef Watches::const_iterator const_watch_iterator; - -inline void remove_watch (Watches &ws, Clause *clause) { - const auto end = ws.end (); - auto i = ws.begin (); - for (auto j = i; j != end; j++) { - const Watch &w = *i++ = *j; - if (w.clause == clause) - i--; - } - CADICAL_assert (i + 1 == end); - ws.resize (i - ws.begin ()); -} - -// search for the clause and updates the size marked in the watch lists -inline void update_watch_size (Watches &ws, int blit, Clause *conflict) { - bool found = false; - const int size = conflict->size; - for (Watch &w : ws) { - if (w.clause == conflict) - w.size = size, w.blit = blit, found = true; - CADICAL_assert (w.clause->garbage || w.size == 2 || w.clause->size != 2); - } - CADICAL_assert (found), (void) found; -} - -} // namespace CaDiCaL - -ABC_NAMESPACE_CXX_HEADER_END - -#endif