LCOV - code coverage report
Current view: top level - buildbot/coverage/build/src/proof - lazy_proof.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 106 111 95.5 %
Date: 2026-08-02 10:35:41 Functions: 8 8 100.0 %
Branches: 78 120 65.0 %

           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 lazy proof utility.
      11                 :            :  */
      12                 :            : 
      13                 :            : #include "proof/lazy_proof.h"
      14                 :            : 
      15                 :            : #include "proof/proof_ensure_closed.h"
      16                 :            : #include "proof/proof_node.h"
      17                 :            : #include "proof/proof_node_manager.h"
      18                 :            : 
      19                 :            : using namespace cvc5::internal::kind;
      20                 :            : 
      21                 :            : namespace cvc5::internal {
      22                 :            : 
      23                 :    1513696 : LazyCDProof::LazyCDProof(Env& env,
      24                 :            :                          ProofGenerator* dpg,
      25                 :            :                          context::Context* c,
      26                 :            :                          const std::string& name,
      27                 :            :                          bool autoSym,
      28                 :    1513696 :                          bool doCache)
      29                 :            :     : CDProof(env, c, name, autoSym),
      30                 :    1513696 :       d_gens(c ? c : &d_context),
      31                 :    1513696 :       d_defaultGen(dpg),
      32                 :    1513696 :       d_doCache(doCache),
      33 [ +  + ][ +  + ]:    3027392 :       d_allVisited(c ? c : &d_context)
      34                 :            : {
      35                 :    1513696 : }
      36                 :            : 
      37                 :    1855432 : LazyCDProof::~LazyCDProof() {}
      38                 :            : 
      39                 :    7734054 : std::shared_ptr<ProofNode> LazyCDProof::getProofFor(Node fact)
      40                 :            : {
      41         [ +  - ]:    7734054 :   Trace("lazy-cdproof") << "LazyCDProof::mkLazyProof " << fact << std::endl;
      42                 :            :   // make the proof, which should always be non-null, since we construct an
      43                 :            :   // assumption in the worst case.
      44                 :    7734054 :   std::shared_ptr<ProofNode> opf = CDProof::getProofFor(fact);
      45 [ -  + ][ -  + ]:    7734054 :   Assert(opf != nullptr);
                 [ -  - ]
      46         [ +  + ]:    7734054 :   if (!hasGenerators())
      47                 :            :   {
      48         [ +  - ]:    2854184 :     Trace("lazy-cdproof") << "...no generators, finished" << std::endl;
      49                 :            :     // optimization: no generators, we are done
      50                 :    2854184 :     return opf;
      51                 :            :   }
      52                 :            :   // otherwise, we traverse the proof opf and fill in the ASSUME leafs that
      53                 :            :   // have generators
      54                 :    4879870 :   std::unordered_set<ProofNode*> visited;
      55                 :    4879870 :   std::vector<ProofNode*> visit;
      56                 :            :   ProofNode* cur;
      57                 :    4879870 :   visit.push_back(opf.get());
      58                 :            :   bool alreadyVisited;
      59                 :            :   do
      60                 :            :   {
      61                 :   19572106 :     cur = visit.back();
      62                 :   19572106 :     visit.pop_back();
      63         [ +  - ]:   19572106 :     if (d_doCache)
      64                 :            :     {
      65                 :   19572106 :       alreadyVisited = d_allVisited.find(cur) != d_allVisited.end();
      66                 :            :     }
      67                 :            :     else
      68                 :            :     {
      69                 :          0 :       alreadyVisited = visited.find(cur) != visited.end();
      70                 :            :     }
      71                 :            : 
      72         [ +  + ]:   19572106 :     if (!alreadyVisited)
      73                 :            :     {
      74         [ +  - ]:   14292050 :       if (d_doCache)
      75                 :            :       {
      76                 :   14292050 :         d_allVisited.insert(cur);
      77                 :            :       }
      78                 :            :       else
      79                 :            :       {
      80                 :          0 :         visited.insert(cur);
      81                 :            :       }
      82                 :   14292050 :       Node cfact = cur->getResult();
      83         [ +  + ]:   14292050 :       if (getProof(cfact).get() != cur)
      84                 :            :       {
      85                 :            :         // We don't own this proof, skip it. This is to ensure that this method
      86                 :            :         // is idempotent, since it may be the case that a previous call to
      87                 :            :         // getProofFor connected a proof from a proof generator as a child of
      88                 :            :         // a ProofNode in the range of the map in CDProof. Thus, this ensures
      89                 :            :         // we don't touch such proofs.
      90         [ +  - ]:     181595 :         Trace("lazy-cdproof") << "...skip unowned proof" << std::endl;
      91                 :            :       }
      92         [ +  + ]:   14110455 :       else if (cur->getRule() == ProofRule::ASSUME)
      93                 :            :       {
      94                 :    6234846 :         bool isSym = false;
      95                 :    6234846 :         ProofGenerator* pg = getGeneratorFor(cfact, isSym);
      96         [ +  + ]:    6234846 :         if (pg != nullptr)
      97                 :            :         {
      98         [ +  - ]:    9211626 :           Trace("lazy-cdproof")
      99 [ -  + ][ -  - ]:    4605813 :               << "LazyCDProof: Call generator " << pg->identify()
     100                 :    4605813 :               << " for assumption " << cfact << std::endl;
     101 [ +  + ][ +  + ]:    4605813 :           Node cfactGen = isSym ? CDProof::getSymmFact(cfact) : cfact;
                 [ -  - ]
     102 [ -  + ][ -  + ]:    4605813 :           Assert(!cfactGen.isNull());
                 [ -  - ]
     103                 :            :           // Do not use the addProofTo interface, instead use the update node
     104                 :            :           // interface, since this ensures that we don't take ownership for
     105                 :            :           // the current proof. Instead, it is only linked, and ignored on
     106                 :            :           // future calls to getProofFor due to the check above.
     107                 :    4605813 :           std::shared_ptr<ProofNode> pgc = pg->getProofFor(cfactGen);
     108                 :            :           // If the proof was null, then the update is not performed. This is
     109                 :            :           // not considered an error, since this behavior is equivalent to
     110                 :            :           // if pg had provided the proof (ASSUME cfactGen). Ensuring the
     111                 :            :           // proper behavior wrt closed proofs should be done outside this
     112                 :            :           // method.
     113         [ +  - ]:    4605813 :           if (pgc != nullptr)
     114                 :            :           {
     115         [ +  - ]:    9211626 :             Trace("lazy-cdproof-gen")
     116                 :    4605813 :                 << "LazyCDProof: stored proof: " << *pgc.get() << std::endl;
     117                 :            : 
     118         [ +  + ]:    4605813 :             if (isSym)
     119                 :            :             {
     120         [ +  + ]:      85086 :               if (pgc->getRule() == ProofRule::SYMM)
     121                 :            :               {
     122                 :          9 :                 getManager()->updateNode(cur, pgc->getChildren()[0].get());
     123                 :            :               }
     124                 :            :               else
     125                 :            :               {
     126                 :     170154 :                 getManager()->updateNode(cur, ProofRule::SYMM, {pgc}, {});
     127                 :            :               }
     128                 :            :             }
     129                 :            :             else
     130                 :            :             {
     131                 :    4520727 :               getManager()->updateNode(cur, pgc.get());
     132                 :            :             }
     133         [ +  - ]:    9211626 :             Trace("lazy-cdproof") << "LazyCDProof: Successfully added fact for "
     134                 :    4605813 :                                   << cfactGen << std::endl;
     135                 :            :           }
     136                 :    4605813 :         }
     137                 :            :         else
     138                 :            :         {
     139 [ +  - ][ -  + ]:    3258066 :           Trace("lazy-cdproof") << "LazyCDProof: " << identify()
                 [ -  - ]
     140                 :    1629033 :                                 << " : No generator for " << cfact << std::endl;
     141                 :            :         }
     142                 :            :         // Notice that we do not traverse the proofs that have been generated
     143                 :            :         // lazily by the proof generators here.  In other words, we assume that
     144                 :            :         // the proofs from provided proof generators are final and need
     145                 :            :         // no further modification by this class.
     146                 :            :       }
     147                 :            :       else
     148                 :            :       {
     149                 :    7875609 :         const std::vector<std::shared_ptr<ProofNode>>& cc = cur->getChildren();
     150         [ +  + ]:   22567845 :         for (const std::shared_ptr<ProofNode>& cp : cc)
     151                 :            :         {
     152                 :   14692236 :           visit.push_back(cp.get());
     153                 :            :         }
     154                 :            :       }
     155                 :   14292050 :     }
     156         [ +  + ]:   19572106 :   } while (!visit.empty());
     157                 :            :   // we have now updated the ASSUME leafs of opf, return it
     158         [ +  - ]:    4879870 :   Trace("lazy-cdproof") << "...finished" << std::endl;
     159 [ -  + ][ -  + ]:    4879870 :   Assert(opf->getResult() == fact);
                 [ -  - ]
     160                 :    4879870 :   return opf;
     161                 :    4879870 : }
     162                 :            : 
     163                 :    4540353 : void LazyCDProof::addLazyStep(Node expected,
     164                 :            :                               ProofGenerator* pg,
     165                 :            :                               TrustId idNull,
     166                 :            :                               bool isClosed,
     167                 :            :                               const char* ctx,
     168                 :            :                               bool forceOverwrite)
     169                 :            : {
     170         [ +  + ]:    4540353 :   if (pg == nullptr)
     171                 :            :   {
     172                 :            :     // null generator, should have given a proof rule
     173         [ -  + ]:     108752 :     if (idNull == TrustId::NONE)
     174                 :            :     {
     175                 :          0 :       Unreachable() << "LazyCDProof::addLazyStep: " << identify()
     176                 :          0 :                     << ": failed to provide proof generator for " << expected;
     177                 :            :       return;
     178                 :            :     }
     179         [ +  - ]:     217504 :     Trace("lazy-cdproof") << "LazyCDProof::addLazyStep: " << expected
     180                 :     108752 :                           << " set (trusted) step " << idNull << "\n";
     181                 :     108752 :     Node tid = mkTrustId(nodeManager(), idNull);
     182 [ +  + ][ -  - ]:     326256 :     addStep(expected, ProofRule::TRUST, {}, {tid, expected});
     183                 :     108752 :     return;
     184                 :     108752 :   }
     185         [ +  - ]:    8863202 :   Trace("lazy-cdproof") << "LazyCDProof::addLazyStep: " << expected
     186 [ -  + ][ -  - ]:    4431601 :                         << " set to generator " << pg->identify() << "\n";
     187         [ +  - ]:    4431601 :   if (!forceOverwrite)
     188                 :            :   {
     189                 :    4431601 :     NodeProofGeneratorMap::const_iterator it = d_gens.find(expected);
     190         [ +  + ]:    4431601 :     if (it != d_gens.end())
     191                 :            :     {
     192                 :            :       // don't overwrite something that is already there
     193                 :    1117702 :       return;
     194                 :            :     }
     195                 :            :   }
     196                 :            :   // just store now
     197                 :    3313899 :   d_gens.insert(expected, pg);
     198                 :            :   // debug checking
     199         [ +  + ]:    3313899 :   if (isClosed)
     200                 :            :   {
     201         [ +  - ]:     745744 :     Trace("lazy-cdproof-debug") << "Checking closed..." << std::endl;
     202                 :     745744 :     pfgEnsureClosed(options(), expected, pg, "lazy-cdproof-debug", ctx);
     203                 :            :   }
     204                 :            : }
     205                 :            : 
     206                 :    6234846 : ProofGenerator* LazyCDProof::getGeneratorFor(Node fact, bool& isSym)
     207                 :            : {
     208                 :    6234846 :   isSym = false;
     209                 :    6234846 :   NodeProofGeneratorMap::const_iterator it = d_gens.find(fact);
     210         [ +  + ]:    6234846 :   if (it != d_gens.end())
     211                 :            :   {
     212                 :     667432 :     return (*it).second;
     213                 :            :   }
     214         [ +  + ]:    5567414 :   if (d_autoSymm)
     215                 :            :   {
     216                 :    4641330 :     Node factSym = CDProof::getSymmFact(fact);
     217                 :            :     // could be symmetry
     218         [ +  + ]:    4641330 :     if (factSym.isNull())
     219                 :            :     {
     220                 :            :       // can't be symmetry, return the default generator
     221                 :     929838 :       return d_defaultGen;
     222                 :            :     }
     223                 :    3711492 :     it = d_gens.find(factSym);
     224         [ +  + ]:    3711492 :     if (it != d_gens.end())
     225                 :            :     {
     226                 :      85086 :       isSym = true;
     227                 :      85086 :       return (*it).second;
     228                 :            :     }
     229         [ +  + ]:    4641330 :   }
     230                 :            :   // return the default generator
     231                 :    4552490 :   return d_defaultGen;
     232                 :            : }
     233                 :            : 
     234                 :    7734054 : bool LazyCDProof::hasGenerators() const
     235                 :            : {
     236 [ +  + ][ +  + ]:    7734054 :   return !d_gens.empty() || d_defaultGen != nullptr;
     237                 :            : }
     238                 :            : 
     239                 :     250930 : bool LazyCDProof::hasGenerator(Node fact) const
     240                 :            : {
     241         [ -  + ]:     250930 :   if (d_defaultGen != nullptr)
     242                 :            :   {
     243                 :          0 :     return true;
     244                 :            :   }
     245                 :     250930 :   NodeProofGeneratorMap::const_iterator it = d_gens.find(fact);
     246         [ +  + ]:     250930 :   if (it != d_gens.end())
     247                 :            :   {
     248                 :         94 :     return true;
     249                 :            :   }
     250                 :            :   // maybe there is a symmetric fact?
     251                 :     250836 :   Node factSym = CDProof::getSymmFact(fact);
     252         [ +  + ]:     250836 :   if (!factSym.isNull())
     253                 :            :   {
     254                 :      49630 :     it = d_gens.find(factSym);
     255                 :            :   }
     256                 :     250836 :   return it != d_gens.end();
     257                 :     250836 : }
     258                 :            : 
     259                 :            : }  // namespace cvc5::internal

Generated by: LCOV version 1.14