LCOV - code coverage report
Current view: top level - buildbot/coverage/build/src/prop/cadical - cadical.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 151 178 84.8 %
Date: 2026-08-12 10:35:20 Functions: 32 39 82.1 %
Branches: 53 94 56.4 %

           Branch data     Line data    Source code
       1                 :            : /******************************************************************************
       2                 :            :  * This file is part of the cvc5 project.
       3                 :            :  *
       4                 :            :  * Copyright (c) 2009-2026 by the authors listed in the file AUTHORS
       5                 :            :  * in the top-level source directory and their institutional affiliations.
       6                 :            :  * All rights reserved.  See the file COPYING in the top-level source
       7                 :            :  * directory for licensing information.
       8                 :            :  * ****************************************************************************
       9                 :            :  *
      10                 :            :  * Wrapper for CaDiCaL SAT Solver.
      11                 :            :  *
      12                 :            :  * Implementation of the CaDiCaL SAT solver for cvc5 (bit-vectors).
      13                 :            :  */
      14                 :            : 
      15                 :            : #include "prop/cadical/cadical.h"
      16                 :            : 
      17                 :            : #include <cadical/cadical.hpp>
      18                 :            : #include <cstdint>
      19                 :            : #include <memory>
      20                 :            : 
      21                 :            : #include "base/check.h"
      22                 :            : #include "options/base_options.h"
      23                 :            : #include "options/main_options.h"
      24                 :            : #include "options/proof_options.h"
      25                 :            : #include "prop/cadical/cdclt_propagator.h"
      26                 :            : #include "prop/cadical/proof_tracer.h"
      27                 :            : #include "prop/cadical/util.h"
      28                 :            : #include "prop/sat_solver_types.h"
      29                 :            : #include "prop/theory_proxy.h"
      30                 :            : #include "theory/shared_terms_database.h"
      31                 :            : #include "util/resource_manager.h"
      32                 :            : #include "util/statistics_registry.h"
      33                 :            : #include "util/string.h"
      34                 :            : 
      35                 :            : namespace cvc5::internal::prop {
      36                 :            : using namespace cadical;
      37                 :            : 
      38                 :            : /* -------------------------------------------------------------------------- */
      39                 :            : 
      40                 :            : class ClauseLearner : public CaDiCaL::Learner
      41                 :            : {
      42                 :            :  public:
      43                 :          1 :   ClauseLearner(TheoryProxy& proxy, int32_t clause_size)
      44                 :          1 :       : d_proxy(proxy), d_max_clause_size(clause_size)
      45                 :            :   {
      46                 :          1 :   }
      47                 :          2 :   ~ClauseLearner() override {}
      48                 :            : 
      49                 :          1 :   bool learning(int size) override
      50                 :            :   {
      51 [ -  + ][ -  - ]:          1 :     return d_max_clause_size == 0 || size <= d_max_clause_size;
      52                 :            :   }
      53                 :            : 
      54                 :          2 :   void learn(int lit) override
      55                 :            :   {
      56         [ +  + ]:          2 :     if (lit)
      57                 :            :     {
      58                 :          1 :       SatLiteral slit = toSatLiteral(lit);
      59                 :          1 :       d_clause.push_back(slit);
      60                 :            :     }
      61                 :            :     else
      62                 :            :     {
      63                 :          1 :       d_proxy.notifySatClause(d_clause);
      64                 :          1 :       d_clause.clear();
      65                 :            :     }
      66                 :          2 :   }
      67                 :            : 
      68                 :            :  private:
      69                 :            :   TheoryProxy& d_proxy;
      70                 :            :   /** Intermediate literals buffer. */
      71                 :            :   std::vector<SatLiteral> d_clause;
      72                 :            :   /** Maximum size of clauses to get notified about. */
      73                 :            :   int32_t d_max_clause_size;
      74                 :            : };
      75                 :            : 
      76                 :      20009 : CadicalSolver::CadicalSolver(Env& env,
      77                 :            :                              StatisticsRegistry& registry,
      78                 :      20009 :                              const std::string& name)
      79                 :            :     : EnvObj(env),
      80                 :      20009 :       d_solver(new CaDiCaL::Solver()),
      81                 :      20009 :       d_context(context()),
      82                 :            :       // Note: CaDiCaL variables start with index 1 rather than 0 since negated
      83                 :            :       //       literals are represented as the negation of the index.
      84                 :      20009 :       d_nextVarIdx(1),
      85                 :      20009 :       d_inSatMode(false),
      86                 :      60027 :       d_statistics(registry, name)
      87                 :            : {
      88                 :      20009 : }
      89                 :            : 
      90                 :      20009 : void CadicalSolver::initialize()
      91                 :            : {
      92                 :      20009 :   d_solver->set("quiet", 1);  // CaDiCaL is verbose by default
      93                 :            : 
      94                 :            :   // walk and lucky phase do not use the external propagator, disable for now
      95         [ +  + ]:      20009 :   if (d_propagator)
      96                 :            :   {
      97                 :         72 :     d_solver->set("walk", 0);
      98                 :         72 :     d_solver->set("lucky", 0);
      99                 :            :     // ilb currently does not play well with user propagators
     100                 :         72 :     d_solver->set("ilb", 0);
     101                 :         72 :     d_solver->set("ilbassumptions", 0);
     102         [ +  - ]:         72 :     d_solver->connect_fixed_listener(d_propagator.get());
     103                 :         72 :     d_solver->connect_external_propagator(d_propagator.get());
     104                 :            :   }
     105                 :            : 
     106                 :      20009 :   d_true = newVar(false, true);
     107                 :      20009 :   d_false = newVar(false, true);
     108                 :      20009 :   d_solver->clause(toCadicalVar(d_true));
     109                 :      20009 :   d_solver->clause(-toCadicalVar(d_false));
     110                 :      20009 : }
     111                 :            : 
     112                 :      39992 : CadicalSolver::~CadicalSolver()
     113                 :            : {
     114         [ +  + ]:      19996 :   if (d_proof_tracer != nullptr)
     115                 :            :   {
     116                 :         20 :     d_solver->disconnect_proof_tracer(d_proof_tracer.get());
     117                 :            :   }
     118                 :      39992 : }
     119                 :            : 
     120                 :            : /**
     121                 :            :  * Terminator class that notifies CaDiCaL to terminate when the resource limit
     122                 :            :  * is reached (used for resource limits specified via --rlimit or --tlimit).
     123                 :            :  */
     124                 :            : class ResourceLimitTerminator : public CaDiCaL::Terminator
     125                 :            : {
     126                 :            :  public:
     127                 :      20009 :   ResourceLimitTerminator(ResourceManager& resmgr) : d_resmgr(resmgr) {}
     128                 :            : 
     129                 :     788766 :   bool terminate() override
     130                 :            :   {
     131                 :     788766 :     d_resmgr.spendResource(Resource::BvSatStep);
     132                 :     788766 :     return d_resmgr.out();
     133                 :            :   }
     134                 :            : 
     135                 :            :  private:
     136                 :            :   ResourceManager& d_resmgr;
     137                 :            : };
     138                 :            : 
     139                 :      20009 : void CadicalSolver::setResourceLimit(ResourceManager* resmgr)
     140                 :            : {
     141                 :      20009 :   d_terminator.reset(new ResourceLimitTerminator(*resmgr));
     142                 :      20009 :   d_solver->connect_terminator(d_terminator.get());
     143                 :      20009 : }
     144                 :            : 
     145                 :      61302 : SatValue CadicalSolver::_solve(const std::vector<SatLiteral>& assumptions)
     146                 :            : {
     147         [ +  + ]:      61302 :   if (d_propagator)
     148                 :            :   {
     149         [ +  - ]:        101 :     Trace("cadical::propagator") << "solve start" << std::endl;
     150                 :        101 :     d_propagator->renotify_fixed();
     151                 :            :   }
     152                 :      61302 :   TimerStat::CodeTimer codeTimer(d_statistics.d_solveTime);
     153                 :      61302 :   d_assumptions.clear();
     154         [ +  + ]:      61302 :   if (d_propagator)
     155                 :            :   {
     156                 :            :     // Assume activation literals for all active user levels.
     157         [ +  + ]:        133 :     for (const auto& lit : d_propagator->activation_literals())
     158                 :            :     {
     159         [ +  - ]:         64 :       Trace("cadical::propagator")
     160                 :         32 :           << "assume activation lit: " << ~lit << std::endl;
     161                 :         32 :       d_solver->assume(toCadicalLit(~lit));
     162                 :            :     }
     163                 :            :   }
     164                 :            :   SatValue res;
     165         [ +  + ]:    7877881 :   for (const SatLiteral& lit : assumptions)
     166                 :            :   {
     167         [ +  + ]:    7816579 :     if (d_propagator)
     168                 :            :     {
     169         [ +  - ]:        246 :       Trace("cadical::propagator") << "assume: " << lit << std::endl;
     170                 :            :     }
     171                 :    7816579 :     d_solver->assume(toCadicalLit(lit));
     172                 :    7816579 :     d_assumptions.push_back(lit);
     173                 :            :   }
     174         [ +  + ]:      61302 :   if (d_propagator)
     175                 :            :   {
     176                 :        101 :     d_propagator->in_search(true);
     177                 :            :   }
     178                 :      61302 :   res = toSatValue(d_solver->solve());
     179         [ +  + ]:      61302 :   if (d_propagator)
     180                 :            :   {
     181 [ +  + ][ +  - ]:        101 :     Assert(res != SAT_VALUE_TRUE || d_propagator->done());
         [ -  + ][ -  + ]
                 [ -  - ]
     182         [ +  - ]:        101 :     Trace("cadical::propagator") << "solve done: " << res << std::endl;
     183                 :        101 :     d_propagator->in_search(false);
     184                 :            :   }
     185                 :      61302 :   ++d_statistics.d_numSatCalls;
     186                 :      61302 :   d_inSatMode = (res == SAT_VALUE_TRUE);
     187                 :      61302 :   return res;
     188                 :      61302 : }
     189                 :            : 
     190                 :            : /* SatSolver Interface ------------------------------------------------------ */
     191                 :            : 
     192                 :   10560029 : ClauseId CadicalSolver::addClause(const SatClause& clause, bool removable)
     193                 :            : {
     194                 :   10560029 :   if (d_propagator && TraceIsOn("cadical::propagator"))
     195                 :            :   {
     196         [ -  - ]:          0 :     Trace("cadical::propagator") << "addClause (" << removable << "):";
     197                 :          0 :     SatLiteral alit = d_propagator->current_activation_lit();
     198         [ -  - ]:          0 :     if (alit != undefSatLiteral)
     199                 :            :     {
     200         [ -  - ]:          0 :       Trace("cadical::propagator") << " " << alit;
     201                 :            :     }
     202         [ -  - ]:          0 :     for (const SatLiteral& lit : clause)
     203                 :            :     {
     204         [ -  - ]:          0 :       Trace("cadical::propagator") << " " << lit;
     205                 :            :     }
     206         [ -  - ]:          0 :     Trace("cadical::propagator") << " 0" << std::endl;
     207                 :            :   }
     208         [ +  + ]:   10560029 :   if (d_propagator)
     209                 :            :   {
     210                 :       2590 :     d_propagator->add_clause(clause);
     211                 :            :   }
     212                 :            :   else
     213                 :            :   {
     214         [ +  + ]:   39651426 :     for (const SatLiteral& lit : clause)
     215                 :            :     {
     216                 :   29093987 :       d_solver->add(toCadicalLit(lit));
     217                 :            :     }
     218                 :   10557439 :     d_solver->add(0);
     219                 :            :   }
     220                 :   10560029 :   ++d_statistics.d_numClauses;
     221                 :   10560029 :   return ClauseIdError;
     222                 :            : }
     223                 :            : 
     224                 :    2364142 : SatVariable CadicalSolver::newVar(bool isTheoryAtom, CVC5_UNUSED bool canErase)
     225                 :            : {
     226                 :    2364142 :   ++d_statistics.d_numVariables;
     227         [ +  + ]:    2364142 :   if (d_propagator)
     228                 :            :   {
     229                 :       2067 :     d_propagator->add_new_var(d_nextVarIdx, isTheoryAtom);
     230                 :            :   }
     231                 :    2364142 :   return d_nextVarIdx++;
     232                 :            : }
     233                 :            : 
     234                 :        177 : SatVariable CadicalSolver::trueVar() { return d_true; }
     235                 :            : 
     236                 :        262 : SatVariable CadicalSolver::falseVar() { return d_false; }
     237                 :            : 
     238                 :         66 : SatValue CadicalSolver::solve() { return _solve({}); }
     239                 :            : 
     240                 :          0 : SatValue CadicalSolver::solve(long unsigned int&)
     241                 :            : {
     242                 :          0 :   Unimplemented() << "Setting limits for CaDiCaL not supported yet";
     243                 :            :   return SatValue::SAT_VALUE_UNKNOWN;
     244                 :            : };
     245                 :            : 
     246                 :      61236 : SatValue CadicalSolver::solve(const std::vector<SatLiteral>& assumptions)
     247                 :            : {
     248                 :      61236 :   return _solve(assumptions);
     249                 :            : }
     250                 :            : 
     251                 :          0 : bool CadicalSolver::setPropagateOnly()
     252                 :            : {
     253                 :          0 :   d_solver->limit("decisions", 0); /* Gets reset after next solve() call. */
     254                 :          0 :   return true;
     255                 :            : }
     256                 :            : 
     257                 :      19753 : void CadicalSolver::getUnsatAssumptions(std::vector<SatLiteral>& assumptions)
     258                 :            : {
     259         [ +  + ]:    7639090 :   for (const SatLiteral& lit : d_assumptions)
     260                 :            :   {
     261         [ +  + ]:    7619337 :     if (d_solver->failed(toCadicalLit(lit)))
     262                 :            :     {
     263                 :     151633 :       assumptions.push_back(lit);
     264                 :            :     }
     265                 :            :   }
     266                 :      19753 : }
     267                 :            : 
     268                 :          0 : void CadicalSolver::interrupt() { d_solver->terminate(); }
     269                 :            : 
     270                 :     130309 : SatValue CadicalSolver::value(SatLiteral l) { return d_propagator->value(l); }
     271                 :            : 
     272                 :     213427 : SatValue CadicalSolver::modelValue(SatLiteral l)
     273                 :            : {
     274 [ -  + ][ -  + ]:     213427 :   Assert(d_inSatMode);
                 [ -  - ]
     275                 :     213427 :   auto val = d_solver->val(toCadicalVar(l.getSatVariable()));
     276         [ +  + ]:     213427 :   return toSatValueLit(l.isNegated() ? -val : val);
     277                 :            : }
     278                 :            : 
     279                 :          0 : bool CadicalSolver::ok() const { return d_inSatMode; }
     280                 :            : 
     281                 :      20009 : CadicalSolver::Statistics::Statistics(StatisticsRegistry& registry,
     282                 :      20009 :                                       const std::string& prefix)
     283                 :      20009 :     : d_numSatCalls(registry.registerInt(prefix + "cadical::calls_to_solve")),
     284                 :      20009 :       d_numVariables(registry.registerInt(prefix + "cadical::variables")),
     285                 :      20009 :       d_numClauses(registry.registerInt(prefix + "cadical::clauses")),
     286                 :      20009 :       d_solveTime(registry.registerTimer(prefix + "cadical::solve_time"))
     287                 :            : {
     288                 :      20009 : }
     289                 :            : 
     290                 :            : /* CDCLTSatSolver Interface ------------------------------------------------- */
     291                 :            : 
     292                 :         72 : void CadicalSolver::initialize(TheoryProxy* theoryProxy)
     293                 :            : {
     294                 :         72 :   d_proxy = theoryProxy;
     295                 :         72 :   d_propagator.reset(new CadicalPropagator(
     296                 :         72 :       theoryProxy, d_context, *d_solver, statisticsRegistry()));
     297         [ +  + ]:         72 :   if (!d_env.getPlugins().empty())
     298                 :            :   {
     299                 :          1 :     d_clause_learner.reset(new ClauseLearner(*theoryProxy, 0));
     300                 :          1 :     d_solver->connect_learner(d_clause_learner.get());
     301                 :            :   }
     302                 :            : 
     303         [ +  + ]:         72 :   if (d_env.isSatProofProducing())
     304                 :            :   {
     305                 :         20 :     d_proof_tracer.reset(new ProofTracer(*d_propagator));
     306                 :         20 :     d_solver->connect_proof_tracer(d_proof_tracer.get(), true);
     307                 :            :   }
     308                 :            : 
     309                 :         72 :   initialize();
     310                 :         72 : }
     311                 :            : 
     312                 :         46 : void CadicalSolver::attachProofManager(CVC5_UNUSED PropPfManager* ppm)
     313                 :            : {
     314                 :            :   // not implemented yet
     315                 :         46 : }
     316                 :            : 
     317                 :         32 : void CadicalSolver::push()
     318                 :            : {
     319                 :         32 :   d_context->push();  // SAT context for cvc5
     320                 :            :   // Push new user level
     321                 :         32 :   d_propagator->user_push();
     322                 :            :   // Set new activation literal for pushed user level
     323                 :            :   // Note: This happens after the push to ensure that the activation literal's
     324                 :            :   // introduction level is the current user level.
     325                 :         32 :   SatVariable alit = newVar(false, true);
     326                 :         32 :   d_propagator->set_activation_lit(alit);
     327                 :         32 : }
     328                 :            : 
     329                 :         72 : uint32_t CadicalSolver::getAssertionLevel() const
     330                 :            : {
     331 [ -  + ][ -  + ]:         72 :   Assert(d_propagator);
                 [ -  - ]
     332                 :         72 :   return d_propagator->current_user_level();
     333                 :            : }
     334                 :            : 
     335                 :         32 : void CadicalSolver::pop()
     336                 :            : {
     337                 :         32 :   d_context->pop();  // SAT context for cvc5
     338                 :         32 :   d_propagator->user_pop();
     339                 :            :   // CaDiCaL issues notify_backtrack(0) when done, we don't have to call this
     340                 :            :   // explicitly here
     341                 :         32 : }
     342                 :            : 
     343                 :        101 : void CadicalSolver::resetTrail()
     344                 :            : {
     345                 :            :   // Reset SAT context to decision level 0
     346                 :        101 :   d_propagator->notify_backtrack(0);
     347                 :        101 : }
     348                 :            : 
     349                 :         61 : void CadicalSolver::preferPhase(SatLiteral lit)
     350                 :            : {
     351         [ +  - ]:         61 :   Trace("cadical::propagator") << "phase: " << lit << std::endl;
     352                 :         61 :   d_propagator->phase(lit);
     353                 :         61 : }
     354                 :            : 
     355                 :          5 : bool CadicalSolver::isDecision(SatVariable var) const
     356                 :            : {
     357                 :          5 :   return d_solver->is_decision(toCadicalVar(var));
     358                 :            : }
     359                 :            : 
     360                 :          0 : bool CadicalSolver::isFixed(SatVariable var) const
     361                 :            : {
     362         [ -  - ]:          0 :   if (d_propagator)
     363                 :            :   {
     364                 :          0 :     return d_propagator->is_fixed(var);
     365                 :            :   }
     366                 :          0 :   return d_solver->fixed(toCadicalVar(var));
     367                 :            : }
     368                 :            : 
     369                 :          0 : std::vector<SatLiteral> CadicalSolver::getDecisions() const
     370                 :            : {
     371                 :          0 :   std::vector<SatLiteral> decisions;
     372         [ -  - ]:          0 :   for (SatLiteral lit : d_propagator->get_decisions())
     373                 :            :   {
     374         [ -  - ]:          0 :     if (lit != undefSatLiteral)
     375                 :            :     {
     376                 :          0 :       decisions.push_back(lit);
     377                 :            :     }
     378                 :            :   }
     379                 :          0 :   return decisions;
     380                 :          0 : }
     381                 :            : 
     382                 :          0 : std::vector<Node> CadicalSolver::getOrderHeap() const { return {}; }
     383                 :            : 
     384                 :         20 : std::shared_ptr<ProofNode> CadicalSolver::getProof()
     385                 :            : {
     386         [ +  - ]:         20 :   if (d_proof_tracer)
     387                 :            :   {
     388                 :         20 :     ProofNodeManager* pnm = d_env.getProofNodeManager();
     389                 :         20 :     NodeManager* nm = d_env.getNodeManager();
     390                 :         20 :     return d_proof_tracer->get_chain_resolution_proof(pnm, nm, d_proxy);
     391                 :            :   }
     392                 :          0 :   return nullptr;
     393                 :            : }
     394                 :            : 
     395                 :            : /* -------------------------------------------------------------------------- */
     396                 :            : }  // namespace cvc5::internal::prop

Generated by: LCOV version 1.14