LCOV - code coverage report
Current view: top level - buildbot/coverage/build/src/prop - prop_engine.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 335 434 77.2 %
Date: 2026-08-12 10:35:20 Functions: 43 49 87.8 %
Branches: 191 340 56.2 %

           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                 :            :  * Implementation of the propositional engine of cvc5.
      11                 :            :  */
      12                 :            : 
      13                 :            : #include "prop/prop_engine.h"
      14                 :            : 
      15                 :            : #include <utility>
      16                 :            : 
      17                 :            : #include "base/check.h"
      18                 :            : #include "base/output.h"
      19                 :            : #include "expr/skolem_manager.h"
      20                 :            : #include "options/base_options.h"
      21                 :            : #include "options/decision_options.h"
      22                 :            : #include "options/main_options.h"
      23                 :            : #include "options/options.h"
      24                 :            : #include "options/proof_options.h"
      25                 :            : #include "options/prop_options.h"
      26                 :            : #include "options/smt_options.h"
      27                 :            : #include "proof/proof_node_algorithm.h"
      28                 :            : #include "prop/cnf_stream.h"
      29                 :            : #include "prop/proof_cnf_stream.h"
      30                 :            : #include "prop/prop_proof_manager.h"
      31                 :            : #include "prop/sat_solver.h"
      32                 :            : #include "prop/sat_solver_factory.h"
      33                 :            : #include "prop/theory_proxy.h"
      34                 :            : #include "smt/env.h"
      35                 :            : #include "theory/output_channel.h"
      36                 :            : #include "theory/theory_engine.h"
      37                 :            : #include "util/resource_manager.h"
      38                 :            : #include "util/result.h"
      39                 :            : 
      40                 :            : namespace cvc5::internal {
      41                 :            : namespace prop {
      42                 :            : 
      43                 :            : /** Keeps a boolean flag scoped */
      44                 :            : class ScopedBool
      45                 :            : {
      46                 :            :  private:
      47                 :            :   bool d_original;
      48                 :            :   bool& d_reference;
      49                 :            : 
      50                 :            :  public:
      51                 :      32412 :   ScopedBool(bool& reference) : d_reference(reference)
      52                 :            :   {
      53                 :      32412 :     d_original = reference;
      54                 :      32412 :   }
      55                 :            : 
      56                 :      32412 :   ~ScopedBool() { d_reference = d_original; }
      57                 :            : };
      58                 :            : 
      59                 :      28722 : PropEngine::PropEngine(Env& env, TheoryEngine* te)
      60                 :            :     : EnvObj(env),
      61                 :      28722 :       d_inCheckSat(false),
      62                 :      28722 :       d_theoryEngine(te),
      63                 :      28722 :       d_skdm(new SkolemDefManager(d_env.getContext(), d_env.getUserContext())),
      64                 :      28722 :       d_theoryProxy(nullptr),
      65                 :      28722 :       d_satSolver(nullptr),
      66                 :      28722 :       d_cnfStream(nullptr),
      67                 :      28722 :       d_theoryLemmaPg(d_env, d_env.getUserContext(), "PropEngine::ThLemmaPg"),
      68                 :      28722 :       d_ppm(nullptr),
      69                 :      28722 :       d_interrupted(false),
      70                 :      28722 :       d_assumptions(userContext()),
      71                 :      28722 :       d_localLemmas(userContext()),
      72                 :      86166 :       d_stats(statisticsRegistry())
      73                 :            : {
      74         [ +  - ]:      28722 :   Trace("prop") << "Constructing the PropEngine" << std::endl;
      75                 :      28722 :   context::UserContext* userContext = d_env.getUserContext();
      76                 :            : 
      77                 :            :   // CNF stream, SAT solver and theory proxy required pointers to each other,
      78                 :            :   // make the theory proxy first
      79                 :      28722 :   d_theoryProxy = new TheoryProxy(d_env, this, d_theoryEngine, d_skdm.get());
      80                 :            : 
      81                 :      28722 :   const auto factory = SatSolverFactory::getFactory(options().prop.satSolver);
      82                 :      28722 :   d_satSolver = factory(
      83                 :            :       env, statisticsRegistry(), env.getResourceManager(), d_theoryProxy, "");
      84                 :            : 
      85                 :            :   // create CnfStream with new SAT solver
      86                 :      57444 :   d_cnfStream = new CnfStream(env,
      87                 :      28722 :                               d_satSolver,
      88                 :      57444 :                               d_theoryProxy,
      89                 :            :                               userContext,
      90                 :            :                               FormulaLitPolicy::TRACK,
      91         [ +  - ]:      28722 :                               "prop");
      92                 :            : 
      93                 :            :   // connect theory proxy
      94                 :      28722 :   d_theoryProxy->finishInit(d_satSolver, d_cnfStream);
      95                 :            :   // if proof producing at all
      96         [ +  + ]:      28722 :   if (options().smt.produceProofs)
      97                 :            :   {
      98                 :            :     PropPfManager* ppm =
      99                 :      15194 :         new PropPfManager(env, d_satSolver, *d_cnfStream, d_assumptions);
     100                 :      15194 :     d_ppm.reset(ppm);
     101                 :      15194 :     d_satSolver->attachProofManager(ppm);
     102                 :            :   }
     103                 :      28722 : }
     104                 :            : 
     105                 :      28722 : void PropEngine::finishInit()
     106                 :            : {
     107                 :            :   // Make sure that true/false are not free assumptions in the proof.
     108         [ +  + ]:      28722 :   if (d_ppm)
     109                 :            :   {
     110                 :      15194 :     NodeManager* nm = nodeManager();
     111                 :      30388 :     d_ppm->convertAndAssert(theory::InferenceId::INPUT,
     112                 :      30388 :                             nm->mkConst(true),
     113                 :            :                             false,
     114                 :            :                             false,
     115                 :            :                             true,
     116                 :            :                             nullptr);
     117                 :      30388 :     d_ppm->convertAndAssert(theory::InferenceId::INPUT,
     118                 :      30388 :                             nm->mkConst(false).notNode(),
     119                 :            :                             false,
     120                 :            :                             false,
     121                 :            :                             true,
     122                 :            :                             nullptr);
     123                 :            :   }
     124                 :      28722 : }
     125                 :            : 
     126                 :      57418 : PropEngine::~PropEngine()
     127                 :            : {
     128         [ +  - ]:      28709 :   Trace("prop") << "Destructing the PropEngine" << std::endl;
     129         [ +  - ]:      28709 :   delete d_cnfStream;
     130         [ +  - ]:      28709 :   delete d_satSolver;
     131         [ +  - ]:      28709 :   delete d_theoryProxy;
     132                 :      57418 : }
     133                 :            : 
     134                 :     434801 : TrustNode PropEngine::preprocess(TNode node,
     135                 :            :                                  std::vector<theory::SkolemLemma>& newLemmas)
     136                 :            : {
     137                 :     434801 :   return d_theoryProxy->preprocess(node, newLemmas);
     138                 :            : }
     139                 :            : 
     140                 :       1342 : TrustNode PropEngine::removeItes(TNode node,
     141                 :            :                                  std::vector<theory::SkolemLemma>& newLemmas)
     142                 :            : {
     143                 :       1342 :   return d_theoryProxy->removeItes(node, newLemmas);
     144                 :            : }
     145                 :            : 
     146                 :      52594 : void PropEngine::notifyTopLevelSubstitution(const Node& lhs,
     147                 :            :                                             const Node& rhs) const
     148                 :            : {
     149                 :      52594 :   d_theoryProxy->notifyTopLevelSubstitution(lhs, rhs);
     150         [ +  + ]:      52594 :   if (isOutputOn(OutputTag::SUBS))
     151                 :            :   {
     152                 :          2 :     Node eq = SkolemManager::getOriginalForm(lhs.eqNode(rhs));
     153                 :          2 :     output(OutputTag::SUBS) << "(substitution " << eq << ")" << std::endl;
     154                 :          2 :   }
     155 [ -  + ][ -  + ]:     157782 :   AssertEqual(lhs.getType(), rhs.getType());
                 [ -  - ]
     156                 :      52594 : }
     157                 :            : 
     158                 :      40622 : void PropEngine::assertInputFormulas(
     159                 :            :     const std::vector<Node>& assertions,
     160                 :            :     std::unordered_map<size_t, Node>& skolemMap)
     161                 :            : {
     162 [ -  + ][ -  + ]:      40622 :   Assert(!d_inCheckSat) << "Sat solver in solve()!";
                 [ -  - ]
     163                 :            :   // now presolve with prop proof manager so proof logging is on. This must be
     164                 :            :   // done *before* the PropEngine checkSat call because when asserting formulas
     165                 :            :   // to the theory engine lemmas may already be generated.
     166         [ +  + ]:      40622 :   if (d_ppm != nullptr)
     167                 :            :   {
     168                 :      21208 :     d_ppm->presolve();
     169                 :            :   }
     170                 :      40622 :   d_theoryProxy->notifyInputFormulas(assertions, skolemMap);
     171                 :      40622 :   int64_t natomsPre = d_cnfStream->d_stats.d_numAtoms.get();
     172         [ +  + ]:     510164 :   for (const Node& node : assertions)
     173                 :            :   {
     174         [ +  - ]:     469558 :     Trace("prop") << "assertFormula(" << node << ")" << std::endl;
     175                 :     469574 :     assertInternal(theory::InferenceId::INPUT, node, false, false, true);
     176                 :            :   }
     177                 :      40606 :   int64_t natomsPost = d_cnfStream->d_stats.d_numAtoms.get();
     178 [ -  + ][ -  + ]:      40606 :   Assert(natomsPost >= natomsPre);
                 [ -  - ]
     179                 :      40606 :   d_stats.d_numInputAtoms += (natomsPost - natomsPre);
     180                 :      40606 : }
     181                 :            : 
     182                 :     886235 : void PropEngine::assertLemma(theory::InferenceId id,
     183                 :            :                              TrustNode tlemma,
     184                 :            :                              theory::LemmaProperty p)
     185                 :            : {
     186                 :     886235 :   bool removable = isLemmaPropertyRemovable(p);
     187                 :     886235 :   bool local = isLemmaPropertyLocal(p);
     188                 :     886235 :   bool inprocess = isLemmaPropertyInprocess(p);
     189                 :            : 
     190                 :            :   // call preprocessor
     191                 :     886235 :   std::vector<theory::SkolemLemma> ppLemmas;
     192                 :     886236 :   TrustNode tplemma = d_theoryProxy->preprocessLemma(tlemma, ppLemmas);
     193                 :            : 
     194                 :            :   // do final checks on the lemmas we are about to send
     195                 :     886234 :   if (d_env.isTheoryProofProducing()
     196 [ +  + ][ +  + ]:     886234 :       && options().proof.proofCheck == options::ProofCheckMode::EAGER)
                 [ +  + ]
     197                 :            :   {
     198 [ -  + ][ -  + ]:       4771 :     Assert(tplemma.getGenerator() != nullptr);
                 [ -  - ]
     199                 :            :     // ensure closed, make the proof node eagerly here to debug
     200                 :       4771 :     tplemma.debugCheckClosed(
     201                 :            :         options(), "te-proof-debug", "TheoryEngine::lemma");
     202         [ +  + ]:       4781 :     for (theory::SkolemLemma& lem : ppLemmas)
     203                 :            :     {
     204 [ -  + ][ -  + ]:         10 :       Assert(lem.d_lemma.getGenerator() != nullptr);
                 [ -  - ]
     205                 :         10 :       lem.d_lemma.debugCheckClosed(
     206                 :            :           options(), "te-proof-debug", "TheoryEngine::lemma_new");
     207                 :            :     }
     208                 :            :   }
     209                 :            : 
     210         [ -  + ]:     886234 :   if (TraceIsOn("te-lemma"))
     211                 :            :   {
     212                 :          0 :     Trace("te-lemma") << "Lemma, output: " << tplemma.getProven() << std::endl;
     213         [ -  - ]:          0 :     for (const theory::SkolemLemma& lem : ppLemmas)
     214                 :            :     {
     215                 :          0 :       Trace("te-lemma") << "Lemma, new lemma: " << lem.d_lemma.getProven()
     216                 :          0 :                         << " (skolem is " << lem.d_skolem << ")" << std::endl;
     217                 :            :     }
     218         [ -  - ]:          0 :     Trace("te-lemma") << "removable = " << removable << std::endl;
     219                 :            :   }
     220                 :            : 
     221                 :            :   // now, assert the lemmas
     222                 :     886234 :   assertLemmasInternal(id, tplemma, ppLemmas, removable, inprocess, local);
     223                 :     886235 : }
     224                 :            : 
     225                 :     921799 : void PropEngine::assertTrustedLemmaInternal(theory::InferenceId id,
     226                 :            :                                             TrustNode trn,
     227                 :            :                                             bool removable,
     228                 :            :                                             bool local)
     229                 :            : {
     230                 :     921799 :   Node node = trn.getNode();
     231         [ -  + ]:     921799 :   if (local)
     232                 :            :   {
     233                 :            :     // if local, filter here
     234         [ -  - ]:          0 :     if (d_localLemmas.find(node) != d_localLemmas.end())
     235                 :            :     {
     236                 :          0 :       return;
     237                 :            :     }
     238                 :          0 :     d_localLemmas.insert(node);
     239                 :            :   }
     240         [ +  - ]:     921799 :   Trace("prop::lemmas") << "assertLemma(" << node << ")" << std::endl;
     241         [ +  + ]:     921799 :   if (isOutputOn(OutputTag::LEMMAS))
     242                 :            :   {
     243                 :          1 :     output(OutputTag::LEMMAS) << "(lemma ";
     244                 :            :     // use original form of the lemma here
     245                 :          1 :     output(OutputTag::LEMMAS) << SkolemManager::getOriginalForm(node);
     246                 :          1 :     output(OutputTag::LEMMAS) << " :source " << id;
     247                 :          1 :     output(OutputTag::LEMMAS) << ")" << std::endl;
     248                 :            :   }
     249                 :     921799 :   bool negated = trn.getKind() == TrustNodeKind::CONFLICT;
     250                 :            :   // should have a proof generator if the theory engine is proof producing
     251 [ +  + ][ +  - ]:     921799 :   Assert(!d_env.isTheoryProofProducing() || trn.getGenerator() != nullptr);
         [ -  + ][ -  + ]
                 [ -  - ]
     252                 :            :   // if we are producing proofs for the SAT solver but not for theory engine,
     253                 :            :   // then we need to prevent the lemma of being added as an assumption (since
     254                 :            :   // the generator will be null). We use the default proof generator for lemmas.
     255         [ +  + ]:    1331354 :   if (d_env.isSatProofProducing() && !d_env.isTheoryProofProducing()
     256 [ +  + ][ +  + ]:    1331354 :       && !trn.getGenerator())
                 [ +  + ]
     257                 :            :   {
     258         [ +  + ]:         90 :     Node actualNode = negated ? node.notNode() : node;
     259                 :         90 :     d_theoryLemmaPg.addTrustedStep(actualNode, TrustId::THEORY_LEMMA, {}, {});
     260                 :         90 :     trn = TrustNode::mkReplaceGenTrustNode(trn, &d_theoryLemmaPg);
     261                 :         90 :   }
     262                 :     921799 :   assertInternal(id, node, negated, removable, false, trn.getGenerator());
     263         [ +  - ]:     921799 : }
     264                 :            : 
     265                 :    1391357 : void PropEngine::assertInternal(theory::InferenceId id,
     266                 :            :                                 TNode node,
     267                 :            :                                 bool negated,
     268                 :            :                                 bool removable,
     269                 :            :                                 bool input,
     270                 :            :                                 ProofGenerator* pg)
     271                 :            : {
     272                 :    1391357 :   bool addAssumption = false;
     273         [ +  + ]:    1391357 :   if (isProofEnabled())
     274                 :            :   {
     275                 :     839243 :     if (input
     276 [ +  + ][ +  + ]:     839243 :         && options().smt.unsatCoresMode == options::UnsatCoresMode::ASSUMPTIONS)
                 [ +  + ]
     277                 :            :     {
     278                 :            :       // use the proof CNF stream to ensure the literal
     279                 :     115068 :       d_ppm->ensureLiteral(node);
     280                 :     115068 :       addAssumption = true;
     281                 :            :     }
     282                 :            :     else
     283                 :            :     {
     284                 :     724175 :       d_ppm->convertAndAssert(id, node, negated, removable, input, pg);
     285                 :            :     }
     286                 :            :   }
     287                 :     552114 :   else if (input
     288 [ +  + ][ -  + ]:     552114 :            && options().smt.unsatCoresMode
                 [ -  + ]
     289                 :            :                   == options::UnsatCoresMode::ASSUMPTIONS)
     290                 :            :   {
     291                 :          0 :     d_cnfStream->ensureLiteral(node);
     292                 :          0 :     addAssumption = true;
     293                 :            :   }
     294                 :            :   else
     295                 :            :   {
     296                 :     552130 :     d_cnfStream->convertAndAssert(node, removable, negated);
     297                 :            :   }
     298         [ +  + ]:    1391341 :   if (addAssumption)
     299                 :            :   {
     300         [ -  + ]:     115068 :     if (negated)
     301                 :            :     {
     302                 :          0 :       d_assumptions.push_back(node.notNode());
     303                 :            :     }
     304                 :            :     else
     305                 :            :     {
     306                 :     115068 :       d_assumptions.push_back(node);
     307                 :            :     }
     308                 :            :   }
     309                 :    1391341 : }
     310                 :            : 
     311                 :    1317938 : void PropEngine::assertLemmasInternal(
     312                 :            :     theory::InferenceId id,
     313                 :            :     TrustNode trn,
     314                 :            :     const std::vector<theory::SkolemLemma>& ppLemmas,
     315                 :            :     bool removable,
     316                 :            :     bool inprocess,
     317                 :            :     bool local)
     318                 :            : {
     319                 :            :   // notify skolem definitions first to ensure that the computation of
     320                 :            :   // when a literal contains a skolem is accurate in the calls below.
     321         [ +  - ]:    1317938 :   Trace("prop") << "Notify skolem definitions..." << std::endl;
     322         [ +  + ]:    1353503 :   for (const theory::SkolemLemma& lem : ppLemmas)
     323                 :            :   {
     324                 :      35565 :     d_theoryProxy->notifySkolemDefinition(lem.getProven(), lem.d_skolem);
     325                 :            :   }
     326                 :            :   // Assert to the SAT solver first
     327         [ +  - ]:    1317938 :   Trace("prop") << "Push to SAT..." << std::endl;
     328         [ +  + ]:    1317938 :   if (!trn.isNull())
     329                 :            :   {
     330                 :            :     // inprocess
     331                 :     886234 :     if (inprocess
     332 [ +  + ][ +  + ]:     886234 :         && options().theory.lemmaInprocess != options::LemmaInprocessMode::NONE)
                 [ +  + ]
     333                 :            :     {
     334                 :          3 :       trn = d_theoryProxy->inprocessLemma(trn);
     335                 :            :     }
     336                 :     886234 :     assertTrustedLemmaInternal(id, trn, removable, local);
     337                 :            :   }
     338         [ +  + ]:    1353503 :   for (const theory::SkolemLemma& lem : ppLemmas)
     339                 :            :   {
     340                 :      35565 :     assertTrustedLemmaInternal(theory::InferenceId::THEORY_PP_SKOLEM_LEM,
     341                 :      35565 :                                lem.d_lemma,
     342                 :            :                                removable,
     343                 :            :                                local);
     344                 :            :   }
     345                 :            :   // Note that this order is important for theories that send lemmas during
     346                 :            :   // preregistration, as it impacts the order in which lemmas are processed
     347                 :            :   // by default by the decision engine. In particular, sending to the SAT
     348                 :            :   // solver first means that lemmas sent during preregistration in response to
     349                 :            :   // the current lemma are processed after that lemma. This makes a difference
     350                 :            :   // e.g. for string reduction lemmas, where preregistration lemmas are
     351                 :            :   // introduced for skolems that appear in reductions. Moving the above
     352                 :            :   // block after the one below has mixed performance on SMT-LIB strings logics.
     353         [ +  - ]:    1317938 :   Trace("prop") << "Notify assertions..." << std::endl;
     354                 :            :   // also add to the decision engine, where notice we don't need proofs
     355         [ +  + ]:    1317938 :   if (!trn.isNull())
     356                 :            :   {
     357                 :            :     // notify the theory proxy of the lemma
     358                 :     886234 :     d_theoryProxy->notifyAssertion(trn.getProven(), TNode::null(), true, local);
     359                 :            :   }
     360         [ +  + ]:    1353503 :   for (const theory::SkolemLemma& lem : ppLemmas)
     361                 :            :   {
     362                 :      35565 :     d_theoryProxy->notifyAssertion(lem.getProven(), lem.d_skolem, true, local);
     363                 :            :   }
     364         [ +  - ]:    1317938 :   Trace("prop") << "Finish " << trn << std::endl;
     365                 :    1317938 : }
     366                 :            : 
     367                 :     269814 : void PropEngine::notifyExplainedPropagation(TrustNode texp)
     368                 :            : {
     369         [ +  + ]:     269814 :   if (d_ppm != nullptr)
     370                 :            :   {
     371                 :     158564 :     d_ppm->notifyExplainedPropagation(texp);
     372                 :            :   }
     373                 :     269814 : }
     374                 :            : 
     375                 :     166864 : void PropEngine::preferPhase(TNode n, bool phase)
     376                 :            : {
     377         [ +  - ]:     166864 :   Trace("prop") << "preferPhase(" << n << ", " << phase << ")" << std::endl;
     378                 :            : 
     379 [ -  + ][ -  + ]:     166864 :   Assert(n.getType().isBoolean());
                 [ -  - ]
     380                 :     166864 :   SatLiteral lit = d_cnfStream->getLiteral(n);
     381         [ +  + ]:     166864 :   d_satSolver->preferPhase(phase ? lit : ~lit);
     382                 :     166864 : }
     383                 :            : 
     384                 :     206711 : bool PropEngine::isDecision(Node lit) const
     385                 :            : {
     386 [ -  + ][ -  + ]:     206711 :   Assert(isSatLiteral(lit));
                 [ -  - ]
     387                 :     206711 :   return d_satSolver->isDecision(d_cnfStream->getLiteral(lit).getSatVariable());
     388                 :            : }
     389                 :            : 
     390                 :          0 : std::vector<Node> PropEngine::getPropDecisions() const
     391                 :            : {
     392                 :          0 :   std::vector<Node> decisions;
     393                 :          0 :   std::vector<SatLiteral> miniDecisions = d_satSolver->getDecisions();
     394         [ -  - ]:          0 :   for (SatLiteral d : miniDecisions)
     395                 :            :   {
     396                 :          0 :     decisions.push_back(d_cnfStream->getNode(d));
     397                 :            :   }
     398                 :          0 :   return decisions;
     399                 :          0 : }
     400                 :            : 
     401                 :          0 : std::vector<Node> PropEngine::getPropOrderHeap() const
     402                 :            : {
     403                 :          0 :   return d_satSolver->getOrderHeap();
     404                 :            : }
     405                 :            : 
     406                 :         16 : bool PropEngine::isFixed(TNode lit) const
     407                 :            : {
     408         [ +  - ]:         16 :   if (isSatLiteral(lit))
     409                 :            :   {
     410                 :         16 :     return d_satSolver->isFixed(d_cnfStream->getLiteral(lit).getSatVariable());
     411                 :            :   }
     412                 :          0 :   return false;
     413                 :            : }
     414                 :            : 
     415                 :          0 : void PropEngine::printSatisfyingAssignment()
     416                 :            : {
     417                 :            :   const CnfStream::NodeToLiteralMap& transCache =
     418                 :          0 :       d_cnfStream->getTranslationCache();
     419         [ -  - ]:          0 :   Trace("prop-value") << "Literal | Value | Expr" << std::endl
     420                 :          0 :                       << "----------------------------------------"
     421                 :          0 :                       << "-----------------" << std::endl;
     422                 :          0 :   for (CnfStream::NodeToLiteralMap::const_iterator i = transCache.begin(),
     423                 :          0 :                                                    end = transCache.end();
     424         [ -  - ]:          0 :        i != end;
     425                 :          0 :        ++i)
     426                 :            :   {
     427                 :          0 :     std::pair<Node, SatLiteral> curr = *i;
     428                 :          0 :     SatLiteral l = curr.second;
     429         [ -  - ]:          0 :     if (!l.isNegated())
     430                 :            :     {
     431                 :          0 :       Node n = curr.first;
     432                 :          0 :       SatValue value = d_satSolver->modelValue(l);
     433         [ -  - ]:          0 :       Trace("prop-value") << "'" << l << "' " << value << " " << n << std::endl;
     434                 :          0 :     }
     435                 :          0 :   }
     436                 :          0 : }
     437                 :        934 : void PropEngine::outputIncompleteReason(UnknownExplanation uexp,
     438                 :            :                                         theory::IncompleteId iid)
     439                 :            : {
     440         [ +  + ]:        934 :   if (isOutputOn(OutputTag::INCOMPLETE))
     441                 :            :   {
     442                 :          4 :     output(OutputTag::INCOMPLETE) << "(incomplete ";
     443                 :          4 :     output(OutputTag::INCOMPLETE) << uexp;
     444         [ +  - ]:          4 :     if (iid != theory::IncompleteId::UNKNOWN)
     445                 :            :     {
     446                 :          4 :       output(OutputTag::INCOMPLETE) << " " << iid;
     447                 :            :     }
     448                 :          4 :     output(OutputTag::INCOMPLETE) << ")" << std::endl;
     449                 :            :   }
     450                 :        934 : }
     451                 :            : 
     452                 :      32412 : Result PropEngine::checkSat()
     453                 :            : {
     454 [ -  + ][ -  + ]:      32412 :   Assert(!d_inCheckSat) << "Sat solver in solve()!";
                 [ -  - ]
     455         [ +  - ]:      32412 :   Trace("prop") << "PropEngine::checkSat()" << std::endl;
     456                 :            : 
     457                 :            :   // Mark that we are in the checkSat
     458                 :      32412 :   ScopedBool scopedBool(d_inCheckSat);
     459                 :      32412 :   d_inCheckSat = true;
     460                 :            : 
     461         [ -  + ]:      32412 :   if (options().base.preprocessOnly)
     462                 :            :   {
     463                 :          0 :     outputIncompleteReason(UnknownExplanation::REQUIRES_FULL_CHECK);
     464                 :          0 :     return Result(Result::UNKNOWN, UnknownExplanation::REQUIRES_FULL_CHECK);
     465                 :            :   }
     466                 :            : 
     467                 :            :   // Note this currently ignores conflicts (a dangerous practice).
     468                 :      32412 :   d_theoryProxy->presolve();
     469                 :            : 
     470                 :            :   // add the assumptions
     471                 :      32412 :   std::vector<SatLiteral> assumptions;
     472         [ +  + ]:     160538 :   for (const Node& node : d_assumptions)
     473                 :            :   {
     474                 :     128126 :     assumptions.push_back(d_cnfStream->getLiteral(node));
     475                 :            :   }
     476                 :            : 
     477                 :            :   // now log preprocessing
     478         [ +  + ]:      32412 :   if (d_ppm != nullptr)
     479                 :            :   {
     480                 :      17560 :     d_ppm->logPreprocessing();
     481                 :            :   }
     482                 :            : 
     483                 :            :   // Reset the interrupted flag
     484                 :      32412 :   d_interrupted = false;
     485                 :            : 
     486                 :            :   // Check the problem
     487                 :            :   SatValue result;
     488         [ +  + ]:      32412 :   if (assumptions.empty())
     489                 :            :   {
     490                 :      24877 :     result = d_satSolver->solve();
     491                 :            :   }
     492                 :            :   else
     493                 :            :   {
     494                 :       7535 :     result = d_satSolver->solve(assumptions);
     495                 :            :   }
     496                 :            : 
     497                 :      32396 :   ResourceManager* rm = resourceManager();
     498                 :      32396 :   bool wasInterrupted = result == SAT_VALUE_UNKNOWN;
     499                 :            :   // If a resource limit expires during a full theory check, the SAT solver may
     500                 :            :   // still return SAT before observing its termination callback. In that case,
     501                 :            :   // the candidate model may not have been fully checked by the theories.
     502 [ +  + ][ +  - ]:      32396 :   if (result == SAT_VALUE_TRUE && (d_interrupted || rm->out()))
         [ -  + ][ -  + ]
     503                 :            :   {
     504                 :          0 :     wasInterrupted = true;
     505                 :          0 :     result = SAT_VALUE_UNKNOWN;
     506                 :            :   }
     507                 :            : 
     508                 :      32396 :   d_theoryProxy->postsolve(result);
     509                 :            : 
     510         [ +  + ]:      32396 :   if (wasInterrupted)
     511                 :            :   {
     512                 :         82 :     UnknownExplanation why = UnknownExplanation::INTERRUPTED;
     513         [ +  + ]:         82 :     if (rm->outOfTime())
     514                 :            :     {
     515                 :         80 :       why = UnknownExplanation::TIMEOUT;
     516                 :            :     }
     517         [ +  + ]:         82 :     if (rm->outOfResources())
     518                 :            :     {
     519                 :          2 :       why = UnknownExplanation::RESOURCEOUT;
     520                 :            :     }
     521                 :         82 :     outputIncompleteReason(why);
     522                 :         82 :     return Result(Result::UNKNOWN, why);
     523                 :            :   }
     524                 :            : 
     525                 :      32314 :   if (result == SAT_VALUE_TRUE && TraceIsOn("prop"))
     526                 :            :   {
     527                 :          0 :     printSatisfyingAssignment();
     528                 :            :   }
     529                 :            : 
     530         [ +  - ]:      32314 :   Trace("prop") << "PropEngine::checkSat() => " << result << std::endl;
     531         [ +  + ]:      32314 :   if (result == SAT_VALUE_TRUE)
     532                 :            :   {
     533         [ +  + ]:      13709 :     if (d_theoryProxy->isModelUnsound())
     534                 :            :     {
     535                 :        832 :       outputIncompleteReason(UnknownExplanation::INCOMPLETE,
     536                 :        832 :                              d_theoryProxy->getModelUnsoundId());
     537                 :        832 :       return Result(Result::UNKNOWN, UnknownExplanation::INCOMPLETE);
     538                 :            :     }
     539                 :            :   }
     540         [ +  + ]:      18605 :   else if (d_theoryProxy->isRefutationUnsound())
     541                 :            :   {
     542                 :         20 :     outputIncompleteReason(UnknownExplanation::INCOMPLETE,
     543                 :         20 :                            d_theoryProxy->getRefutationUnsoundId());
     544                 :         20 :     return Result(Result::UNKNOWN, UnknownExplanation::INCOMPLETE);
     545                 :            :   }
     546                 :            : 
     547         [ +  + ]:      31462 :   if (d_ppm != nullptr)
     548                 :            :   {
     549                 :      17459 :     d_ppm->postsolve(result);
     550                 :            :   }
     551                 :            : 
     552         [ +  + ]:      31462 :   return Result(result == SAT_VALUE_TRUE ? Result::SAT : Result::UNSAT);
     553                 :      32428 : }
     554                 :            : 
     555                 :      96566 : Node PropEngine::getValue(TNode node) const
     556                 :            : {
     557 [ -  + ][ -  + ]:      96566 :   Assert(node.getType().isBoolean());
                 [ -  - ]
     558 [ -  + ][ -  + ]:      96566 :   Assert(d_cnfStream->hasLiteral(node));
                 [ -  - ]
     559                 :            : 
     560                 :      96566 :   SatLiteral lit = d_cnfStream->getLiteral(node);
     561                 :            : 
     562                 :      96566 :   SatValue v = d_satSolver->value(lit);
     563         [ +  + ]:      96566 :   if (v == SAT_VALUE_TRUE)
     564                 :            :   {
     565                 :     192616 :     return nodeManager()->mkConst(true);
     566                 :            :   }
     567         [ +  + ]:        258 :   else if (v == SAT_VALUE_FALSE)
     568                 :            :   {
     569                 :        416 :     return nodeManager()->mkConst(false);
     570                 :            :   }
     571                 :            :   else
     572                 :            :   {
     573 [ -  + ][ -  + ]:         50 :     Assert(v == SAT_VALUE_UNKNOWN);
                 [ -  - ]
     574                 :         50 :     return Node::null();
     575                 :            :   }
     576                 :            : }
     577                 :            : 
     578                 :   58615483 : bool PropEngine::isSatLiteral(TNode node) const
     579                 :            : {
     580                 :   58615483 :   return d_cnfStream->hasLiteral(node);
     581                 :            : }
     582                 :            : 
     583                 :   22704421 : bool PropEngine::hasValue(TNode node, bool& value) const
     584                 :            : {
     585 [ -  + ][ -  + ]:   22704421 :   Assert(node.getType().isBoolean());
                 [ -  - ]
     586                 :   22704421 :   Assert(d_cnfStream->hasLiteral(node)) << node;
     587                 :            : 
     588                 :   22704421 :   SatLiteral lit = d_cnfStream->getLiteral(node);
     589                 :            : 
     590                 :   22704421 :   SatValue v = d_satSolver->value(lit);
     591         [ +  + ]:   22704421 :   if (v == SAT_VALUE_TRUE)
     592                 :            :   {
     593                 :   13693352 :     value = true;
     594                 :   13693352 :     return true;
     595                 :            :   }
     596         [ +  + ]:    9011069 :   else if (v == SAT_VALUE_FALSE)
     597                 :            :   {
     598                 :     316550 :     value = false;
     599                 :     316550 :     return true;
     600                 :            :   }
     601                 :            :   else
     602                 :            :   {
     603 [ -  + ][ -  + ]:    8694519 :     Assert(v == SAT_VALUE_UNKNOWN);
                 [ -  - ]
     604                 :    8694519 :     return false;
     605                 :            :   }
     606                 :            : }
     607                 :            : 
     608                 :      28899 : void PropEngine::getBooleanVariables(std::vector<TNode>& outputVariables) const
     609                 :            : {
     610                 :      28899 :   d_cnfStream->getBooleanVariables(outputVariables);
     611                 :      28899 : }
     612                 :            : 
     613                 :     421356 : Node PropEngine::ensureLiteral(TNode n)
     614                 :            : {
     615                 :            :   // must preprocess
     616                 :     421356 :   Node preprocessed = getPreprocessedTerm(n);
     617         [ +  - ]:     842712 :   Trace("ensureLiteral") << "ensureLiteral preprocessed: " << preprocessed
     618                 :     421356 :                          << std::endl;
     619         [ +  + ]:     421356 :   if (isProofEnabled())
     620                 :            :   {
     621                 :     233374 :     d_ppm->ensureLiteral(preprocessed);
     622                 :            :   }
     623                 :            :   else
     624                 :            :   {
     625                 :     187982 :     d_cnfStream->ensureLiteral(preprocessed);
     626                 :            :   }
     627                 :     421356 :   return preprocessed;
     628                 :          0 : }
     629                 :            : 
     630                 :     431704 : Node PropEngine::getPreprocessedTerm(TNode n)
     631                 :            : {
     632                 :            :   // must preprocess
     633                 :     431704 :   std::vector<theory::SkolemLemma> newLemmas;
     634                 :     431704 :   TrustNode tpn = d_theoryProxy->preprocess(n, newLemmas);
     635                 :            :   // send lemmas corresponding to the skolems introduced by preprocessing n
     636                 :     431704 :   TrustNode trnNull;
     637                 :     431704 :   assertLemmasInternal(theory::InferenceId::THEORY_PP_SKOLEM_LEM,
     638                 :            :                        trnNull,
     639                 :            :                        newLemmas,
     640                 :            :                        false,
     641                 :            :                        false,
     642                 :            :                        false);
     643         [ +  + ]:     863408 :   return tpn.isNull() ? Node(n) : tpn.getNode();
     644                 :     431704 : }
     645                 :            : 
     646                 :       4194 : Node PropEngine::getPreprocessedTerm(TNode n,
     647                 :            :                                      std::vector<Node>& skAsserts,
     648                 :            :                                      std::vector<Node>& sks)
     649                 :            : {
     650                 :            :   // get the preprocessed form of the term
     651                 :       4194 :   Node pn = getPreprocessedTerm(n);
     652                 :            :   // initialize the set of skolems and assertions to process
     653                 :       4194 :   std::vector<Node> toProcessAsserts;
     654                 :       4194 :   std::vector<Node> toProcess;
     655                 :       4194 :   d_theoryProxy->getSkolems(pn, toProcessAsserts, toProcess);
     656                 :       4194 :   size_t index = 0;
     657                 :            :   // until fixed point is reached
     658         [ +  + ]:       8461 :   while (index < toProcess.size())
     659                 :            :   {
     660                 :       4267 :     Node ka = toProcessAsserts[index];
     661                 :       4267 :     Node k = toProcess[index];
     662                 :       4267 :     index++;
     663         [ +  + ]:       4267 :     if (std::find(sks.begin(), sks.end(), k) != sks.end())
     664                 :            :     {
     665                 :            :       // already added the skolem to the list
     666                 :       2246 :       continue;
     667                 :            :     }
     668                 :            :     // must preprocess lemmas as well
     669                 :       2021 :     Node kap = getPreprocessedTerm(ka);
     670                 :       2021 :     skAsserts.push_back(kap);
     671                 :       2021 :     sks.push_back(k);
     672                 :            :     // get the skolems in the preprocessed form of the lemma ka
     673                 :       2021 :     d_theoryProxy->getSkolems(kap, toProcessAsserts, toProcess);
     674 [ +  + ][ +  + ]:       6513 :   }
     675                 :            :   // return the preprocessed term
     676                 :       8388 :   return pn;
     677                 :       4194 : }
     678                 :            : 
     679                 :       4339 : void PropEngine::push()
     680                 :            : {
     681 [ -  + ][ -  + ]:       4339 :   Assert(!d_inCheckSat) << "Sat solver in solve()!";
                 [ -  - ]
     682                 :       4339 :   d_satSolver->push();
     683         [ +  - ]:       4339 :   Trace("prop") << "push()" << std::endl;
     684                 :       4339 : }
     685                 :            : 
     686                 :       4338 : void PropEngine::pop()
     687                 :            : {
     688 [ -  + ][ -  + ]:       4338 :   Assert(!d_inCheckSat) << "Sat solver in solve()!";
                 [ -  - ]
     689                 :       4338 :   d_satSolver->pop();
     690         [ +  - ]:       4338 :   Trace("prop") << "pop()" << std::endl;
     691                 :       4338 : }
     692                 :            : 
     693                 :      31972 : void PropEngine::resetTrail()
     694                 :            : {
     695                 :      31972 :   d_satSolver->resetTrail();
     696         [ +  - ]:      31972 :   Trace("prop") << "resetTrail()" << std::endl;
     697                 :      31972 : }
     698                 :            : 
     699                 :      28672 : uint32_t PropEngine::getAssertionLevel() const
     700                 :            : {
     701                 :      28672 :   return d_satSolver->getAssertionLevel();
     702                 :            : }
     703                 :            : 
     704                 :          0 : bool PropEngine::isRunning() const { return d_inCheckSat; }
     705                 :     269557 : void PropEngine::interrupt()
     706                 :            : {
     707         [ +  + ]:     269557 :   if (!d_inCheckSat)
     708                 :            :   {
     709                 :     261519 :     return;
     710                 :            :   }
     711                 :            : 
     712                 :       8038 :   d_interrupted = true;
     713                 :       8038 :   d_satSolver->interrupt();
     714         [ +  - ]:       8038 :   Trace("prop") << "interrupt()" << std::endl;
     715                 :            : }
     716                 :            : 
     717                 :       4787 : void PropEngine::spendResource(Resource r)
     718                 :            : {
     719                 :       4787 :   d_env.getResourceManager()->spendResource(r);
     720                 :       4787 : }
     721                 :            : 
     722                 :          0 : bool PropEngine::properExplanation(TNode node, TNode expl) const
     723                 :            : {
     724         [ -  - ]:          0 :   if (!d_cnfStream->hasLiteral(node))
     725                 :            :   {
     726         [ -  - ]:          0 :     Trace("properExplanation")
     727                 :          0 :         << "properExplanation(): Failing because node "
     728                 :          0 :         << "being explained doesn't have a SAT literal ?!" << std::endl
     729                 :          0 :         << "properExplanation(): The node is: " << node << std::endl;
     730                 :          0 :     return false;
     731                 :            :   }
     732                 :            : 
     733                 :          0 :   SatLiteral nodeLit = d_cnfStream->getLiteral(node);
     734                 :            : 
     735                 :          0 :   for (TNode::kinded_iterator i = expl.begin(Kind::AND),
     736                 :          0 :                               i_end = expl.end(Kind::AND);
     737         [ -  - ]:          0 :        i != i_end;
     738                 :          0 :        ++i)
     739                 :            :   {
     740         [ -  - ]:          0 :     if (!d_cnfStream->hasLiteral(*i))
     741                 :            :     {
     742         [ -  - ]:          0 :       Trace("properExplanation")
     743                 :          0 :           << "properExplanation(): Failing because one of explanation "
     744                 :          0 :           << "nodes doesn't have a SAT literal" << std::endl
     745                 :          0 :           << "properExplanation(): The explanation node is: " << *i
     746                 :          0 :           << std::endl;
     747                 :          0 :       return false;
     748                 :            :     }
     749                 :            : 
     750                 :          0 :     SatLiteral iLit = d_cnfStream->getLiteral(*i);
     751                 :            : 
     752         [ -  - ]:          0 :     if (iLit == nodeLit)
     753                 :            :     {
     754         [ -  - ]:          0 :       Trace("properExplanation")
     755                 :          0 :           << "properExplanation(): Failing because the node" << std::endl
     756                 :          0 :           << "properExplanation(): " << node << std::endl
     757                 :          0 :           << "properExplanation(): cannot be made to explain itself!"
     758                 :          0 :           << std::endl;
     759                 :          0 :       return false;
     760                 :            :     }
     761 [ -  - ][ -  - ]:          0 :   }
     762                 :            : 
     763                 :          0 :   return true;
     764                 :            : }
     765                 :            : 
     766                 :          7 : void PropEngine::checkProof(const context::CDList<Node>& assertions)
     767                 :            : {
     768         [ -  + ]:          7 :   if (!d_env.isSatProofProducing())
     769                 :            :   {
     770                 :          0 :     return;
     771                 :            :   }
     772                 :          7 :   return d_ppm->checkProof(assertions);
     773                 :            : }
     774                 :            : 
     775                 :       8148 : std::shared_ptr<ProofNode> PropEngine::getProof(bool connectCnf)
     776                 :            : {
     777         [ -  + ]:       8148 :   if (!d_env.isSatProofProducing())
     778                 :            :   {
     779                 :          0 :     return nullptr;
     780                 :            :   }
     781         [ +  - ]:      16296 :   Trace("sat-proof") << "PropEngine::getProof: getting proof with cnfStream's "
     782                 :          0 :                         "lazycdproof cxt lvl "
     783                 :       8148 :                      << userContext()->getLevel() << "\n";
     784                 :       8148 :   return d_ppm->getProof(connectCnf);
     785                 :            : }
     786                 :            : 
     787                 :          6 : std::vector<std::shared_ptr<ProofNode>> PropEngine::getProofLeaves(
     788                 :            :     modes::ProofComponent pc)
     789                 :            : {
     790                 :          6 :   return d_ppm->getProofLeaves(pc);
     791                 :            : }
     792                 :            : 
     793                 :    1812713 : bool PropEngine::isProofEnabled() const { return d_ppm != nullptr; }
     794                 :            : 
     795                 :       3467 : void PropEngine::getUnsatCore(std::vector<Node>& core)
     796                 :            : {
     797         [ +  + ]:       3467 :   if (options().smt.unsatCoresMode == options::UnsatCoresMode::ASSUMPTIONS)
     798                 :            :   {
     799         [ +  - ]:       6268 :     Trace("unsat-core") << "PropEngine::getUnsatCore: via unsat assumptions"
     800                 :       3134 :                         << std::endl;
     801                 :       3134 :     std::vector<SatLiteral> unsat_assumptions;
     802                 :       3134 :     d_satSolver->getUnsatAssumptions(unsat_assumptions);
     803         [ +  + ]:      21020 :     for (const SatLiteral& lit : unsat_assumptions)
     804                 :            :     {
     805                 :      17886 :       core.push_back(d_cnfStream->getNode(lit));
     806                 :            :     }
     807                 :       3134 :   }
     808                 :            :   else
     809                 :            :   {
     810         [ +  - ]:        333 :     Trace("unsat-core") << "PropEngine::getUnsatCore: via proof" << std::endl;
     811                 :            :     // otherwise, it is just the free assumptions of the proof. Note that we
     812                 :            :     // need to connect the SAT proof to the CNF proof becuase we need the
     813                 :            :     // preprocessed input as leaves, not the clauses derived from them.
     814                 :        333 :     std::shared_ptr<ProofNode> pfn = getProof();
     815         [ +  - ]:        333 :     Trace("unsat-core") << "Proof is " << *pfn.get() << std::endl;
     816                 :        333 :     expr::getFreeAssumptions(pfn.get(), core);
     817         [ +  - ]:        333 :     Trace("unsat-core") << "Core is " << core << std::endl;
     818                 :        333 :   }
     819                 :       3467 : }
     820                 :            : 
     821                 :         10 : std::vector<Node> PropEngine::getUnsatCoreLemmas()
     822                 :            : {
     823 [ -  + ][ -  + ]:         10 :   Assert(d_env.isSatProofProducing());
                 [ -  - ]
     824                 :         10 :   std::vector<Node> lems = d_ppm->getUnsatCoreLemmas();
     825         [ -  + ]:         10 :   if (isOutputOn(OutputTag::UNSAT_CORE_LEMMAS))
     826                 :            :   {
     827                 :          0 :     output(OutputTag::UNSAT_CORE_LEMMAS)
     828                 :          0 :         << ";; unsat core lemmas start" << std::endl;
     829                 :          0 :     std::stringstream ss;
     830         [ -  - ]:          0 :     for (const Node& lem : lems)
     831                 :            :     {
     832                 :          0 :       output(OutputTag::UNSAT_CORE_LEMMAS) << "(unsat-core-lemma ";
     833                 :            :       output(OutputTag::UNSAT_CORE_LEMMAS)
     834                 :          0 :           << SkolemManager::getOriginalForm(lem);
     835                 :          0 :       uint64_t timestamp = 0;
     836                 :          0 :       theory::InferenceId id = d_ppm->getInferenceIdFor(lem, timestamp);
     837         [ -  - ]:          0 :       if (id != theory::InferenceId::NONE)
     838                 :            :       {
     839                 :          0 :         output(OutputTag::UNSAT_CORE_LEMMAS) << " :source " << id;
     840                 :            :       }
     841                 :          0 :       output(OutputTag::UNSAT_CORE_LEMMAS) << " :timestamp " << timestamp;
     842                 :          0 :       output(OutputTag::UNSAT_CORE_LEMMAS) << ")" << std::endl;
     843                 :            :       // for trace below
     844                 :          0 :       ss << id << ", " << timestamp << std::endl;
     845                 :            :     }
     846                 :          0 :     output(OutputTag::UNSAT_CORE_LEMMAS)
     847                 :          0 :         << ";; unsat core lemmas end" << std::endl;
     848                 :            :     // print in csv form for debugging
     849         [ -  - ]:          0 :     Trace("ocl-timestamp") << "TIMESTAMPS" << std::endl;
     850                 :          0 :     Trace("ocl-timestamp") << ss.str() << std::endl;
     851                 :          0 :   }
     852                 :         10 :   return lems;
     853                 :          0 : }
     854                 :            : 
     855                 :         20 : std::vector<Node> PropEngine::getLearnedZeroLevelLiterals(
     856                 :            :     modes::LearnedLitType ltype) const
     857                 :            : {
     858                 :         20 :   return d_theoryProxy->getLearnedZeroLevelLiterals(ltype);
     859                 :            : }
     860                 :            : 
     861                 :          7 : std::vector<Node> PropEngine::getLearnedZeroLevelLiteralsForRestart() const
     862                 :            : {
     863                 :          7 :   return d_theoryProxy->getLearnedZeroLevelLiteralsForRestart();
     864                 :            : }
     865                 :            : 
     866                 :          0 : modes::LearnedLitType PropEngine::getLiteralType(const Node& lit) const
     867                 :            : {
     868                 :          0 :   return d_theoryProxy->getLiteralType(lit);
     869                 :            : }
     870                 :            : 
     871                 :      28722 : PropEngine::Statistics::Statistics(StatisticsRegistry& sr)
     872                 :      28722 :     : d_numInputAtoms(sr.registerInt("prop::PropEngine::numInputAtoms"))
     873                 :            : {
     874                 :      28722 : }
     875                 :            : 
     876                 :            : }  // namespace prop
     877                 :            : }  // namespace cvc5::internal

Generated by: LCOV version 1.14