LCOV - code coverage report
Current view: top level - buildbot/coverage/build/src/prop/minisat - sat_proof_manager.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 391 538 72.7 %
Date: 2026-03-31 10:41:31 Functions: 23 24 95.8 %
Branches: 245 554 44.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 proof manager for Minisat.
      11                 :            :  */
      12                 :            : 
      13                 :            : #include "prop/minisat/sat_proof_manager.h"
      14                 :            : 
      15                 :            : #include "options/proof_options.h"
      16                 :            : #include "proof/proof_node_algorithm.h"
      17                 :            : #include "proof/theory_proof_step_buffer.h"
      18                 :            : #include "prop/cnf_stream.h"
      19                 :            : #include "prop/minisat/minisat.h"
      20                 :            : #include "prop/prop_proof_manager.h"
      21                 :            : 
      22                 :            : namespace cvc5::internal {
      23                 :            : namespace prop {
      24                 :            : 
      25                 :      20020 : SatProofManager::SatProofManager(Env& env,
      26                 :            :                                  Minisat::Solver* solver,
      27                 :            :                                  CnfStream* cnfStream,
      28                 :      20020 :                                  PropPfManager* ppm)
      29                 :            :     : EnvObj(env),
      30                 :      20020 :       d_solver(solver),
      31                 :      20020 :       d_cnfStream(cnfStream),
      32                 :      20020 :       d_ppm(ppm),
      33                 :      20020 :       d_resChains(d_env, true, userContext()),
      34                 :            :       // enforce unique assumptions and no symmetry. This avoids creating
      35                 :            :       // duplicate assumption proof nodes for the premises of resolution steps,
      36                 :            :       // which when expanded in the lazy proof chain would duplicate their
      37                 :            :       // justifications (which can lead to performance impacts when proof
      38                 :            :       // post-processing). Symmetry we can disable because there is no equality
      39                 :            :       // reasoning performed here
      40                 :      20020 :       d_resChainPg(d_env, userContext(), true, false),
      41                 :      20020 :       d_assumptions(userContext()),
      42                 :      20020 :       d_conflictLit(undefSatVariable),
      43                 :      20020 :       d_optResLevels(userContext()),
      44                 :      20020 :       d_optResManager(userContext(), &d_resChains, d_optResProofs),
      45                 :      80080 :       d_optClausesManager(userContext(), ppm->getCnfProof(), d_optClausesPfs)
      46                 :            : {
      47                 :      20020 :   d_true = nodeManager()->mkConst(true);
      48                 :      20020 :   d_false = nodeManager()->mkConst(false);
      49                 :      20020 :   d_optResManager.trackNodeHashSet(&d_assumptions, &d_assumptionLevels);
      50                 :            :   // temporary, to allow this class to be notified when new clauses are added
      51                 :            :   // see https://github.com/cvc5/cvc5-wishues/issues/149
      52                 :      20020 :   ppm->d_satPm = this;
      53                 :      20020 : }
      54                 :            : 
      55                 :          0 : void SatProofManager::printClause(const Minisat::Clause& clause)
      56                 :            : {
      57         [ -  - ]:          0 :   for (size_t i = 0, size = clause.size(); i < size; ++i)
      58                 :            :   {
      59                 :          0 :     SatLiteral satLit = MinisatSatSolver::toSatLiteral(clause[i]);
      60         [ -  - ]:          0 :     Trace("sat-proof") << satLit << " ";
      61                 :            :   }
      62                 :          0 : }
      63                 :            : 
      64                 :    6948272 : Node SatProofManager::getClauseNode(const Minisat::Clause& clause)
      65                 :            : {
      66                 :    6948272 :   std::vector<Node> clauseNodes;
      67         [ +  + ]:   38924645 :   for (size_t i = 0, size = clause.size(); i < size; ++i)
      68                 :            :   {
      69                 :   31976373 :     SatLiteral satLit = MinisatSatSolver::toSatLiteral(clause[i]);
      70                 :   31976373 :     clauseNodes.push_back(d_cnfStream->getNode(satLit));
      71                 :            :   }
      72                 :            :   // order children by node id
      73                 :    6948272 :   std::sort(clauseNodes.begin(), clauseNodes.end());
      74                 :   13896544 :   return nodeManager()->mkNode(Kind::OR, clauseNodes);
      75                 :    6948272 : }
      76                 :            : 
      77                 :     210178 : void SatProofManager::startResChain(const Minisat::Clause& start)
      78                 :            : {
      79         [ -  + ]:     210178 :   if (TraceIsOn("sat-proof"))
      80                 :            :   {
      81         [ -  - ]:          0 :     Trace("sat-proof") << "SatProofManager::startResChain: ";
      82                 :          0 :     printClause(start);
      83         [ -  - ]:          0 :     Trace("sat-proof") << "\n";
      84                 :            :   }
      85                 :     210178 :   d_resLinks.emplace_back(getClauseNode(start), Node::null(), true);
      86                 :     210178 : }
      87                 :            : 
      88                 :    1640607 : void SatProofManager::addResolutionStep(Minisat::Lit lit, bool redundant)
      89                 :            : {
      90                 :    1640607 :   SatLiteral satLit = MinisatSatSolver::toSatLiteral(lit);
      91                 :    1640607 :   Node litNode = d_cnfStream->getNodeCache()[satLit];
      92                 :    1640607 :   bool negated = satLit.isNegated();
      93 [ +  + ][ +  - ]:    1640607 :   Assert(!negated || litNode.getKind() == Kind::NOT);
         [ -  + ][ -  + ]
                 [ -  - ]
      94         [ +  + ]:    1640607 :   if (!redundant)
      95                 :            :   {
      96         [ +  - ]:    1460354 :     Trace("sat-proof") << "SatProofManager::addResolutionStep: {"
      97                 :          0 :                        << satLit.isNegated() << "} [" << satLit << "] "
      98                 :     730177 :                        << ~satLit << "\n";
      99                 :            :     // if lit is negated then the chain resolution construction will use it as a
     100                 :            :     // pivot occurring as is in the second clause and the node under the
     101                 :            :     // negation in the first clause
     102                 :     730177 :     d_resLinks.emplace_back(d_cnfStream->getNodeCache()[~satLit],
     103                 :    1460354 :                             negated ? litNode[0] : litNode,
     104         [ +  + ]:    1460354 :                             !satLit.isNegated());
     105                 :            :   }
     106                 :            :   else
     107                 :            :   {
     108         [ +  - ]:    1820860 :     Trace("sat-proof") << "SatProofManager::addResolutionStep: redundant lit "
     109                 :     910430 :                        << satLit << " stored\n";
     110                 :     910430 :     d_redundantLits.push_back(satLit);
     111                 :            :   }
     112                 :    1640607 : }
     113                 :            : 
     114                 :    4183309 : void SatProofManager::addResolutionStep(const Minisat::Clause& clause,
     115                 :            :                                         Minisat::Lit lit)
     116                 :            : {
     117                 :    4183309 :   SatLiteral satLit = MinisatSatSolver::toSatLiteral(lit);
     118                 :    4183309 :   Node litNode = d_cnfStream->getNodeCache()[satLit];
     119                 :    4183309 :   bool negated = satLit.isNegated();
     120 [ +  + ][ +  - ]:    4183309 :   Assert(!negated || litNode.getKind() == Kind::NOT);
         [ -  + ][ -  + ]
                 [ -  - ]
     121                 :    4183309 :   Node clauseNode = getClauseNode(clause);
     122                 :            :   // if lit is negative then the chain resolution construction will use it as a
     123                 :            :   // pivot occurring as is in the second clause and the node under the
     124                 :            :   // negation in the first clause, which means that the third argument of the
     125                 :            :   // tuple must be false
     126         [ +  + ]:    4183309 :   d_resLinks.emplace_back(clauseNode, negated ? litNode[0] : litNode, negated);
     127         [ -  + ]:    4183309 :   if (TraceIsOn("sat-proof"))
     128                 :            :   {
     129         [ -  - ]:          0 :     Trace("sat-proof") << "SatProofManager::addResolutionStep: {"
     130                 :          0 :                        << satLit.isNegated() << "} [" << ~satLit << "] ";
     131                 :          0 :     printClause(clause);
     132         [ -  - ]:          0 :     Trace("sat-proof") << "\nSatProofManager::addResolutionStep:\t"
     133                 :          0 :                        << clauseNode << " - lvl " << clause.level() + 1 << "\n";
     134                 :            :   }
     135                 :    4183309 : }
     136                 :            : 
     137                 :       9910 : void SatProofManager::endResChain(Minisat::Lit lit)
     138                 :            : {
     139                 :       9910 :   SatLiteral satLit = MinisatSatSolver::toSatLiteral(lit);
     140         [ +  - ]:      19820 :   Trace("sat-proof") << "SatProofManager::endResChain: curr user level: "
     141                 :       9910 :                      << userContext()->getLevel() << "\n";
     142         [ +  - ]:      19820 :   Trace("sat-proof") << "SatProofManager::endResChain: chain_res for "
     143                 :       9910 :                      << satLit;
     144                 :       9910 :   endResChain(d_cnfStream->getNode(satLit), {satLit});
     145                 :       9910 : }
     146                 :            : 
     147                 :     200268 : void SatProofManager::endResChain(const Minisat::Clause& clause)
     148                 :            : {
     149         [ -  + ]:     200268 :   if (TraceIsOn("sat-proof"))
     150                 :            :   {
     151         [ -  - ]:          0 :     Trace("sat-proof") << "SatProofManager::endResChain: curr user level: "
     152                 :          0 :                        << userContext()->getLevel() << "\n";
     153         [ -  - ]:          0 :     Trace("sat-proof") << "SatProofManager::endResChain: chain_res for ";
     154                 :          0 :     printClause(clause);
     155                 :            :   }
     156                 :     200268 :   std::set<SatLiteral> clauseLits;
     157         [ +  + ]:    3723616 :   for (unsigned i = 0, size = clause.size(); i < size; ++i)
     158                 :            :   {
     159                 :    3523348 :     clauseLits.insert(MinisatSatSolver::toSatLiteral(clause[i]));
     160                 :            :   }
     161                 :     200268 :   endResChain(getClauseNode(clause), clauseLits, clause.level() + 1);
     162                 :     200268 : }
     163                 :            : 
     164                 :     210178 : void SatProofManager::endResChain(Node conclusion,
     165                 :            :                                   const std::set<SatLiteral>& conclusionLits,
     166                 :            :                                   uint32_t clauseLevel)
     167                 :            : {
     168         [ +  - ]:     210178 :   Trace("sat-proof") << ", " << conclusion << "\n";
     169                 :     210178 :   LazyCDProof* cnfProof = d_ppm->getCnfProof();
     170                 :     210178 :   if (cnfProof->hasStep(conclusion) || cnfProof->hasGenerator(conclusion))
     171                 :            :   {
     172         [ +  - ]:        496 :     Trace("sat-proof") << "SatProofManager::endResChain: cnf proof has "
     173                 :        248 :                           "step/gen for it; skip\n";
     174                 :            :     // clearing
     175                 :        248 :     d_resLinks.clear();
     176                 :        248 :     d_redundantLits.clear();
     177                 :       2648 :     return;
     178                 :            :   }
     179         [ +  + ]:     209930 :   if (d_resChains.hasGenerator(conclusion))
     180                 :            :   {
     181         [ +  - ]:       3712 :     Trace("sat-proof")
     182                 :          0 :         << "SatProofManager::endResChain: skip repeated proof of " << conclusion
     183                 :       1856 :         << "\n";
     184                 :            :     // clearing
     185                 :       1856 :     d_resLinks.clear();
     186                 :       1856 :     d_redundantLits.clear();
     187                 :       1856 :     return;
     188                 :            :   }
     189                 :            :   // first process redundant literals
     190                 :     208074 :   std::set<SatLiteral> visited;
     191                 :     208074 :   unsigned pos = d_resLinks.size();
     192         [ +  + ]:    1114610 :   for (SatLiteral satLit : d_redundantLits)
     193                 :            :   {
     194                 :     906536 :     processRedundantLit(satLit, conclusionLits, visited, pos);
     195                 :            :   }
     196                 :     208074 :   d_redundantLits.clear();
     197                 :            :   // build resolution chain
     198                 :            :   // the conclusion is stored already in the arguments because of the
     199                 :            :   // possibility of reordering
     200                 :     624222 :   std::vector<Node> children, args{conclusion};
     201                 :     208074 :   std::vector<Node> pols;
     202                 :     208074 :   std::vector<Node> lits;
     203         [ +  + ]:    7565608 :   for (unsigned i = 0, size = d_resLinks.size(); i < size; ++i)
     204                 :            :   {
     205                 :    7357534 :     Node clause, pivot;
     206                 :            :     bool posFirst;
     207                 :    7357534 :     std::tie(clause, pivot, posFirst) = d_resLinks[i];
     208                 :    7357534 :     children.push_back(clause);
     209         [ +  - ]:    7357534 :     Trace("sat-proof") << "SatProofManager::endResChain:   ";
     210         [ +  + ]:    7357534 :     if (i > 0)
     211                 :            :     {
     212         [ +  - ]:   14298920 :       Trace("sat-proof") << "{" << posFirst << "} ["
     213                 :    7149460 :                          << d_cnfStream->getTranslationCache()[pivot] << "] ";
     214                 :            :     }
     215                 :            :     // special case for clause (or l1 ... ln) being a single literal
     216                 :            :     // corresponding itself to a clause, which is indicated by the pivot being
     217                 :            :     // of the form (not (or l1 ... ln))
     218                 :   22072602 :     if (clause.getKind() == Kind::OR
     219 [ +  + ][ -  + ]:   14715068 :         && !(pivot.getKind() == Kind::NOT && pivot[0].getKind() == Kind::OR
         [ -  - ][ +  + ]
                 [ -  - ]
     220 [ -  - ][ -  + ]:    7357534 :              && pivot[0] == clause))
         [ -  + ][ -  - ]
     221                 :            :     {
     222         [ +  + ]:   33755382 :       for (unsigned j = 0, sizeJ = clause.getNumChildren(); j < sizeJ; ++j)
     223                 :            :       {
     224 [ +  - ][ -  + ]:   27320382 :         Trace("sat-proof") << d_cnfStream->getTranslationCache()[clause[j]];
                 [ -  - ]
     225         [ +  + ]:   27320382 :         if (j < sizeJ - 1)
     226                 :            :         {
     227         [ +  - ]:   20885382 :           Trace("sat-proof") << ", ";
     228                 :            :         }
     229                 :            :       }
     230                 :            :     }
     231                 :            :     else
     232                 :            :     {
     233 [ -  + ][ -  - ]:     922534 :       Assert(d_cnfStream->getTranslationCache().find(clause)
     234                 :            :              != d_cnfStream->getTranslationCache().end())
     235 [ -  + ][ -  - ]:     922534 :           << "clause node " << clause
     236 [ -  + ][ -  + ]:     922534 :           << " treated as unit has no literal. Pivot is " << pivot << "\n";
                 [ -  - ]
     237         [ +  - ]:     922534 :       Trace("sat-proof") << d_cnfStream->getTranslationCache()[clause];
     238                 :            :     }
     239         [ +  - ]:    7357534 :     Trace("sat-proof") << " : ";
     240         [ +  + ]:    7357534 :     if (i > 0)
     241                 :            :     {
     242         [ +  + ]:    7149460 :       pols.push_back(posFirst ? d_true : d_false);
     243                 :    7149460 :       lits.push_back(pivot);
     244         [ +  - ]:    7149460 :       Trace("sat-proof") << "{" << posFirst << "} [" << pivot << "] ";
     245                 :            :     }
     246         [ +  - ]:    7357534 :     Trace("sat-proof") << clause << "\n";
     247                 :    7357534 :   }
     248                 :     208074 :   args.push_back(nodeManager()->mkNode(Kind::SEXPR, pols));
     249                 :     208074 :   args.push_back(nodeManager()->mkNode(Kind::SEXPR, lits));
     250                 :            :   // clearing
     251                 :     208074 :   d_resLinks.clear();
     252                 :            :   // whether no-op
     253         [ -  + ]:     208074 :   if (children.size() == 1)
     254                 :            :   {
     255         [ -  - ]:          0 :     Trace("sat-proof") << "SatProofManager::endResChain: no-op. The conclusion "
     256                 :          0 :                        << conclusion << " is set-equal to premise "
     257                 :          0 :                        << children[0] << "\n";
     258                 :          0 :     return;
     259                 :            :   }
     260                 :            :   // whether trivial cycle
     261         [ +  + ]:    7563976 :   for (const Node& child : children)
     262                 :            :   {
     263         [ +  + ]:    7356446 :     if (conclusion == child)
     264                 :            :     {
     265         [ +  - ]:       1088 :       Trace("sat-proof")
     266                 :          0 :           << "SatProofManager::endResChain: no-op. The conclusion "
     267                 :        544 :           << conclusion << " is equal to a premise\n";
     268                 :        544 :       return;
     269                 :            :     }
     270                 :            :   }
     271                 :            :   // if this is a clause whose level is below the current user level, we save it
     272                 :            :   // to have its proof kept during backtracking
     273         [ +  + ]:     207530 :   if (clauseLevel < userContext()->getLevel())
     274                 :            :   {
     275                 :         43 :     d_optResLevels[conclusion] = clauseLevel;
     276         [ +  - ]:         86 :     Trace("sat-proof") << "SatProofManager::endResChain: ..clause's lvl "
     277                 :          0 :                        << clauseLevel << " below curr user level "
     278                 :         43 :                        << userContext()->getLevel() << "\n";
     279                 :            :   }
     280                 :            :   // since the conclusion can be both reordered and without duplicates and the
     281                 :            :   // SAT solver does not record this information, we use a CHAIN_M_RESOLUTION
     282                 :            :   // step, which bypasses these. Note that we could generate a chain resolution
     283                 :            :   // rule here by explicitly computing the detailed steps, but leave this for
     284                 :            :   // post-processing.
     285                 :     207530 :   ProofStep ps(ProofRule::CHAIN_M_RESOLUTION, children, args);
     286                 :            :   // note that we must tell the proof generator to overwrite if repeated
     287                 :     207530 :   d_resChainPg.addStep(conclusion, ps);
     288                 :            :   // the premises of this resolution may not have been justified yet, so we do
     289                 :            :   // not pass assumptions to check closedness
     290                 :     207530 :   d_resChains.addLazyStep(conclusion, &d_resChainPg);
     291 [ +  + ][ +  + ]:     210250 : }
         [ +  + ][ +  + ]
                 [ +  + ]
     292                 :            : 
     293                 :    3299721 : void SatProofManager::processRedundantLit(
     294                 :            :     SatLiteral lit,
     295                 :            :     const std::set<SatLiteral>& conclusionLits,
     296                 :            :     std::set<SatLiteral>& visited,
     297                 :            :     unsigned pos)
     298                 :            : {
     299         [ +  - ]:    6599442 :   Trace("sat-proof") << push
     300                 :          0 :                      << "SatProofManager::processRedundantLit: Lit: " << lit
     301                 :    3299721 :                      << "\n";
     302         [ +  + ]:    3299721 :   if (visited.count(lit))
     303                 :            :   {
     304         [ +  - ]:    1022949 :     Trace("sat-proof") << "already visited\n" << pop;
     305                 :    1225634 :     return;
     306                 :            :   }
     307                 :            :   Minisat::Solver::TCRef reasonRef =
     308                 :    2276772 :       d_solver->reason(Minisat::var(MinisatSatSolver::toMinisatLit(lit)));
     309         [ +  + ]:    2276772 :   if (reasonRef == Minisat::Solver::TCRef_Undef)
     310                 :            :   {
     311         [ +  - ]:     405370 :     Trace("sat-proof") << "unit, add link to lit " << lit << " at pos: " << pos
     312                 :          0 :                        << "\n"
     313                 :     202685 :                        << pop;
     314                 :     202685 :     visited.insert(lit);
     315                 :     202685 :     Node litNode = d_cnfStream->getNodeCache()[lit];
     316                 :     202685 :     bool negated = lit.isNegated();
     317 [ +  + ][ +  - ]:     202685 :     Assert(!negated || litNode.getKind() == Kind::NOT);
         [ -  + ][ -  + ]
                 [ -  - ]
     318                 :            : 
     319                 :     202685 :     d_resLinks.emplace(d_resLinks.begin() + pos,
     320                 :     202685 :                        d_cnfStream->getNodeCache()[~lit],
     321                 :     405370 :                        negated ? litNode[0] : litNode,
     322         [ +  + ]:     202685 :                        !negated);
     323                 :     202685 :     return;
     324                 :     202685 :   }
     325 [ -  + ][ -  + ]:    2074087 :   Assert(reasonRef < d_solver->ca.size())
                 [ -  - ]
     326                 :          0 :       << "reasonRef " << reasonRef << " and d_satSolver->ca.size() "
     327                 :          0 :       << d_solver->ca.size() << "\n";
     328                 :    2074087 :   const Minisat::Clause& reason = d_solver->ca[reasonRef];
     329         [ -  + ]:    2074087 :   if (TraceIsOn("sat-proof"))
     330                 :            :   {
     331         [ -  - ]:          0 :     Trace("sat-proof") << "reason: ";
     332                 :          0 :     printClause(reason);
     333         [ -  - ]:          0 :     Trace("sat-proof") << "\n";
     334                 :            :   }
     335                 :            :   // Since processRedundantLit calls can reallocate memory in the SAT solver due
     336                 :            :   // to explaining stuff, we directly get the literals and the clause node here
     337                 :    2074087 :   std::vector<SatLiteral> toProcess;
     338         [ +  + ]:    5772656 :   for (unsigned i = 1, size = reason.size(); i < size; ++i)
     339                 :            :   {
     340                 :    3698569 :     toProcess.push_back(MinisatSatSolver::toSatLiteral(reason[i]));
     341                 :            :   }
     342                 :    2074087 :   Node clauseNode = getClauseNode(reason);
     343                 :            :     // check if redundant literals in the reason. The first literal is the one we
     344                 :            :   // will be eliminating, so we check the others
     345         [ +  + ]:    5772656 :   for (unsigned i = 0, size = toProcess.size(); i < size; ++i)
     346                 :            :   {
     347                 :    3698569 :     SatLiteral satLit = toProcess[i];
     348                 :            :     // if literal does not occur in the conclusion we process it as well
     349         [ +  + ]:    3698569 :     if (!conclusionLits.count(satLit))
     350                 :            :     {
     351                 :    2393185 :       processRedundantLit(satLit, conclusionLits, visited, pos);
     352                 :            :     }
     353                 :            :   }
     354 [ -  + ][ -  + ]:    2074087 :   Assert(!visited.count(lit));
                 [ -  - ]
     355                 :    2074087 :   visited.insert(lit);
     356         [ +  - ]:    4148174 :   Trace("sat-proof") << "clause, add link to lit " << lit << " at pos: " << pos
     357                 :          0 :                      << "\n"
     358                 :    2074087 :                      << pop;
     359                 :            :   // add the step before steps for children. Note that the step is with the
     360                 :            :   // reason, not only with ~lit, since the learned clause is built under the
     361                 :            :   // assumption that the redundant literal is removed via the resolution with
     362                 :            :   // the explanation of its negation
     363                 :    2074087 :   Node litNode = d_cnfStream->getNodeCache()[lit];
     364                 :    2074087 :   bool negated = lit.isNegated();
     365 [ +  + ][ +  - ]:    2074087 :   Assert(!negated || litNode.getKind() == Kind::NOT);
         [ -  + ][ -  + ]
                 [ -  - ]
     366                 :    2074087 :   d_resLinks.emplace(d_resLinks.begin() + pos,
     367                 :            :                      clauseNode,
     368                 :    4148174 :                      negated ? litNode[0] : litNode,
     369         [ +  + ]:    2074087 :                      !negated);
     370                 :    2074087 : }
     371                 :            : 
     372                 :     154965 : void SatProofManager::explainLit(SatLiteral lit,
     373                 :            :                                  std::unordered_set<TNode>& premises)
     374                 :            : {
     375         [ +  - ]:     154965 :   Trace("sat-proof") << push << "SatProofManager::explainLit: Lit: " << lit;
     376                 :     154965 :   Node litNode = d_cnfStream->getNode(lit);
     377         [ +  - ]:     154965 :   Trace("sat-proof") << " [" << litNode << "]\n";
     378                 :            :   // We don't need to explain nodes who are inputs. Note that it's *necessary*
     379                 :            :   // to avoid attempting such explanations because they can introduce cycles at
     380                 :            :   // the node level. For example, if a literal l depends on an input clause C
     381                 :            :   // but a literal l', node-equivalent to C, depends on l, we may have a cycle
     382                 :            :   // when building the overall SAT proof.
     383         [ +  + ]:     154965 :   if (d_assumptions.contains(litNode))
     384                 :            :   {
     385         [ +  - ]:      69428 :     Trace("sat-proof")
     386                 :          0 :         << "SatProofManager::explainLit: input assumption, ABORT\n"
     387                 :      34714 :         << pop;
     388                 :      34714 :     return;
     389                 :            :   }
     390                 :            :   // We don't need to explain nodes who already have proofs.
     391                 :            :   //
     392                 :            :   // Note that if we had two literals for (= a b) and (= b a) and we had already
     393                 :            :   // a proof for (= a b) this test would return true for (= b a), which could
     394                 :            :   // lead to open proof. However we should never have two literals like this in
     395                 :            :   // the SAT solver since they'd be rewritten to the same one
     396         [ +  + ]:     120251 :   if (d_resChainPg.hasProofFor(litNode))
     397                 :            :   {
     398         [ +  - ]:      89940 :     Trace("sat-proof") << "SatProofManager::explainLit: already justified "
     399                 :          0 :                        << lit << ", ABORT\n"
     400                 :      44970 :                        << pop;
     401                 :      44970 :     return;
     402                 :            :   }
     403                 :            :   Minisat::Solver::TCRef reasonRef =
     404                 :      75281 :       d_solver->reason(Minisat::var(MinisatSatSolver::toMinisatLit(lit)));
     405         [ +  + ]:      75281 :   if (reasonRef == Minisat::Solver::TCRef_Undef)
     406                 :            :   {
     407         [ +  - ]:         79 :     Trace("sat-proof") << "SatProofManager::explainLit: no SAT reason\n" << pop;
     408                 :         79 :     return;
     409                 :            :   }
     410 [ -  + ][ -  + ]:      75202 :   Assert(reasonRef < d_solver->ca.size())
                 [ -  - ]
     411                 :          0 :       << "reasonRef " << reasonRef << " and d_satSolver->ca.size() "
     412                 :          0 :       << d_solver->ca.size() << "\n";
     413                 :      75202 :   const Minisat::Clause& reason = d_solver->ca[reasonRef];
     414                 :      75202 :   unsigned size = reason.size();
     415         [ -  + ]:      75202 :   if (TraceIsOn("sat-proof"))
     416                 :            :   {
     417         [ -  - ]:          0 :     Trace("sat-proof") << "SatProofManager::explainLit: with clause: ";
     418                 :          0 :     printClause(reason);
     419         [ -  - ]:          0 :     Trace("sat-proof") << "\n";
     420                 :            :   }
     421                 :            : #ifdef CVC5_ASSERTIONS
     422                 :            :   // pedantically check that the negation of the literal to explain *does not*
     423                 :            :   // occur in the reason, otherwise we will loop forever
     424         [ +  + ]:     275048 :   for (unsigned i = 0; i < size; ++i)
     425                 :            :   {
     426 [ -  + ][ -  + ]:     199846 :     AlwaysAssert(~MinisatSatSolver::toSatLiteral(reason[i]) != lit)
                 [ -  - ]
     427                 :          0 :         << "cyclic justification\n";
     428                 :            :   }
     429                 :            : #endif
     430                 :            :   // add the reason clause first
     431                 :     300808 :   std::vector<Node> children{getClauseNode(reason)}, args;
     432                 :            :   // save in the premises
     433                 :      75202 :   premises.insert(children.back());
     434                 :            :   // Since explainLit calls can reallocate memory in the
     435                 :            :   // SAT solver, we directly get the literals we need to explain so we no
     436                 :            :   // longer depend on the reference to reason
     437                 :      75202 :   std::vector<Node> toExplain{children.back().begin(), children.back().end()};
     438         [ +  - ]:      75202 :   Trace("sat-proof") << push;
     439                 :      75202 :   std::vector<Node> pols;
     440                 :      75202 :   std::vector<Node> lits;
     441         [ +  + ]:     275048 :   for (unsigned i = 0; i < size; ++i)
     442                 :            :   {
     443                 :            : #ifdef CVC5_ASSERTIONS
     444                 :            :     // pedantically make sure that the reason stays the same
     445                 :     199846 :     const Minisat::Clause& reloadedReason = d_solver->ca[reasonRef];
     446 [ -  + ][ -  + ]:     199846 :     AlwaysAssert(size == static_cast<unsigned>(reloadedReason.size()));
                 [ -  - ]
     447 [ -  + ][ -  + ]:     199846 :     AlwaysAssert(children[0] == getClauseNode(reloadedReason));
                 [ -  - ]
     448                 :            : #endif
     449                 :     199846 :     SatLiteral currLit = d_cnfStream->getTranslationCache()[toExplain[i]];
     450                 :            :     // ignore the lit we are trying to explain...
     451         [ +  + ]:     199846 :     if (currLit == lit)
     452                 :            :     {
     453                 :      75202 :       continue;
     454                 :            :     }
     455                 :     124644 :     std::unordered_set<TNode> childPremises;
     456                 :     124644 :     explainLit(~currLit, childPremises);
     457                 :            :     // save to resolution chain premises / arguments
     458 [ -  + ][ -  + ]:     124644 :     Assert(d_cnfStream->getNodeCache().find(currLit)
                 [ -  - ]
     459                 :            :            != d_cnfStream->getNodeCache().end());
     460                 :     124644 :     children.push_back(d_cnfStream->getNodeCache()[~currLit]);
     461                 :     124644 :     Node currLitNode = d_cnfStream->getNodeCache()[currLit];
     462                 :     124644 :     bool negated = currLit.isNegated();
     463 [ +  + ][ +  - ]:     124644 :     Assert(!negated || currLitNode.getKind() == Kind::NOT);
         [ -  + ][ -  + ]
                 [ -  - ]
     464                 :            :     // note this is the opposite of what is done in addResolutionStep. This is
     465                 :            :     // because here the clause, which contains the literal being analyzed, is
     466                 :            :     // the first clause rather than the second
     467         [ +  + ]:     124644 :     pols.push_back(!negated ? d_true : d_false);
     468         [ +  + ]:     124644 :     lits.push_back(negated ? currLitNode[0] : currLitNode);
     469                 :            :     // add child premises and the child itself
     470                 :     124644 :     premises.insert(childPremises.begin(), childPremises.end());
     471                 :     124644 :     premises.insert(d_cnfStream->getNodeCache()[~currLit]);
     472                 :     124644 :   }
     473         [ -  + ]:      75202 :   if (TraceIsOn("sat-proof"))
     474                 :            :   {
     475         [ -  - ]:          0 :     Trace("sat-proof") << pop << "SatProofManager::explainLit: chain_res for "
     476                 :          0 :                        << lit << ", " << litNode << " with clauses:\n";
     477         [ -  - ]:          0 :     for (unsigned i = 0, csize = children.size(); i < csize; ++i)
     478                 :            :     {
     479         [ -  - ]:          0 :       Trace("sat-proof") << "SatProofManager::explainLit:   " << children[i];
     480         [ -  - ]:          0 :       if (i > 0)
     481                 :            :       {
     482         [ -  - ]:          0 :         Trace("sat-proof") << " [" << lits[i] << ", " << pols[i] << "]";
     483                 :            :       }
     484         [ -  - ]:          0 :       Trace("sat-proof") << "\n";
     485                 :            :     }
     486                 :            :   }
     487                 :            :   // if justification of children contains the expected conclusion, avoid the
     488                 :            :   // cyclic proof by aborting.
     489         [ -  + ]:      75202 :   if (premises.count(litNode))
     490                 :            :   {
     491         [ -  - ]:          0 :     Trace("sat-proof") << "SatProofManager::explainLit: CYCLIC PROOF of " << lit
     492                 :          0 :                        << " [" << litNode << "], ABORT\n"
     493                 :          0 :                        << pop;
     494                 :          0 :     return;
     495                 :            :   }
     496         [ +  - ]:      75202 :   Trace("sat-proof") << pop;
     497                 :            :   // create step
     498                 :      75202 :   args.push_back(litNode);
     499                 :      75202 :   args.push_back(nodeManager()->mkNode(Kind::SEXPR, pols));
     500                 :      75202 :   args.push_back(nodeManager()->mkNode(Kind::SEXPR, lits));
     501                 :      75202 :   ProofStep ps(ProofRule::CHAIN_M_RESOLUTION, children, args);
     502                 :      75202 :   d_resChainPg.addStep(litNode, ps);
     503                 :            :   // the premises in the limit of the justification may correspond to other
     504                 :            :   // links in the chain which have, themselves, literals yet to be justified. So
     505                 :            :   // we are not ready yet to check closedness w.r.t. CNF transformation of the
     506                 :            :   // preprocessed assertions
     507                 :      75202 :   d_resChains.addLazyStep(litNode, &d_resChainPg);
     508 [ +  - ][ +  - ]:     154965 : }
         [ +  - ][ +  - ]
         [ +  - ][ +  + ]
     509                 :            : 
     510                 :       9532 : void SatProofManager::finalizeProof(Node inConflictNode,
     511                 :            :                                     const std::vector<SatLiteral>& inConflict)
     512                 :            : {
     513         [ +  - ]:      19064 :   Trace("sat-proof")
     514                 :          0 :       << "SatProofManager::finalizeProof: conflicting clause node: "
     515                 :       9532 :       << inConflictNode << "\n";
     516                 :            :   // nothing to do
     517         [ +  + ]:       9532 :   if (inConflictNode == d_false)
     518                 :            :   {
     519                 :       3571 :     return;
     520                 :            :   }
     521         [ -  + ]:       5961 :   if (TraceIsOn("sat-proof-debug2"))
     522                 :            :   {
     523         [ -  - ]:          0 :     Trace("sat-proof-debug2")
     524                 :          0 :         << push << "SatProofManager::finalizeProof: saved proofs in chain:\n";
     525                 :          0 :     std::map<Node, std::shared_ptr<ProofNode>> links = d_resChains.getLinks();
     526                 :          0 :     std::unordered_set<Node> skip;
     527         [ -  - ]:          0 :     for (const std::pair<const Node, std::shared_ptr<ProofNode>>& link : links)
     528                 :            :     {
     529         [ -  - ]:          0 :       if (skip.count(link.first))
     530                 :            :       {
     531                 :          0 :         continue;
     532                 :            :       }
     533                 :          0 :       auto it = d_cnfStream->getTranslationCache().find(link.first);
     534         [ -  - ]:          0 :       if (it != d_cnfStream->getTranslationCache().end())
     535                 :            :       {
     536         [ -  - ]:          0 :         Trace("sat-proof-debug2")
     537                 :          0 :             << "SatProofManager::finalizeProof:  " << it->second;
     538                 :            :       }
     539                 :            :       // a refl step added due to double elim negation, ignore
     540         [ -  - ]:          0 :       else if (link.second->getRule() == ProofRule::REFL)
     541                 :            :       {
     542                 :          0 :         continue;
     543                 :            :       }
     544                 :            :       // a clause
     545                 :            :       else
     546                 :            :       {
     547         [ -  - ]:          0 :         Trace("sat-proof-debug2") << "SatProofManager::finalizeProof:";
     548                 :          0 :         Assert(link.first.getKind() == Kind::OR) << link.first;
     549         [ -  - ]:          0 :         for (const Node& n : link.first)
     550                 :            :         {
     551                 :          0 :           it = d_cnfStream->getTranslationCache().find(n);
     552                 :          0 :           Assert(it != d_cnfStream->getTranslationCache().end());
     553         [ -  - ]:          0 :           Trace("sat-proof-debug2") << it->second << " ";
     554                 :          0 :         }
     555                 :            :       }
     556         [ -  - ]:          0 :       Trace("sat-proof-debug2") << "\n";
     557         [ -  - ]:          0 :       Trace("sat-proof-debug2")
     558                 :          0 :           << "SatProofManager::finalizeProof: " << link.first << "\n";
     559                 :            :       // get resolution
     560                 :          0 :       Node cur = link.first;
     561                 :          0 :       std::shared_ptr<ProofNode> pfn = link.second;
     562         [ -  - ]:          0 :       while (pfn->getRule() != ProofRule::CHAIN_M_RESOLUTION)
     563                 :            :       {
     564                 :          0 :         Assert(pfn->getChildren().size() == 1
     565                 :            :                && pfn->getChildren()[0]->getRule() == ProofRule::ASSUME)
     566                 :          0 :             << *link.second.get() << "\n"
     567                 :          0 :             << *pfn.get();
     568                 :          0 :         cur = pfn->getChildren()[0]->getResult();
     569                 :            :         // retrieve justification of assumption in the links
     570                 :          0 :         Assert(links.find(cur) != links.end());
     571                 :          0 :         pfn = links[cur];
     572                 :            :         // ignore it in the rest of the outside loop
     573                 :          0 :         skip.insert(cur);
     574                 :            :       }
     575                 :          0 :       std::vector<Node> fassumps;
     576                 :          0 :       expr::getFreeAssumptions(pfn.get(), fassumps);
     577         [ -  - ]:          0 :       Trace("sat-proof-debug2") << push;
     578         [ -  - ]:          0 :       for (const Node& fa : fassumps)
     579                 :            :       {
     580         [ -  - ]:          0 :         Trace("sat-proof-debug2") << "SatProofManager::finalizeProof:   - ";
     581                 :          0 :         it = d_cnfStream->getTranslationCache().find(fa);
     582         [ -  - ]:          0 :         if (it != d_cnfStream->getTranslationCache().end())
     583                 :            :         {
     584         [ -  - ]:          0 :           Trace("sat-proof-debug2") << it->second << "\n";
     585                 :          0 :           continue;
     586                 :            :         }
     587                 :            :         // then it's a clause
     588                 :          0 :         Assert(fa.getKind() == Kind::OR);
     589         [ -  - ]:          0 :         for (const Node& n : fa)
     590                 :            :         {
     591                 :          0 :           it = d_cnfStream->getTranslationCache().find(n);
     592                 :          0 :           Assert(it != d_cnfStream->getTranslationCache().end());
     593         [ -  - ]:          0 :           Trace("sat-proof-debug2") << it->second << " ";
     594                 :          0 :         }
     595         [ -  - ]:          0 :         Trace("sat-proof-debug2") << "\n";
     596                 :            :       }
     597         [ -  - ]:          0 :       Trace("sat-proof-debug2") << pop;
     598         [ -  - ]:          0 :       Trace("sat-proof-debug2")
     599                 :          0 :           << "SatProofManager::finalizeProof:  " << *pfn.get() << "\n=======\n";
     600                 :            :       ;
     601                 :          0 :     }
     602         [ -  - ]:          0 :     Trace("sat-proof-debug2") << pop;
     603                 :          0 :   }
     604                 :            :   // We will resolve away of the literals l_1...l_n in inConflict. At this point
     605                 :            :   // each ~l_i must be either explainable, the result of a previously saved
     606                 :            :   // resolution chain, or an input. In account of it possibly being the first,
     607                 :            :   // we call explainLit on each ~l_i while accumulating the children and
     608                 :            :   // arguments for the resolution step to conclude false.
     609                 :      23844 :   std::vector<Node> children{inConflictNode}, args;
     610                 :       5961 :   std::unordered_set<TNode> premises;
     611                 :       5961 :   std::vector<Node> pols;
     612                 :       5961 :   std::vector<Node> lits;
     613         [ +  + ]:      27861 :   for (unsigned i = 0, size = inConflict.size(); i < size; ++i)
     614                 :            :   {
     615 [ -  + ][ -  + ]:      21900 :     Assert(d_cnfStream->getNodeCache().find(inConflict[i])
                 [ -  - ]
     616                 :            :            != d_cnfStream->getNodeCache().end());
     617                 :      21900 :     std::unordered_set<TNode> childPremises;
     618                 :      21900 :     explainLit(~inConflict[i], childPremises);
     619                 :      21900 :     Node negatedLitNode = d_cnfStream->getNodeCache()[~inConflict[i]];
     620                 :            :     // save to resolution chain premises / arguments
     621                 :      21900 :     children.push_back(negatedLitNode);
     622                 :      21900 :     Node litNode = d_cnfStream->getNodeCache()[inConflict[i]];
     623                 :      21900 :     bool negated = inConflict[i].isNegated();
     624 [ +  + ][ +  - ]:      21900 :     Assert(!negated || litNode.getKind() == Kind::NOT);
         [ -  + ][ -  + ]
                 [ -  - ]
     625                 :            :     // note this is the opposite of what is done in addResolutionStep. This is
     626                 :            :     // because here the clause, which contains the literal being analyzed, is
     627                 :            :     // the first clause rather than the second
     628         [ +  + ]:      21900 :     pols.push_back(!negated ? d_true : d_false);
     629         [ +  + ]:      21900 :     lits.push_back(negated ? litNode[0] : litNode);
     630                 :            :     // add child premises and the child itself
     631                 :      21900 :     premises.insert(childPremises.begin(), childPremises.end());
     632                 :      21900 :     premises.insert(negatedLitNode);
     633         [ +  - ]:      21900 :     Trace("sat-proof") << "===========\n";
     634                 :      21900 :   }
     635         [ -  + ]:       5961 :   if (TraceIsOn("sat-proof"))
     636                 :            :   {
     637         [ -  - ]:          0 :     Trace("sat-proof") << "SatProofManager::finalizeProof: chain_res for false "
     638                 :          0 :                           "with clauses:\n";
     639         [ -  - ]:          0 :     for (unsigned i = 0, size = children.size(); i < size; ++i)
     640                 :            :     {
     641         [ -  - ]:          0 :       Trace("sat-proof") << "SatProofManager::finalizeProof:   " << children[i];
     642         [ -  - ]:          0 :       if (i > 0)
     643                 :            :       {
     644         [ -  - ]:          0 :         Trace("sat-proof") << " [" << args[i - 1] << "]";
     645                 :            :       }
     646         [ -  - ]:          0 :       Trace("sat-proof") << "\n";
     647                 :            :     }
     648                 :            :   }
     649                 :            :   // create step
     650                 :       5961 :   args.push_back(d_false);
     651                 :       5961 :   args.push_back(nodeManager()->mkNode(Kind::SEXPR, pols));
     652                 :       5961 :   args.push_back(nodeManager()->mkNode(Kind::SEXPR, lits));
     653                 :       5961 :   ProofStep ps(ProofRule::CHAIN_M_RESOLUTION, children, args);
     654                 :       5961 :   d_resChainPg.addStep(d_false, ps);
     655                 :            :   // not yet ready to check closedness because maybe only now we will justify
     656                 :            :   // literals used in resolutions
     657                 :       5961 :   d_resChains.addLazyStep(d_false, &d_resChainPg);
     658                 :            :   // Fix point justification of literals in leaves of the proof of false
     659                 :            :   bool expanded;
     660         [ +  + ]:       7174 :   do
     661                 :            :   {
     662                 :       7174 :     expanded = false;
     663         [ +  - ]:       7174 :     Trace("sat-proof") << "expand assumptions to prove false\n";
     664                 :       7174 :     std::shared_ptr<ProofNode> pfn = d_resChains.getProofFor(d_false);
     665 [ -  + ][ -  + ]:       7174 :     Assert(pfn);
                 [ -  - ]
     666         [ -  + ]:       7174 :     if (TraceIsOn("sat-proof-debug"))
     667                 :            :     {
     668                 :          0 :       std::stringstream ss;
     669                 :          0 :       pfn->printDebug(ss, true);
     670                 :          0 :       Trace("sat-proof-debug") << "sat proof of false: " << ss.str() << "\n";
     671                 :          0 :     }
     672                 :       7174 :     std::vector<Node> fassumps;
     673                 :       7174 :     expr::getFreeAssumptions(pfn.get(), fassumps);
     674         [ -  + ]:       7174 :     if (TraceIsOn("sat-proof"))
     675                 :            :     {
     676         [ -  - ]:          0 :       for (const Node& fa : fassumps)
     677                 :            :       {
     678                 :          0 :         auto it = d_cnfStream->getTranslationCache().find(fa);
     679         [ -  - ]:          0 :         if (it != d_cnfStream->getTranslationCache().end())
     680                 :            :         {
     681         [ -  - ]:          0 :           Trace("sat-proof") << "- " << it->second << "\n";
     682         [ -  - ]:          0 :           Trace("sat-proof") << "  - " << fa << "\n";
     683                 :          0 :           continue;
     684                 :            :         }
     685                 :            :         // then it's a clause
     686                 :          0 :         std::stringstream ss;
     687                 :          0 :         Assert(fa.getKind() == Kind::OR);
     688         [ -  - ]:          0 :         for (const Node& n : fa)
     689                 :            :         {
     690                 :          0 :           it = d_cnfStream->getTranslationCache().find(n);
     691                 :          0 :           Assert(it != d_cnfStream->getTranslationCache().end());
     692                 :          0 :           ss << it->second << " ";
     693                 :          0 :         }
     694                 :          0 :         Trace("sat-proof") << "- " << ss.str() << "\n";
     695         [ -  - ]:          0 :         Trace("sat-proof") << "  - " << fa << "\n";
     696                 :          0 :       }
     697                 :            :     }
     698                 :            : 
     699                 :            :     // for each assumption, see if it has a reason
     700         [ +  + ]:     650343 :     for (const Node& fa : fassumps)
     701                 :            :     {
     702                 :            :       // ignore already processed assumptions
     703         [ +  + ]:     643169 :       if (premises.count(fa))
     704                 :            :       {
     705         [ +  - ]:     140121 :         Trace("sat-proof") << "already processed assumption " << fa << "\n";
     706                 :     634748 :         continue;
     707                 :            :       }
     708                 :            :       // ignore input assumptions. This is necessary to avoid rare collisions
     709                 :            :       // between input clauses and literals that are equivalent at the node
     710                 :            :       // level. In trying to justify the literal below, if it was previously
     711                 :            :       // propagated (say, in a previous check-sat call that survived the
     712                 :            :       // user-context changes) but no longer holds, then we may introduce a
     713                 :            :       // bogus proof for it, rather than keeping it as an input.
     714         [ +  + ]:     503048 :       if (d_assumptions.contains(fa))
     715                 :            :       {
     716         [ +  - ]:     494627 :         Trace("sat-proof") << "input assumption " << fa << "\n";
     717                 :     494627 :         continue;
     718                 :            :       }
     719                 :            :       // ignore non-literals
     720                 :       8421 :       auto it = d_cnfStream->getTranslationCache().find(fa);
     721         [ -  + ]:       8421 :       if (it == d_cnfStream->getTranslationCache().end())
     722                 :            :       {
     723         [ -  - ]:          0 :         Trace("sat-proof") << "no lit assumption " << fa << "\n";
     724                 :          0 :         premises.insert(fa);
     725                 :          0 :         continue;
     726                 :            :       }
     727         [ +  - ]:      16842 :       Trace("sat-proof") << "lit assumption (" << it->second << "), " << fa
     728                 :       8421 :                          << "\n";
     729                 :            :       // mark another iteration for the loop, as some resolution link may be
     730                 :            :       // connected because of the new justifications
     731                 :       8421 :       expanded = true;
     732                 :       8421 :       std::unordered_set<TNode> childPremises;
     733                 :       8421 :       explainLit(it->second, childPremises);
     734                 :            :       // add the premises used in the justification. We know they will have
     735                 :            :       // been as expanded as possible
     736                 :       8421 :       premises.insert(childPremises.begin(), childPremises.end());
     737                 :            :       // add free assumption itself
     738                 :       8421 :       premises.insert(fa);
     739                 :       8421 :     }
     740                 :       7174 :   } while (expanded);
     741                 :       5961 : }
     742                 :            : 
     743                 :        387 : void SatProofManager::storeUnitConflict(Minisat::Lit inConflict)
     744                 :            : {
     745 [ -  + ][ -  + ]:        387 :   Assert(d_conflictLit == undefSatLiteral);
                 [ -  - ]
     746                 :        387 :   d_conflictLit = MinisatSatSolver::toSatLiteral(inConflict);
     747                 :        387 : }
     748                 :            : 
     749                 :        387 : void SatProofManager::finalizeProof()
     750                 :            : {
     751 [ -  + ][ -  + ]:        387 :   Assert(d_conflictLit != undefSatLiteral);
                 [ -  - ]
     752         [ +  - ]:        774 :   Trace("sat-proof")
     753                 :          0 :       << "SatProofManager::finalizeProof: conflicting (lazy) satLit: "
     754                 :        387 :       << d_conflictLit << "\n";
     755                 :        387 :   finalizeProof(d_cnfStream->getNode(d_conflictLit), {d_conflictLit});
     756                 :            :   // reset since if in incremental mode this may be used again
     757                 :        387 :   d_conflictLit = undefSatLiteral;
     758                 :        387 : }
     759                 :            : 
     760                 :       3763 : void SatProofManager::finalizeProof(Minisat::Lit inConflict, bool adding)
     761                 :            : {
     762                 :       3763 :   SatLiteral satLit = MinisatSatSolver::toSatLiteral(inConflict);
     763         [ +  - ]:       7526 :   Trace("sat-proof") << "SatProofManager::finalizeProof: conflicting satLit: "
     764                 :       3763 :                      << satLit << "\n";
     765                 :       3763 :   Node clauseNode = d_cnfStream->getNode(satLit);
     766         [ +  - ]:       3763 :   if (adding)
     767                 :            :   {
     768                 :       7526 :     registerSatAssumptions({clauseNode});
     769                 :            :   }
     770                 :       3763 :   finalizeProof(clauseNode, {satLit});
     771                 :       3763 : }
     772                 :            : 
     773                 :       5382 : void SatProofManager::finalizeProof(const Minisat::Clause& inConflict,
     774                 :            :                                     bool adding)
     775                 :            : {
     776         [ -  + ]:       5382 :   if (TraceIsOn("sat-proof"))
     777                 :            :   {
     778         [ -  - ]:          0 :     Trace("sat-proof")
     779                 :          0 :         << "SatProofManager::finalizeProof: conflicting clause: ";
     780                 :          0 :     printClause(inConflict);
     781         [ -  - ]:          0 :     Trace("sat-proof") << "\n";
     782                 :            :   }
     783                 :       5382 :   std::vector<SatLiteral> clause;
     784         [ +  + ]:      26703 :   for (unsigned i = 0, size = inConflict.size(); i < size; ++i)
     785                 :            :   {
     786                 :      21321 :     clause.push_back(MinisatSatSolver::toSatLiteral(inConflict[i]));
     787                 :            :   }
     788                 :       5382 :   Node clauseNode = getClauseNode(inConflict);
     789         [ +  + ]:       5382 :   if (adding)
     790                 :            :   {
     791                 :        230 :     registerSatAssumptions({clauseNode});
     792                 :            :   }
     793                 :       5382 :   finalizeProof(clauseNode, clause);
     794                 :       5382 : }
     795                 :            : 
     796                 :       9417 : std::shared_ptr<ProofNode> SatProofManager::getProof()
     797                 :            : {
     798                 :       9417 :   std::shared_ptr<ProofNode> pfn = d_resChains.getProofFor(d_false);
     799         [ +  + ]:       9417 :   if (!pfn)
     800                 :            :   {
     801                 :       3072 :     pfn = d_env.getProofNodeManager()->mkAssume(d_false);
     802                 :            :   }
     803                 :       9417 :   return pfn;
     804                 :          0 : }
     805                 :            : 
     806                 :      75112 : void SatProofManager::registerSatLitAssumption(Minisat::Lit lit)
     807                 :            : {
     808         [ +  - ]:     150224 :   Trace("sat-proof") << "SatProofManager::registerSatLitAssumption: - "
     809 [ -  + ][ -  - ]:      75112 :                      << d_cnfStream->getNode(
     810                 :      75112 :                             MinisatSatSolver::toSatLiteral(lit))
     811                 :      75112 :                      << "\n";
     812                 :      75112 :   d_assumptions.insert(
     813                 :     150224 :       d_cnfStream->getNode(MinisatSatSolver::toSatLiteral(lit)));
     814                 :      75112 : }
     815                 :            : 
     816                 :    3860785 : void SatProofManager::registerSatAssumptions(const std::vector<Node>& assumps)
     817                 :            : {
     818         [ +  + ]:    7721570 :   for (const Node& a : assumps)
     819                 :            :   {
     820         [ +  - ]:    7721570 :     Trace("sat-proof") << "SatProofManager::registerSatAssumptions: - " << a
     821                 :    3860785 :                        << "\n";
     822                 :    3860785 :     d_assumptions.insert(a);
     823                 :            :   }
     824                 :    3860785 : }
     825                 :            : 
     826                 :        100 : void SatProofManager::notifyAssumptionInsertedAtLevel(int level,
     827                 :            :                                                       Node assumption)
     828                 :            : {
     829 [ -  + ][ -  + ]:        100 :   Assert(d_assumptions.contains(assumption));
                 [ -  - ]
     830                 :        100 :   d_assumptionLevels[level].push_back(assumption);
     831                 :        100 : }
     832                 :            : 
     833                 :        961 : void SatProofManager::notifyPop()
     834                 :            : {
     835                 :        961 :   for (context::CDHashMap<Node, int>::const_iterator it =
     836                 :        961 :            d_optResLevels.begin();
     837         [ +  + ]:       1019 :        it != d_optResLevels.end();
     838                 :         58 :        ++it)
     839                 :            :   {
     840                 :            :     // Save into map the proof of the resolution chain. We copy to prevent the
     841                 :            :     // proof node saved to be restored of suffering unintended updates. This is
     842                 :            :     // *necessary*.
     843                 :            :     std::shared_ptr<ProofNode> clauseResPf =
     844                 :        116 :         d_resChains.getProofFor(it->first)->clone();
     845 [ +  - ][ +  - ]:         58 :     Assert(clauseResPf && clauseResPf->getRule() != ProofRule::ASSUME);
         [ -  + ][ -  + ]
                 [ -  - ]
     846                 :         58 :     d_optResProofs[it->second].push_back(clauseResPf);
     847                 :         58 :   }
     848                 :        961 : }
     849                 :            : 
     850                 :         83 : void SatProofManager::notifyCurrPropagationInsertedAtLevel(uint32_t explLevel)
     851                 :            : {
     852 [ -  + ][ -  + ]:         83 :   Assert(explLevel < (userContext()->getLevel() - 1));
                 [ -  - ]
     853                 :         83 :   Node currProp = d_ppm->getLastExplainedPropagation();
     854 [ -  + ][ -  + ]:         83 :   Assert(!currProp.isNull());
                 [ -  - ]
     855                 :         83 :   LazyCDProof* pf = d_ppm->getCnfProof();
     856         [ +  - ]:        166 :   Trace("cnf") << "Need to save curr propagation " << currProp
     857                 :          0 :                << "'s proof in level " << explLevel + 1
     858                 :          0 :                << " despite being currently in level "
     859                 :         83 :                << userContext()->getLevel() << "\n";
     860                 :            :   // Save into map the proof of the processed propagation. Note that
     861                 :            :   // propagations must be explained eagerly, since their justification depends
     862                 :            :   // on the theory engine and may be different if we only get its proof when the
     863                 :            :   // SAT solver pops the user context. Not doing this may lead to open proofs.
     864                 :            :   //
     865                 :            :   // It's also necessary to copy the proof node, so we prevent unintended
     866                 :            :   // updates to the saved proof. Not doing this may also lead to open proofs.
     867                 :            :   std::shared_ptr<ProofNode> currPropagationProcPf =
     868                 :        166 :       pf->getProofFor(currProp)->clone();
     869 [ -  + ][ -  + ]:         83 :   Assert(currPropagationProcPf->getRule() != ProofRule::ASSUME);
                 [ -  - ]
     870         [ +  - ]:        166 :   Trace("cnf-debug") << "\t..saved pf {" << currPropagationProcPf << "} "
     871                 :         83 :                      << *currPropagationProcPf.get() << "\n";
     872                 :         83 :   d_optClausesPfs[explLevel + 1].push_back(currPropagationProcPf);
     873                 :            :   // Notify this proof manager that the propagation (which is a SAT assumption)
     874                 :            :   // had its level optimized
     875                 :         83 :   notifyAssumptionInsertedAtLevel(explLevel, currProp);
     876                 :            :   // Reset
     877                 :         83 :   d_ppm->resetLastExplainedPropagation();
     878                 :         83 : }
     879                 :            : 
     880                 :         17 : void SatProofManager::notifyClauseInsertedAtLevel(const SatClause& clause,
     881                 :            :                                                   uint32_t clLevel)
     882                 :            : {
     883         [ +  - ]:         34 :   Trace("cnf") << "Need to save clause " << clause << " in level "
     884                 :          0 :                << clLevel + 1 << " despite being currently in level "
     885                 :         17 :                << userContext()->getLevel() << "\n";
     886                 :         17 :   LazyCDProof* pf = d_ppm->getCnfProof();
     887                 :         17 :   Node clauseNode = getClauseNode(clause);
     888         [ +  - ]:         17 :   Trace("cnf") << "Node equivalent: " << clauseNode << "\n";
     889 [ -  + ][ -  + ]:         17 :   Assert(clLevel < (userContext()->getLevel() - 1));
                 [ -  - ]
     890                 :            :   // As above, also justify eagerly.
     891                 :         34 :   std::shared_ptr<ProofNode> clauseCnfPf = pf->getProofFor(clauseNode)->clone();
     892 [ -  + ][ -  + ]:         17 :   Assert(clauseCnfPf->getRule() != ProofRule::ASSUME);
                 [ -  - ]
     893                 :         17 :   d_optClausesPfs[clLevel + 1].push_back(clauseCnfPf);
     894                 :            :   // Notify SAT proof manager that the propagation (which is a SAT assumption)
     895                 :            :   // had its level optimized
     896                 :         17 :   notifyAssumptionInsertedAtLevel(clLevel, clauseNode);
     897                 :         17 : }
     898                 :            : 
     899                 :         17 : Node SatProofManager::getClauseNode(const SatClause& clause)
     900                 :            : {
     901                 :         17 :   std::vector<Node> clauseNodes;
     902         [ +  + ]:        111 :   for (size_t i = 0, size = clause.size(); i < size; ++i)
     903                 :            :   {
     904                 :         94 :     SatLiteral satLit = clause[i];
     905                 :         94 :     clauseNodes.push_back(d_cnfStream->getNode(satLit));
     906                 :            :   }
     907                 :            :   // order children by node id
     908                 :         17 :   std::sort(clauseNodes.begin(), clauseNodes.end());
     909                 :         34 :   return nodeManager()->mkNode(Kind::OR, clauseNodes);
     910                 :         17 : }
     911                 :            : 
     912                 :            : }  // namespace prop
     913                 :            : }  // namespace cvc5::internal

Generated by: LCOV version 1.14