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: 374 513 72.9 %
Date: 2026-02-15 11:43:36 Functions: 23 24 95.8 %
Branches: 221 518 42.7 %

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

Generated by: LCOV version 1.14