LCOV - code coverage report
Current view: top level - buildbot/coverage/build/src/theory - theory_preprocessor.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 224 234 95.7 %
Date: 2026-03-21 10:41:10 Functions: 12 13 92.3 %
Branches: 122 206 59.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                 :            :  * The theory preprocessor.
      11                 :            :  */
      12                 :            : 
      13                 :            : #include "theory/theory_preprocessor.h"
      14                 :            : 
      15                 :            : #include "expr/skolem_manager.h"
      16                 :            : #include "expr/term_context_stack.h"
      17                 :            : #include "proof/lazy_proof.h"
      18                 :            : #include "smt/logic_exception.h"
      19                 :            : #include "theory/logic_info.h"
      20                 :            : #include "theory/rewriter.h"
      21                 :            : #include "theory/theory_engine.h"
      22                 :            : 
      23                 :            : using namespace std;
      24                 :            : 
      25                 :            : namespace cvc5::internal {
      26                 :            : namespace theory {
      27                 :            : 
      28                 :      50950 : TheoryPreprocessor::TheoryPreprocessor(Env& env, TheoryEngine& engine)
      29                 :            :     : EnvObj(env),
      30                 :      50950 :       d_engine(engine),
      31                 :      50950 :       d_cache(userContext()),
      32                 :      50950 :       d_tfr(env),
      33                 :      50950 :       d_tpg(nullptr),
      34                 :      50950 :       d_tpgRew(nullptr),
      35                 :      50950 :       d_tspg(nullptr),
      36                 :     101900 :       d_lp(nullptr)
      37                 :            : {
      38                 :            :   // proofs are enabled in the theory preprocessor regardless of the proof mode
      39                 :      50950 :   ProofNodeManager* pnm = env.getProofNodeManager();
      40         [ +  + ]:      50950 :   if (pnm != nullptr)
      41                 :            :   {
      42                 :      19375 :     context::Context* u = userContext();
      43                 :      38750 :     d_tpg.reset(
      44                 :            :         new TConvProofGenerator(env,
      45                 :            :                                 u,
      46                 :            :                                 TConvPolicy::FIXPOINT,
      47                 :            :                                 TConvCachePolicy::NEVER,
      48                 :            :                                 "TheoryPreprocessor::preprocess_rewrite",
      49                 :      19375 :                                 &d_rtfc));
      50                 :      38750 :     d_tpgRew.reset(new TConvProofGenerator(env,
      51                 :            :                                            u,
      52                 :            :                                            TConvPolicy::ONCE,
      53                 :            :                                            TConvCachePolicy::NEVER,
      54                 :      19375 :                                            "TheoryPreprocessor::pprew"));
      55                 :      38750 :     d_lp.reset(
      56                 :      19375 :         new LazyCDProof(env, nullptr, u, "TheoryPreprocessor::LazyCDProof"));
      57                 :            :     // Make the main term conversion sequence generator, which tracks up to
      58                 :            :     // three conversions made in succession:
      59                 :            :     // (1) rewriting
      60                 :            :     // (2) (theory preprocessing+rewriting until fixed point)+term formula
      61                 :            :     // removal+rewriting.
      62                 :      19375 :     std::vector<ProofGenerator*> ts;
      63         [ +  - ]:      19375 :     ts.push_back(d_tpgRew.get());
      64         [ +  - ]:      19375 :     ts.push_back(d_tpg.get());
      65                 :      38750 :     d_tspg.reset(new TConvSeqProofGenerator(
      66                 :      38750 :         pnm, ts, userContext(), "TheoryPreprocessor::sequence"));
      67                 :      19375 :   }
      68                 :      50950 : }
      69                 :            : 
      70                 :      50605 : TheoryPreprocessor::~TheoryPreprocessor() {}
      71                 :            : 
      72                 :     895507 : TrustNode TheoryPreprocessor::preprocess(TNode node,
      73                 :            :                                          std::vector<SkolemLemma>& newLemmas)
      74                 :            : {
      75                 :     895507 :   return preprocessInternal(node, newLemmas, true);
      76                 :            : }
      77                 :            : 
      78                 :    1857165 : TrustNode TheoryPreprocessor::preprocessInternal(
      79                 :            :     TNode node, std::vector<SkolemLemma>& newLemmas, bool procLemmas)
      80                 :            : {
      81                 :            :   // In this method, all rewriting steps of node are stored in d_tpg.
      82                 :            : 
      83         [ +  - ]:    1857165 :   Trace("tpp") << "TheoryPreprocessor::preprocess: start " << node << std::endl;
      84                 :            : 
      85                 :            :   // We must rewrite before preprocessing, because some terms when rewritten
      86                 :            :   // may introduce new terms that are not top-level and require preprocessing.
      87                 :            :   // An example of this is (forall ((x Int)) (and (tail L) (P x))) which
      88                 :            :   // rewrites to (and (tail L) (forall ((x Int)) (P x))). The subterm (tail L)
      89                 :            :   // must be preprocessed as a child here.
      90                 :    1857165 :   Node irNode = rewriteWithProof(node, d_tpgRew.get(), true, 0);
      91                 :            : 
      92                 :            :   // run theory preprocessing
      93                 :    1857176 :   TrustNode tpp = theoryPreprocess(irNode, newLemmas);
      94                 :    1857154 :   Node ppNode = tpp.getNode();
      95                 :            : 
      96         [ -  + ]:    1857154 :   if (TraceIsOn("tpp-debug"))
      97                 :            :   {
      98         [ -  - ]:          0 :     if (node != irNode)
      99                 :            :     {
     100         [ -  - ]:          0 :       Trace("tpp-debug") << "after initial rewriting : " << irNode << std::endl;
     101                 :            :     }
     102         [ -  - ]:          0 :     if (irNode != ppNode)
     103                 :            :     {
     104         [ -  - ]:          0 :       Trace("tpp-debug")
     105                 :          0 :           << "after preprocessing + rewriting and term formula removal : "
     106                 :          0 :           << ppNode << std::endl;
     107                 :            :     }
     108         [ -  - ]:          0 :     Trace("tpp-debug") << "TheoryPreprocessor::preprocess: finish" << std::endl;
     109                 :            :   }
     110                 :            : 
     111         [ +  + ]:    1857154 :   if (procLemmas)
     112                 :            :   {
     113                 :            :     // Also must preprocess the new lemmas. This is especially important for
     114                 :            :     // formulas containing witness terms whose bodies are not in preprocessed
     115                 :            :     // form, as term formula removal introduces new lemmas for these that
     116                 :            :     // require theory-preprocessing.
     117                 :    1796166 :     size_t i = 0;
     118         [ +  + ]:    1857154 :     while (i < newLemmas.size())
     119                 :            :     {
     120                 :      60988 :       TrustNode cur = newLemmas[i].d_lemma;
     121                 :      60988 :       newLemmas[i].d_lemma = preprocessLemmaInternal(cur, newLemmas, false);
     122 [ +  - ][ -  + ]:      60988 :       Trace("tpp") << "Final lemma : " << newLemmas[i].getProven() << std::endl;
                 [ -  - ]
     123                 :      60988 :       i++;
     124                 :      60988 :     }
     125                 :            :   }
     126                 :            : 
     127         [ +  + ]:    1857154 :   if (node == ppNode)
     128                 :            :   {
     129         [ +  - ]:    2888354 :     Trace("tpp-debug") << "...TheoryPreprocessor::preprocess returned no change"
     130                 :    1444177 :                        << std::endl;
     131                 :            :     // no change
     132                 :    1444177 :     return TrustNode::null();
     133                 :            :   }
     134                 :            : 
     135                 :            :   // Now, sequence the conversion steps if proofs are enabled.
     136                 :     412977 :   TrustNode tret;
     137         [ +  + ]:     412977 :   if (isProofEnabled())
     138                 :            :   {
     139                 :     247497 :     std::vector<Node> cterms;
     140                 :     247497 :     cterms.push_back(node);
     141                 :     247497 :     cterms.push_back(irNode);
     142                 :     247497 :     cterms.push_back(ppNode);
     143                 :            :     // We have that:
     144                 :            :     // node -> irNode via rewriting
     145                 :            :     // irNode -> ppNode via theory-preprocessing + rewriting + tf removal
     146                 :     247497 :     tret = d_tspg->mkTrustRewriteSequence(cterms);
     147                 :     247497 :     tret.debugCheckClosed(
     148                 :            :         options(), "tpp-debug", "TheoryPreprocessor::lemma_ret");
     149                 :     247497 :   }
     150                 :            :   else
     151                 :            :   {
     152                 :     165480 :     tret = TrustNode::mkTrustRewrite(node, ppNode, nullptr);
     153                 :            :   }
     154                 :            : 
     155         [ +  - ]:     825954 :   Trace("tpp-debug") << "...TheoryPreprocessor::preprocess returned "
     156 [ -  + ][ -  - ]:     412977 :                      << tret.getNode() << std::endl;
     157 [ +  - ][ -  - ]:     825954 :   Trace("tpp") << "TheoryPreprocessor::preprocess: return " << tret.getNode()
     158                 :          0 :                << ", procLemmas=" << procLemmas
     159         [ -  + ]:     412977 :                << ", # lemmas = " << newLemmas.size() << std::endl;
     160                 :     412977 :   return tret;
     161                 :    1857165 : }
     162                 :            : 
     163                 :     900670 : TrustNode TheoryPreprocessor::preprocessLemma(
     164                 :            :     TrustNode node, std::vector<SkolemLemma>& newLemmas)
     165                 :            : {
     166                 :     900670 :   return preprocessLemmaInternal(node, newLemmas, true);
     167                 :            : }
     168                 :            : 
     169                 :     961658 : TrustNode TheoryPreprocessor::preprocessLemmaInternal(
     170                 :            :     TrustNode node, std::vector<SkolemLemma>& newLemmas, bool procLemmas)
     171                 :            : {
     172                 :            :   // what was originally proven
     173                 :     961658 :   Node lemma = node.getProven();
     174                 :     961659 :   TrustNode tplemma = preprocessInternal(lemma, newLemmas, procLemmas);
     175         [ +  + ]:     961657 :   if (tplemma.isNull())
     176                 :            :   {
     177                 :            :     // no change needed
     178                 :     665582 :     return node;
     179                 :            :   }
     180 [ -  + ][ -  + ]:     296075 :   Assert(tplemma.getKind() == TrustNodeKind::REWRITE);
                 [ -  - ]
     181                 :            :   // what it was preprocessed to
     182                 :     296075 :   Node lemmap = tplemma.getNode();
     183 [ -  + ][ -  + ]:     296075 :   Assert(lemmap != node.getProven());
                 [ -  - ]
     184                 :            :   // process the preprocessing
     185         [ +  + ]:     296075 :   if (isProofEnabled())
     186                 :            :   {
     187 [ -  + ][ -  + ]:     160447 :     Assert(d_lp != nullptr);
                 [ -  - ]
     188                 :            :     // add the original proof to the lazy proof
     189                 :     160447 :     d_lp->addLazyStep(node.getProven(),
     190                 :            :                       node.getGenerator(),
     191                 :            :                       TrustId::THEORY_PREPROCESS_LEMMA);
     192                 :            :     // only need to do anything if lemmap changed in a non-trivial way
     193         [ +  + ]:     160447 :     if (!CDProof::isSame(lemmap, lemma))
     194                 :            :     {
     195                 :     151496 :       d_lp->addLazyStep(tplemma.getProven(),
     196                 :            :                         tplemma.getGenerator(),
     197                 :            :                         TrustId::THEORY_PREPROCESS,
     198                 :            :                         true,
     199                 :            :                         "TheoryEngine::lemma_pp");
     200                 :            :       // ---------- from node -------------- from theory preprocess
     201                 :            :       // lemma                lemma = lemmap
     202                 :            :       // ------------------------------------------ EQ_RESOLVE
     203                 :            :       // lemmap
     204                 :     151496 :       std::vector<Node> pfChildren;
     205                 :     151496 :       pfChildren.push_back(lemma);
     206                 :     151496 :       pfChildren.push_back(tplemma.getProven());
     207                 :     151496 :       d_lp->addStep(lemmap, ProofRule::EQ_RESOLVE, pfChildren, {});
     208                 :     151496 :     }
     209                 :            :   }
     210         [ +  + ]:     296075 :   return TrustNode::mkTrustLemma(lemmap, d_lp.get());
     211                 :     961658 : }
     212                 :            : 
     213                 :       1309 : RemoveTermFormulas& TheoryPreprocessor::getRemoveTermFormulas()
     214                 :            : {
     215                 :       1309 :   return d_tfr;
     216                 :            : }
     217                 :            : 
     218                 :    1857165 : TrustNode TheoryPreprocessor::theoryPreprocess(
     219                 :            :     TNode assertion, std::vector<SkolemLemma>& newLemmas)
     220                 :            : {
     221                 :            :   // Map from (term, term context identifier) to the term that it was
     222                 :            :   // theory-preprocessed to. This is used when the result of the current node
     223                 :            :   // should be set to the final result of converting its theory-preprocessed
     224                 :            :   // form.
     225                 :            :   std::unordered_map<std::pair<Node, uint32_t>,
     226                 :            :                      Node,
     227                 :            :                      PairHashFunction<Node, uint32_t, std::hash<Node>>>
     228                 :    1857165 :       wasPreprocessed;
     229                 :            :   std::unordered_map<
     230                 :            :       std::pair<Node, uint32_t>,
     231                 :            :       Node,
     232                 :    1857165 :       PairHashFunction<Node, uint32_t, std::hash<Node>>>::iterator itw;
     233                 :    1857165 :   NodeManager* nm = nodeManager();
     234                 :    1857165 :   TCtxStack ctx(&d_rtfc);
     235                 :    1857165 :   std::vector<bool> processedChildren;
     236                 :    1857165 :   ctx.pushInitial(assertion);
     237                 :    1857165 :   processedChildren.push_back(false);
     238                 :    1857165 :   std::pair<Node, uint32_t> initial = ctx.getCurrent();
     239                 :    1857165 :   std::pair<Node, uint32_t> curr;
     240                 :    1857165 :   Node node;
     241                 :            :   uint32_t nodeVal;
     242                 :    1857165 :   TppCache::const_iterator itc;
     243         [ +  + ]:   20922335 :   while (!ctx.empty())
     244                 :            :   {
     245                 :   19065181 :     curr = ctx.getCurrent();
     246                 :   19065181 :     itc = d_cache.find(curr);
     247                 :   19065181 :     node = curr.first;
     248                 :   19065181 :     nodeVal = curr.second;
     249         [ +  - ]:   19065181 :     Trace("tpp-debug") << "Visit " << node << ", " << nodeVal << std::endl;
     250         [ +  + ]:   19065181 :     if (itc != d_cache.end())
     251                 :            :     {
     252         [ +  - ]:    8769765 :       Trace("tpp-debug") << "...already computed" << std::endl;
     253                 :    8769765 :       ctx.pop();
     254                 :    8769765 :       processedChildren.pop_back();
     255                 :            :       // already computed
     256                 :   13694941 :       continue;
     257                 :            :     }
     258                 :            :     // if we have yet to process children
     259         [ +  + ]:   10295416 :     if (!processedChildren.back())
     260                 :            :     {
     261                 :            :       // check if we should replace the current node by a Skolem
     262                 :    5476446 :       TrustNode newLem;
     263                 :            :       bool inQuant, inTerm;
     264                 :    5476446 :       RtfTermContext::getFlags(nodeVal, inQuant, inTerm);
     265 [ -  + ][ -  + ]:    5476446 :       Assert(!inQuant);
                 [ -  - ]
     266                 :    5476448 :       TrustNode currTrn = d_tfr.runCurrent(node, inTerm, newLem);
     267                 :            :       // if we replaced by a skolem, we do not recurse
     268         [ +  + ]:    5476444 :       if (!currTrn.isNull())
     269                 :            :       {
     270                 :      52516 :         Node ret = currTrn.getNode();
     271                 :            :         // if this is the first time we've seen this term, we have a new lemma
     272                 :            :         // which we add to our vectors
     273         [ +  + ]:      52516 :         if (!newLem.isNull())
     274                 :            :         {
     275                 :      46505 :           newLemmas.push_back(theory::SkolemLemma(newLem, ret));
     276                 :            :         }
     277                 :            :         // register the rewrite into the proof generator
     278         [ +  + ]:      52516 :         if (isProofEnabled())
     279                 :            :         {
     280                 :      33024 :           registerTrustedRewrite(currTrn, d_tpg.get(), true, nodeVal);
     281                 :            :         }
     282         [ +  - ]:      52516 :         Trace("tpp-debug") << "...replace by skolem" << std::endl;
     283                 :      52516 :         d_cache.insert(curr, ret);
     284                 :      52516 :         continue;
     285                 :      52516 :       }
     286                 :    5423928 :       size_t nchild = node.getNumChildren();
     287         [ +  + ]:    5423928 :       if (nchild > 0)
     288                 :            :       {
     289         [ +  + ]:    4825258 :         if (node.isClosure())
     290                 :            :         {
     291                 :            :           // currently, we never do any term formula removal in quantifier
     292                 :            :           // bodies
     293                 :            :         }
     294                 :            :         else
     295                 :            :         {
     296         [ +  - ]:    4765324 :           Trace("tpp-debug") << "...recurse to children" << std::endl;
     297                 :            :           // recurse if we have children
     298                 :    4765324 :           processedChildren[processedChildren.size() - 1] = true;
     299         [ +  + ]:   17048203 :           for (size_t i = 0; i < nchild; i++)
     300                 :            :           {
     301                 :   12282879 :             ctx.pushChild(node, nodeVal, i);
     302                 :   12282879 :             processedChildren.push_back(false);
     303                 :            :           }
     304                 :    4765324 :           continue;
     305                 :    4765324 :         }
     306                 :            :       }
     307                 :            :       else
     308                 :            :       {
     309         [ +  - ]:     598670 :         Trace("tpp-debug") << "...base case" << std::endl;
     310                 :            :       }
     311 [ +  + ][ +  + ]:   10294286 :     }
     312         [ +  - ]:    5477574 :     Trace("tpp-debug") << "...reconstruct" << std::endl;
     313                 :            :     // otherwise, we are now finished processing children, pop the current node
     314                 :            :     // and compute the result
     315                 :    5477574 :     ctx.pop();
     316                 :    5477574 :     processedChildren.pop_back();
     317                 :            :     // if this was preprocessed previously, we set our result to the final
     318                 :            :     // form of the preprocessed form of this.
     319                 :    5477574 :     itw = wasPreprocessed.find(curr);
     320         [ +  + ]:    5477574 :     if (itw != wasPreprocessed.end())
     321                 :            :     {
     322                 :            :       // we preprocessed it to something else, carry that
     323                 :      53668 :       std::pair<Node, uint32_t> key(itw->second, nodeVal);
     324                 :      53668 :       itc = d_cache.find(key);
     325 [ -  + ][ -  + ]:      53668 :       Assert(itc != d_cache.end());
                 [ -  - ]
     326                 :      53668 :       d_cache.insert(curr, itc->second);
     327                 :      53668 :       wasPreprocessed.erase(curr);
     328                 :      53668 :       continue;
     329                 :      53668 :     }
     330                 :    5423906 :     Node ret = node;
     331                 :    5423906 :     Node pret = node;
     332 [ +  + ][ +  + ]:    5423906 :     if (!node.isClosure() && node.getNumChildren() > 0)
                 [ +  + ]
     333                 :            :     {
     334                 :            :       // if we have not already computed the result
     335                 :    4765302 :       std::vector<Node> newChildren;
     336                 :    4765302 :       bool childChanged = false;
     337         [ +  + ]:    4765302 :       if (node.getMetaKind() == kind::metakind::PARAMETERIZED)
     338                 :            :       {
     339                 :     468913 :         newChildren.push_back(node.getOperator());
     340                 :            :       }
     341                 :            :       // reconstruct from the children
     342                 :    4765302 :       std::pair<Node, uint32_t> currChild;
     343         [ +  + ]:   17048137 :       for (size_t i = 0, nchild = node.getNumChildren(); i < nchild; i++)
     344                 :            :       {
     345                 :            :         // recompute the value of the child
     346                 :   12282835 :         uint32_t val = d_rtfc.computeValue(node, nodeVal, i);
     347                 :   12282835 :         currChild = std::pair<Node, uint32_t>(node[i], val);
     348                 :   12282835 :         itc = d_cache.find(currChild);
     349 [ -  + ][ -  + ]:   12282835 :         Assert(itc != d_cache.end());
                 [ -  - ]
     350                 :   12282835 :         Node newChild = (*itc).second;
     351 [ -  + ][ -  + ]:   12282835 :         Assert(!newChild.isNull());
                 [ -  - ]
     352                 :   12282835 :         childChanged |= (newChild != node[i]);
     353                 :   12282835 :         newChildren.push_back(newChild);
     354                 :   12282835 :       }
     355                 :            :       // If changes, we reconstruct the node
     356         [ +  + ]:    4765302 :       if (childChanged)
     357                 :            :       {
     358                 :     323492 :         ret = nm->mkNode(node.getKind(), newChildren);
     359                 :            :       }
     360                 :            :       // Finish the conversion by rewriting. Notice that we must consider this a
     361                 :            :       // pre-rewrite since we do not recursively register the rewriting steps
     362                 :            :       // of subterms of rtfNode. For example, if this step rewrites
     363                 :            :       // (not A) ---> B, then if registered a pre-rewrite, it will apply when
     364                 :            :       // reconstructing proofs via d_tpg. However, if it is a post-rewrite
     365                 :            :       // it will fail to apply if another call to this class registers A -> C,
     366                 :            :       // in which case (not C) will be returned instead of B (see issue 6754).
     367                 :    4765302 :       pret = rewriteWithProof(ret, d_tpg.get(), false, nodeVal);
     368                 :    4765302 :     }
     369                 :            :     // if we did not rewrite above, we are ready to theory preprocess
     370         [ +  + ]:    5423906 :     if (pret == ret)
     371                 :            :     {
     372                 :    5392432 :       pret = preprocessWithProof(ret, newLemmas, nodeVal);
     373                 :            :     }
     374                 :            :     // if we changed due to rewriting or preprocessing, we traverse again
     375         [ +  + ]:    5423897 :     if (pret != ret)
     376                 :            :     {
     377                 :            :       // must restart
     378                 :      53668 :       ctx.push(node, nodeVal);
     379                 :      53668 :       processedChildren.push_back(true);
     380                 :      53668 :       ctx.push(pret, nodeVal);
     381                 :      53668 :       processedChildren.push_back(false);
     382                 :      53668 :       wasPreprocessed[curr] = pret;
     383                 :      53668 :       continue;
     384                 :            :     }
     385                 :            :     // cache
     386                 :    5370229 :     d_cache.insert(curr, ret);
     387 [ +  + ][ +  + ]:    5477583 :   }
     388                 :    1857154 :   itc = d_cache.find(initial);
     389 [ -  + ][ -  + ]:    1857154 :   Assert(itc != d_cache.end());
                 [ -  - ]
     390         [ +  + ]:    3714308 :   return TrustNode::mkTrustRewrite(assertion, (*itc).second, d_tpg.get());
     391                 :    1857220 : }
     392                 :            : 
     393                 :    6644652 : Node TheoryPreprocessor::rewriteWithProof(Node term,
     394                 :            :                                           TConvProofGenerator* pg,
     395                 :            :                                           bool isPre,
     396                 :            :                                           uint32_t tctx)
     397                 :            : {
     398                 :    6644652 :   Node termr = rewrite(term);
     399                 :            :   // store rewrite step if tracking proofs and it rewrites
     400         [ +  + ]:    6644652 :   if (isProofEnabled())
     401                 :            :   {
     402                 :            :     // may rewrite the same term more than once, thus check hasRewriteStep
     403         [ +  + ]:    4061571 :     if (termr != term)
     404                 :            :     {
     405         [ +  - ]:     460468 :       Trace("tpp-debug") << "TheoryPreprocessor: addRewriteStep (rewriting) "
     406                 :     230234 :                          << term << " -> " << termr << std::endl;
     407                 :     460468 :       pg->addRewriteStep(
     408                 :            :           term, termr, ProofRule::MACRO_REWRITE, {}, {term}, isPre, tctx);
     409                 :            :     }
     410                 :            :   }
     411                 :    6644652 :   return termr;
     412                 :          0 : }
     413                 :            : 
     414                 :    5392423 : Node TheoryPreprocessor::preprocessWithProof(Node term,
     415                 :            :                                              std::vector<SkolemLemma>& lems,
     416                 :            :                                              uint32_t tctx)
     417                 :            : {
     418                 :            :   // Important that it is in rewritten form, to ensure that the rewrite steps
     419                 :            :   // recorded in d_tpg are functional. In other words, there should not
     420                 :            :   // be steps from the same term to multiple rewritten forms, which would be
     421                 :            :   // the case if we registered a preprocessing step for a non-rewritten term.
     422 [ -  + ][ -  + ]:    5392423 :   Assert(term == rewrite(term));
                 [ -  - ]
     423         [ +  - ]:   10784846 :   Trace("tpp-debug2") << "preprocessWithProof " << term
     424                 :    5392423 :                       << ", #lems = " << lems.size() << std::endl;
     425                 :            :   // We never call ppRewrite on equalities here, since equalities have a
     426                 :            :   // special status. In particular, notice that theory preprocessing can be
     427                 :            :   // called on all formulas asserted to theory engine, including those generated
     428                 :            :   // as new literals appearing in lemmas. Calling ppRewrite on equalities is
     429                 :            :   // incompatible with theory combination where a split on equality requested
     430                 :            :   // by a theory could be preprocessed to something else, thus making theory
     431                 :            :   // combination either non-terminating or result in solution soundness.
     432                 :            :   // Notice that an alternative solution is to ensure that certain lemmas
     433                 :            :   // (e.g. splits from theory combination) can never have theory preprocessing
     434                 :            :   // applied to them. However, it is more uniform to say that theory
     435                 :            :   // preprocessing is applied to all formulas. This makes it so that e.g.
     436                 :            :   // theory solvers do not need to specify whether they want their lemmas to
     437                 :            :   // be theory-preprocessed or not.
     438         [ +  + ]:    5392423 :   if (term.getKind() == Kind::EQUAL)
     439                 :            :   {
     440                 :     753987 :     return term;
     441                 :            :   }
     442                 :            :   // call ppRewrite for the given theory
     443                 :    4638436 :   std::vector<SkolemLemma> newLems;
     444                 :    4638445 :   TrustNode trn = d_engine.ppRewrite(term, newLems);
     445         [ +  - ]:    9276854 :   Trace("tpp-debug2") << "preprocessWithProof returned " << trn
     446                 :    4638427 :                       << ", #lems = " << newLems.size() << std::endl;
     447                 :    4638427 :   lems.insert(lems.end(), newLems.begin(), newLems.end());
     448         [ +  + ]:    4638427 :   if (trn.isNull())
     449                 :            :   {
     450                 :            :     // no change, return
     451                 :    4616242 :     return term;
     452                 :            :   }
     453                 :      22185 :   Node termr = trn.getNode();
     454 [ -  + ][ -  + ]:      22185 :   Assert(term != termr);
                 [ -  - ]
     455         [ +  + ]:      22185 :   if (isProofEnabled())
     456                 :            :   {
     457                 :       9174 :     registerTrustedRewrite(trn, d_tpg.get(), false, tctx);
     458                 :            :   }
     459                 :            :   // Rewrite again here, which notice is a *pre* rewrite.
     460                 :      22185 :   return rewriteWithProof(termr, d_tpg.get(), true, tctx);
     461                 :    4638436 : }
     462                 :            : 
     463                 :    7470603 : bool TheoryPreprocessor::isProofEnabled() const { return d_tpg != nullptr; }
     464                 :            : 
     465                 :      42198 : void TheoryPreprocessor::registerTrustedRewrite(TrustNode trn,
     466                 :            :                                                 TConvProofGenerator* pg,
     467                 :            :                                                 bool isPre,
     468                 :            :                                                 uint32_t tctx)
     469                 :            : {
     470 [ +  - ][ -  + ]:      42198 :   if (!isProofEnabled() || trn.isNull())
                 [ -  + ]
     471                 :            :   {
     472                 :          0 :     return;
     473                 :            :   }
     474 [ -  + ][ -  + ]:      42198 :   Assert(trn.getKind() == TrustNodeKind::REWRITE);
                 [ -  - ]
     475                 :      42198 :   Node eq = trn.getProven();
     476                 :      42198 :   Node term = eq[0];
     477                 :      42198 :   Node termr = eq[1];
     478         [ +  - ]:      84396 :   Trace("tpp-debug") << "TheoryPreprocessor: addRewriteStep (generator) "
     479                 :      42198 :                      << term << " -> " << termr << std::endl;
     480         [ +  + ]:      42198 :   if (trn.getGenerator() != nullptr)
     481                 :            :   {
     482                 :      37255 :     trn.debugCheckClosed(
     483                 :            :         options(), "tpp-debug", "TheoryPreprocessor::preprocessWithProof");
     484                 :            :   }
     485                 :            :   // always use term context hash 0 (default)
     486                 :      42198 :   pg->addRewriteStep(term,
     487                 :            :                      termr,
     488                 :            :                      trn.getGenerator(),
     489                 :            :                      isPre,
     490                 :            :                      TrustId::THEORY_PREPROCESS,
     491                 :            :                      true,
     492                 :            :                      tctx);
     493                 :      42198 : }
     494                 :            : 
     495                 :            : }  // namespace theory
     496                 :            : }  // namespace cvc5::internal

Generated by: LCOV version 1.14