LCOV - code coverage report
Current view: top level - buildbot/coverage/build/src/smt - proof_post_processor.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 547 594 92.1 %
Date: 2026-02-26 11:40:56 Functions: 21 21 100.0 %
Branches: 336 564 59.6 %

           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 module for processing proof nodes.
      11                 :            :  */
      12                 :            : 
      13                 :            : #include "smt/proof_post_processor.h"
      14                 :            : 
      15                 :            : #include "expr/skolem_manager.h"
      16                 :            : #include "options/base_options.h"
      17                 :            : #include "options/proof_options.h"
      18                 :            : #include "preprocessing/assertion_pipeline.h"
      19                 :            : #include "proof/proof_node_algorithm.h"
      20                 :            : #include "proof/proof_node_manager.h"
      21                 :            : #include "proof/resolution_proofs_util.h"
      22                 :            : #include "proof/subtype_elim_proof_converter.h"
      23                 :            : #include "theory/arith/arith_proof_utilities.h"
      24                 :            : #include "theory/arith/arith_utilities.h"
      25                 :            : #include "theory/builtin/proof_checker.h"
      26                 :            : #include "theory/bv/bitblast/bitblast_proof_generator.h"
      27                 :            : #include "theory/bv/bitblast/proof_bitblaster.h"
      28                 :            : #include "theory/rewriter.h"
      29                 :            : #include "theory/strings/infer_proof_cons.h"
      30                 :            : #include "theory/theory.h"
      31                 :            : #include "util/rational.h"
      32                 :            : 
      33                 :            : using namespace cvc5::internal::kind;
      34                 :            : using namespace cvc5::internal::theory;
      35                 :            : 
      36                 :            : namespace cvc5::internal {
      37                 :            : namespace smt {
      38                 :            : 
      39                 :      18896 : ProofPostprocessCallback::ProofPostprocessCallback(Env& env,
      40                 :      18896 :                                                    bool updateScopedAssumptions)
      41                 :            :     : EnvObj(env),
      42                 :      18896 :       d_pc(nullptr),
      43                 :      18896 :       d_pppg(nullptr),
      44                 :      18896 :       d_wfpm(env),
      45                 :      18896 :       d_macroExpand(statisticsRegistry().registerHistogram<ProofRule>(
      46                 :            :           "ProofPostprocessCallback::macroExpandCount")),
      47                 :      56688 :       d_updateScopedAssumptions(updateScopedAssumptions)
      48                 :            : {
      49                 :      18896 :   d_true = nodeManager()->mkConst(true);
      50                 :      18896 : }
      51                 :            : 
      52                 :      13591 : void ProofPostprocessCallback::initializeUpdate(ProofGenerator* pppg)
      53                 :            : {
      54                 :      13591 :   d_pppg = pppg;
      55                 :      13591 :   d_assumpToProof.clear();
      56                 :      13591 :   d_wfAssumptions.clear();
      57                 :      13591 :   d_pc = d_env.getProofNodeManager()->getChecker();
      58                 :      13591 : }
      59                 :            : 
      60                 :     103525 : void ProofPostprocessCallback::setEliminateRule(ProofRule rule)
      61                 :            : {
      62                 :     103525 :   d_elimRules.insert(rule);
      63                 :     103525 : }
      64                 :            : 
      65                 :    7522291 : bool ProofPostprocessCallback::shouldUpdate(std::shared_ptr<ProofNode> pn,
      66                 :            :                                             const std::vector<Node>& fa,
      67                 :            :                                             bool& continueUpdate)
      68                 :            : {
      69                 :    7522291 :   ProofRule id = pn->getRule();
      70         [ +  + ]:    7522291 :   if (shouldExpand(id))
      71                 :            :   {
      72                 :     406041 :     return true;
      73                 :            :   }
      74                 :            :   // other than elimination rules, we always update assumptions as long as
      75                 :            :   // d_updateScopedAssumptions is true or they are *not* in scope, i.e., not in
      76                 :            :   // fa
      77         [ +  + ]:    7116250 :   if (id != ProofRule::ASSUME)
      78                 :            :   {
      79                 :    5902732 :     return false;
      80                 :            :   }
      81                 :    2427036 :   if (!d_updateScopedAssumptions
      82 [ +  + ][ +  + ]:    1213518 :       && std::find(fa.begin(), fa.end(), pn->getResult()) != fa.end())
         [ +  + ][ +  + ]
                 [ -  - ]
      83                 :            :   {
      84         [ +  - ]:     325008 :     Trace("smt-proof-pp-debug")
      85 [ -  + ][ -  - ]:     162504 :         << "... not updating in-scope assumption " << pn->getResult() << "\n";
      86                 :     162504 :     return false;
      87                 :            :   }
      88                 :    1051014 :   return true;
      89                 :            : }
      90                 :            : 
      91                 :    7039490 : bool ProofPostprocessCallback::shouldUpdatePost(std::shared_ptr<ProofNode> pn,
      92                 :            :                                                 const std::vector<Node>& fa)
      93                 :            : {
      94                 :    7039490 :   return false;
      95                 :            : }
      96                 :            : 
      97                 :    1760993 : bool ProofPostprocessCallback::update(Node res,
      98                 :            :                                       ProofRule id,
      99                 :            :                                       const std::vector<Node>& children,
     100                 :            :                                       const std::vector<Node>& args,
     101                 :            :                                       CDProof* cdp,
     102                 :            :                                       bool& continueUpdate)
     103                 :            : {
     104         [ +  - ]:    3521986 :   Trace("smt-proof-pp-debug") << "- Post process " << id << " " << children
     105                 :    1760993 :                               << " / " << args << std::endl;
     106                 :            : 
     107         [ +  + ]:    1760993 :   if (id == ProofRule::ASSUME)
     108                 :            :   {
     109                 :            :     // we cache based on the assumption node, not the proof node, since there
     110                 :            :     // may be multiple occurrences of the same node.
     111                 :    1051014 :     Node f = args[0];
     112                 :    1051014 :     std::shared_ptr<ProofNode> pfn;
     113                 :            :     std::map<Node, std::shared_ptr<ProofNode>>::iterator it =
     114                 :    1051014 :         d_assumpToProof.find(f);
     115         [ +  + ]:    1051014 :     if (it != d_assumpToProof.end())
     116                 :            :     {
     117         [ +  - ]:     895731 :       Trace("smt-proof-pp-debug") << "...already computed" << std::endl;
     118                 :     895731 :       pfn = it->second;
     119                 :            :     }
     120                 :            :     else
     121                 :            :     {
     122         [ +  - ]:     155283 :       Trace("smt-proof-pp-debug") << "...get proof" << std::endl;
     123 [ -  + ][ -  + ]:     155283 :       Assert(d_pppg != nullptr);
                 [ -  - ]
     124                 :            :       // get proof from preprocess proof generator
     125                 :     155283 :       pfn = d_pppg->getProofFor(f);
     126         [ +  - ]:     155283 :       Trace("smt-proof-pp-debug") << "...finished get proof" << std::endl;
     127                 :            :       // print for debugging
     128         [ +  + ]:     155283 :       if (pfn == nullptr)
     129                 :            :       {
     130         [ +  - ]:     132036 :         Trace("smt-proof-pp-debug")
     131                 :      66018 :             << "...no proof, possibly an input assumption" << std::endl;
     132                 :            :       }
     133                 :            :       else
     134                 :            :       {
     135 [ -  + ][ -  + ]:      89265 :         Assert(pfn->getResult() == f);
                 [ -  - ]
     136         [ -  + ]:      89265 :         if (TraceIsOn("smt-proof-pp"))
     137                 :            :         {
     138         [ -  - ]:          0 :           Trace("smt-proof-pp")
     139                 :          0 :               << "=== Connect proof for preprocessing: " << f << std::endl;
     140         [ -  - ]:          0 :           Trace("smt-proof-pp") << *pfn.get() << std::endl;
     141                 :            :         }
     142                 :            :       }
     143                 :     155283 :       d_assumpToProof[f] = pfn;
     144                 :            :     }
     145 [ +  + ][ +  + ]:    1051014 :     if (pfn == nullptr || pfn->getRule() == ProofRule::ASSUME)
                 [ +  + ]
     146                 :            :     {
     147         [ +  - ]:     993544 :       Trace("smt-proof-pp-debug") << "...do not add proof" << std::endl;
     148                 :            :       // no update
     149                 :     993544 :       return false;
     150                 :            :     }
     151         [ +  - ]:      57470 :     Trace("smt-proof-pp-debug") << "...add proof" << std::endl;
     152                 :            :     // connect the proof
     153                 :      57470 :     cdp->addProof(pfn);
     154                 :      57470 :     return true;
     155                 :    1051014 :   }
     156                 :     709979 :   Node ret = expandMacros(id, children, args, cdp, res);
     157         [ +  - ]:     709979 :   Trace("smt-proof-pp-debug") << "...expanded = " << !ret.isNull() << std::endl;
     158                 :     709979 :   return !ret.isNull();
     159                 :     709979 : }
     160                 :            : 
     161                 :     303938 : bool ProofPostprocessCallback::updateInternal(Node res,
     162                 :            :                                               ProofRule id,
     163                 :            :                                               const std::vector<Node>& children,
     164                 :            :                                               const std::vector<Node>& args,
     165                 :            :                                               CDProof* cdp)
     166                 :            : {
     167                 :     303938 :   bool continueUpdate = true;
     168                 :     303938 :   return update(res, id, children, args, cdp, continueUpdate);
     169                 :            : }
     170                 :            : 
     171                 :    8671744 : bool ProofPostprocessCallback::shouldExpand(ProofRule id) const
     172                 :            : {
     173                 :    8671744 :   return d_elimRules.find(id) != d_elimRules.end();
     174                 :            : }
     175                 :            : 
     176                 :    1149453 : Node ProofPostprocessCallback::expandMacros(ProofRule id,
     177                 :            :                                             const std::vector<Node>& children,
     178                 :            :                                             const std::vector<Node>& args,
     179                 :            :                                             CDProof* cdp,
     180                 :            :                                             Node res)
     181                 :            : {
     182         [ -  + ]:    1149453 :   if (!shouldExpand(id))
     183                 :            :   {
     184                 :            :     // not eliminated
     185                 :          0 :     return Node::null();
     186                 :            :   }
     187                 :    1149453 :   d_macroExpand << id;
     188         [ +  - ]:    1149453 :   Trace("smt-proof-pp-debug") << "Expand macro " << id << std::endl;
     189         [ +  + ]:    1149453 :   if (id == ProofRule::TRUST)
     190                 :            :   {
     191                 :            :     TrustId tid;
     192                 :      19811 :     getTrustId(args[0], tid);
     193                 :            :     // maybe we can show it rewrites to true based on rewriting
     194                 :            :     // modulo original forms (MACRO_SR_PRED_INTRO).
     195                 :      19811 :     TheoryProofStepBuffer psb(d_pc);
     196         [ +  + ]:      19811 :     if (psb.applyPredIntro(
     197                 :            :             res, {}, MethodId::SB_DEFAULT, MethodId::SBA_SEQUENTIAL))
     198                 :            :     {
     199                 :        975 :       cdp->addSteps(psb);
     200                 :        975 :       return res;
     201                 :            :     }
     202                 :      18836 :     return Node::null();
     203                 :      19811 :   }
     204                 :            :   // macro elimination
     205         [ +  + ]:    1129642 :   if (id == ProofRule::MACRO_SR_EQ_INTRO)
     206                 :            :   {
     207                 :            :     // (TRANS
     208                 :            :     //   (SUBS <children> :args args[0:1])
     209                 :            :     //   (REWRITE :args <t.substitute(x1,t1). ... .substitute(xn,tn)> args[2]))
     210                 :     467107 :     std::vector<Node> tchildren;
     211                 :     467107 :     Node t = args[0];
     212                 :     467107 :     Node ts;
     213         [ +  + ]:     467107 :     if (!children.empty())
     214                 :            :     {
     215                 :      24756 :       std::vector<Node> sargs;
     216                 :      24756 :       sargs.push_back(t);
     217                 :      24756 :       MethodId ids = MethodId::SB_DEFAULT;
     218         [ +  + ]:      24756 :       if (args.size() >= 2)
     219                 :            :       {
     220         [ +  - ]:       9692 :         if (getMethodId(args[1], ids))
     221                 :            :         {
     222                 :       9692 :           sargs.push_back(args[1]);
     223                 :            :         }
     224                 :            :       }
     225                 :      24756 :       MethodId ida = MethodId::SBA_SEQUENTIAL;
     226         [ +  + ]:      24756 :       if (args.size() >= 3)
     227                 :            :       {
     228         [ +  - ]:       9518 :         if (getMethodId(args[2], ida))
     229                 :            :         {
     230                 :       9518 :           sargs.push_back(args[2]);
     231                 :            :         }
     232                 :            :       }
     233                 :      49512 :       ts = builtin::BuiltinProofRuleChecker::applySubstitution(
     234                 :      24756 :           t, children, ids, ida);
     235         [ +  - ]:      49512 :       Trace("smt-proof-pp-debug")
     236                 :          0 :           << "...eq intro subs equality is " << t << " == " << ts << ", from "
     237                 :      24756 :           << ids << " " << ida << std::endl;
     238         [ +  + ]:      24756 :       if (ts != t)
     239                 :            :       {
     240                 :      17329 :         Node eq = t.eqNode(ts);
     241                 :            :         // apply SUBS proof rule if necessary
     242         [ -  + ]:      17329 :         if (!updateInternal(eq, ProofRule::SUBS, children, sargs, cdp))
     243                 :            :         {
     244                 :            :           // if we specified that we did not want to eliminate, add as step
     245                 :          0 :           cdp->addStep(eq, ProofRule::SUBS, children, sargs);
     246                 :            :         }
     247                 :      17329 :         tchildren.push_back(eq);
     248                 :      17329 :       }
     249                 :      24756 :     }
     250                 :            :     else
     251                 :            :     {
     252                 :            :       // no substitute
     253                 :     442351 :       ts = t;
     254                 :            :     }
     255                 :     467107 :     std::vector<Node> rargs;
     256                 :     467107 :     rargs.push_back(ts);
     257                 :     467107 :     MethodId idr = MethodId::RW_REWRITE;
     258         [ +  + ]:     467107 :     if (args.size() >= 4)
     259                 :            :     {
     260         [ +  - ]:       2774 :       if (getMethodId(args[3], idr))
     261                 :            :       {
     262                 :       2774 :         rargs.push_back(args[3]);
     263                 :            :       }
     264                 :            :     }
     265                 :     467107 :     Node tr = d_env.rewriteViaMethod(ts, idr);
     266         [ +  - ]:     934214 :     Trace("smt-proof-pp-debug")
     267                 :          0 :         << "...eq intro rewrite equality is " << ts << " == " << tr << ", from "
     268                 :     467107 :         << idr << std::endl;
     269         [ +  + ]:     467107 :     if (ts != tr)
     270                 :            :     {
     271                 :     286609 :       Node eq = ts.eqNode(tr);
     272                 :            :       // apply REWRITE proof rule
     273         [ -  + ]:     286609 :       if (!updateInternal(eq, ProofRule::MACRO_REWRITE, {}, rargs, cdp))
     274                 :            :       {
     275                 :            :         // if not elimianted, add as step
     276                 :          0 :         cdp->addStep(eq, ProofRule::MACRO_REWRITE, {}, rargs);
     277                 :            :       }
     278                 :     286609 :       tchildren.push_back(eq);
     279                 :     286609 :     }
     280         [ +  + ]:     467107 :     if (t == tr)
     281                 :            :     {
     282                 :            :       // typically not necessary, but done to be robust
     283                 :     352946 :       cdp->addStep(t.eqNode(tr), ProofRule::REFL, {}, {t});
     284                 :     176473 :       return t.eqNode(tr);
     285                 :            :     }
     286                 :            :     // must add TRANS if two step
     287                 :     290634 :     return addProofForTrans(tchildren, cdp);
     288                 :     467107 :   }
     289         [ +  + ]:     662535 :   else if (id == ProofRule::MACRO_SR_PRED_INTRO)
     290                 :            :   {
     291                 :      42723 :     std::vector<Node> tchildren;
     292                 :      42723 :     std::vector<Node> sargs = args;
     293                 :      42723 :     MethodId idr = MethodId::RW_REWRITE;
     294         [ +  + ]:      42723 :     if (args.size() >= 4)
     295                 :            :     {
     296                 :       1723 :       getMethodId(args[3], idr);
     297                 :            :     }
     298                 :            :     // take into account witness form, if necessary
     299                 :      42723 :     WitnessReq reqw = d_wfpm.requiresWitnessFormIntro(args[0], idr);
     300         [ +  - ]:      42723 :     Trace("smt-proof-pp-debug") << "...pred intro reqw=" << reqw << std::endl;
     301                 :            :     // (TRUE_ELIM
     302                 :            :     // (TRANS
     303                 :            :     //    (MACRO_SR_EQ_INTRO <children> :args (t args[1:]))
     304                 :            :     //    ... proof of apply_SR(t) = toWitness(apply_SR(t)) ...
     305                 :            :     //    (MACRO_SR_EQ_INTRO {} {toWitness(apply_SR(t))})
     306                 :            :     // ))
     307                 :            :     // Notice this is an optimized, one sided version of the expansion of
     308                 :            :     // MACRO_SR_PRED_TRANSFORM below.
     309                 :            :     // We call the expandMacros method on MACRO_SR_EQ_INTRO, where notice
     310                 :            :     // that this rule application is immediately expanded in the recursive
     311                 :            :     // call and not added to the proof.
     312                 :            :     Node conc =
     313                 :      42723 :         addExpandStep(ProofRule::MACRO_SR_EQ_INTRO, children, sargs, cdp);
     314         [ +  - ]:      85446 :     Trace("smt-proof-pp-debug")
     315                 :      42723 :         << "...pred intro conclusion is " << conc << std::endl;
     316 [ -  + ][ -  + ]:      42723 :     Assert(!conc.isNull());
                 [ -  - ]
     317 [ -  + ][ -  + ]:      42723 :     Assert(conc.getKind() == Kind::EQUAL);
                 [ -  - ]
     318 [ -  + ][ -  + ]:      42723 :     Assert(conc[0] == args[0]);
                 [ -  - ]
     319                 :      42723 :     addToTransChildren(conc, tchildren);
     320                 :      42723 :     Node wc = conc[1];
     321 [ +  + ][ +  + ]:      42723 :     if (reqw == WitnessReq::WITNESS || reqw == WitnessReq::WITNESS_AND_REWRITE)
     322                 :            :     {
     323                 :      11778 :       Node weq = addProofForWitnessForm(conc[1], cdp);
     324         [ +  - ]:      11778 :       Trace("smt-proof-pp-debug") << "...weq is " << weq << std::endl;
     325                 :            :       // note this may be reflexive
     326                 :      11778 :       addToTransChildren(weq, tchildren);
     327                 :      11778 :       wc = weq[1];
     328                 :      11778 :     }
     329 [ +  - ][ +  + ]:      42723 :     if (reqw == WitnessReq::REWRITE || reqw == WitnessReq::WITNESS_AND_REWRITE)
     330                 :            :     {
     331                 :            :       // toWitness(apply_SR(t)) = apply_SR(toWitness(apply_SR(t)))
     332                 :            :       // rewrite again, don't need substitution. Also we always use the
     333                 :            :       // default rewriter, due to the definition of MACRO_SR_PRED_INTRO.
     334                 :      35127 :       Node weqr = addExpandStep(ProofRule::MACRO_SR_EQ_INTRO, {}, {wc}, cdp);
     335                 :      11709 :       addToTransChildren(weqr, tchildren);
     336                 :      11709 :     }
     337         [ +  + ]:      42723 :     if (tchildren.empty())
     338                 :            :     {
     339                 :            :       // if trivial corner case, go back and add conc (which must be reflexive,
     340                 :            :       // since we already tried to add it via addToTransChildren).
     341                 :         80 :       tchildren.push_back(conc);
     342                 :            :     }
     343                 :            :     // apply transitivity if necessary
     344                 :      42723 :     Node eq = addProofForTrans(tchildren, cdp);
     345 [ -  + ][ -  + ]:      42723 :     Assert(!eq.isNull());
                 [ -  - ]
     346 [ -  + ][ -  + ]:      42723 :     Assert(eq.getKind() == Kind::EQUAL);
                 [ -  - ]
     347 [ -  + ][ -  + ]:      42723 :     Assert(eq[0] == args[0]);
                 [ -  - ]
     348 [ -  + ][ -  + ]:      42723 :     Assert(eq[1] == d_true);
                 [ -  - ]
     349                 :            : 
     350                 :      85446 :     cdp->addStep(eq[0], ProofRule::TRUE_ELIM, {eq}, {});
     351                 :      42723 :     return eq[0];
     352                 :      42723 :   }
     353         [ +  + ]:     619812 :   else if (id == ProofRule::MACRO_SR_PRED_ELIM)
     354                 :            :   {
     355                 :            :     // (EQ_RESOLVE
     356                 :            :     //   children[0]
     357                 :            :     //   (MACRO_SR_EQ_INTRO children[1:] :args children[0] ++ args))
     358                 :      11418 :     std::vector<Node> schildren(children.begin() + 1, children.end());
     359                 :      11418 :     std::vector<Node> srargs;
     360                 :      11418 :     srargs.push_back(children[0]);
     361                 :      11418 :     srargs.insert(srargs.end(), args.begin(), args.end());
     362                 :            :     Node conc =
     363                 :      11418 :         addExpandStep(ProofRule::MACRO_SR_EQ_INTRO, schildren, srargs, cdp);
     364 [ -  + ][ -  + ]:      11418 :     Assert(!conc.isNull());
                 [ -  - ]
     365 [ -  + ][ -  + ]:      11418 :     Assert(conc.getKind() == Kind::EQUAL);
                 [ -  - ]
     366 [ -  + ][ -  + ]:      11418 :     Assert(conc[0] == children[0]);
                 [ -  - ]
     367                 :            :     // apply equality resolve
     368 [ +  + ][ -  - ]:      34254 :     cdp->addStep(conc[1], ProofRule::EQ_RESOLVE, {children[0], conc}, {});
     369                 :      11418 :     return conc[1];
     370                 :      11418 :   }
     371         [ +  + ]:     608394 :   else if (id == ProofRule::MACRO_SR_PRED_TRANSFORM)
     372                 :            :   {
     373                 :            :     // (EQ_RESOLVE
     374                 :            :     //   children[0]
     375                 :            :     //   (TRANS
     376                 :            :     //      (MACRO_SR_EQ_INTRO children[1:] :args (children[0] args[1:]))
     377                 :            :     //      ... proof of c = wc
     378                 :            :     //      (MACRO_SR_EQ_INTRO {} wc)
     379                 :            :     //      (SYMM
     380                 :            :     //        (MACRO_SR_EQ_INTRO children[1:] :args <args>)
     381                 :            :     //        ... proof of a = wa
     382                 :            :     //        (MACRO_SR_EQ_INTRO {} wa))))
     383                 :            :     // where
     384                 :            :     // wa = toWitness(apply_SR(args[0])) and
     385                 :            :     // wc = toWitness(apply_SR(children[0])).
     386         [ +  - ]:     373198 :     Trace("smt-proof-pp-debug")
     387                 :     186599 :         << "Transform " << children[0] << " == " << args[0] << std::endl;
     388         [ +  + ]:     186599 :     if (CDProof::isSame(children[0], args[0]))
     389                 :            :     {
     390         [ +  - ]:       3834 :       Trace("smt-proof-pp-debug") << "...nothing to do" << std::endl;
     391                 :            :       // nothing to do
     392                 :       3834 :       return children[0];
     393                 :            :     }
     394                 :     182765 :     std::vector<Node> tchildren;
     395                 :     182765 :     std::vector<Node> schildren(children.begin() + 1, children.end());
     396                 :     182765 :     std::vector<Node> sargs = args;
     397                 :            :     // first, compute if we need
     398                 :     182765 :     MethodId idr = MethodId::RW_REWRITE;
     399         [ +  + ]:     182765 :     if (args.size() >= 4)
     400                 :            :     {
     401                 :        139 :       getMethodId(args[3], idr);
     402                 :            :     }
     403                 :            :     WitnessReq reqw =
     404                 :     182765 :         d_wfpm.requiresWitnessFormTransform(children[0], args[0], idr);
     405         [ +  - ]:     182765 :     Trace("smt-proof-pp-debug") << "...reqw=" << reqw << std::endl;
     406                 :            :     // convert both sides, in three steps, take symmetry of second chain
     407         [ +  + ]:     548295 :     for (unsigned r = 0; r < 2; r++)
     408                 :            :     {
     409                 :     365530 :       std::vector<Node> tchildrenr;
     410                 :            :       // first rewrite children[0], then args[0]
     411         [ +  + ]:     365530 :       sargs[0] = r == 0 ? children[0] : args[0];
     412                 :            :       // t = apply_SR(t)
     413                 :            :       Node eq =
     414                 :     365530 :           expandMacros(ProofRule::MACRO_SR_EQ_INTRO, schildren, sargs, cdp);
     415         [ +  - ]:     731060 :       Trace("smt-proof-pp-debug")
     416                 :     365530 :           << "transform subs_rewrite (" << r << "): " << eq << std::endl;
     417                 :     365530 :       Assert(!eq.isNull() && eq.getKind() == Kind::EQUAL && eq[0] == sargs[0]);
     418                 :     365530 :       addToTransChildren(eq, tchildrenr);
     419                 :            :       // apply_SR(t) = toWitness(apply_SR(t))
     420                 :     365530 :       Node wc = eq[1];
     421         [ +  + ]:     365530 :       if (reqw == WitnessReq::WITNESS
     422         [ +  + ]:     359374 :           || reqw == WitnessReq::WITNESS_AND_REWRITE)
     423                 :            :       {
     424                 :      14140 :         Node weq = addProofForWitnessForm(eq[1], cdp);
     425         [ +  - ]:      28280 :         Trace("smt-proof-pp-debug")
     426                 :      14140 :             << "transform toWitness (" << r << "): " << weq << std::endl;
     427                 :            :         // note this may be reflexive
     428                 :      14140 :         addToTransChildren(weq, tchildrenr);
     429                 :      14140 :         wc = weq[1];
     430                 :      14140 :       }
     431         [ +  + ]:     365530 :       if (reqw == WitnessReq::REWRITE
     432         [ +  + ]:     365420 :           || reqw == WitnessReq::WITNESS_AND_REWRITE)
     433                 :            :       {
     434                 :            :         // toWitness(apply_SR(t)) = apply_SR(toWitness(apply_SR(t)))
     435                 :            :         // rewrite again, don't need substitution. Also, we always use the
     436                 :            :         // default rewriter, due to the definition of MACRO_SR_PRED_TRANSFORM.
     437                 :      24282 :         Node weqr = addExpandStep(ProofRule::MACRO_SR_EQ_INTRO, {}, {wc}, cdp);
     438         [ +  - ]:      16188 :         Trace("smt-proof-pp-debug")
     439                 :       8094 :             << "transform rewrite_witness (" << r << "): " << weqr << std::endl;
     440                 :       8094 :         addToTransChildren(weqr, tchildrenr);
     441                 :       8094 :       }
     442         [ +  - ]:     731060 :       Trace("smt-proof-pp-debug")
     443                 :     365530 :           << "transform connect (" << r << ")" << std::endl;
     444                 :            :       // add to overall chain
     445         [ +  + ]:     365530 :       if (r == 0)
     446                 :            :       {
     447                 :            :         // add the current chain to the overall chain
     448                 :     182765 :         tchildren.insert(tchildren.end(), tchildrenr.begin(), tchildrenr.end());
     449                 :            :       }
     450                 :            :       else
     451                 :            :       {
     452                 :            :         // add the current chain to cdp
     453                 :     182765 :         Node eqr = addProofForTrans(tchildrenr, cdp);
     454         [ +  + ]:     182765 :         if (!eqr.isNull())
     455                 :            :         {
     456         [ +  - ]:     257488 :           Trace("smt-proof-pp-debug") << "transform connect sym " << tchildren
     457                 :     128744 :                                       << " " << eqr << std::endl;
     458                 :            :           // take symmetry of above and add it to the overall chain
     459                 :     128744 :           addToTransChildren(eqr, tchildren, true);
     460                 :            :         }
     461                 :     182765 :       }
     462         [ +  - ]:     731060 :       Trace("smt-proof-pp-debug")
     463                 :     365530 :           << "transform finish (" << r << ")" << std::endl;
     464                 :     365530 :     }
     465                 :            :     // apply transitivity if necessary
     466                 :     182765 :     Node eq = addProofForTrans(tchildren, cdp);
     467 [ +  - ][ -  + ]:     182765 :     if (eq.isNull() || eq[1] != args[0])
         [ +  - ][ -  + ]
                 [ -  - ]
     468                 :            :     {
     469                 :          0 :       DebugUnhandled() << "Failed proof for MACRO_SR_PRED_TRANSFORM";
     470                 :            :       Trace("smt-proof-pp-debug")
     471                 :            :           << "Failed transitivity from " << tchildren << std::endl;
     472                 :            :       return Node::null();
     473                 :            :     }
     474 [ +  + ][ -  - ]:     548295 :     cdp->addStep(eq[1], ProofRule::EQ_RESOLVE, {children[0], eq}, {});
     475                 :     182765 :     return args[0];
     476                 :     182765 :   }
     477         [ +  + ]:     421795 :   else if (id == ProofRule::CHAIN_M_RESOLUTION)
     478                 :            :   {
     479                 :      40618 :     ProofNodeManager* pnm = d_env.getProofNodeManager();
     480                 :            :     // first generate the naive chain_resolution
     481 [ -  + ][ -  + ]:      40618 :     Assert(args.size() == 3);
                 [ -  - ]
     482                 :      40618 :     std::vector<Node> pols(args[1].begin(), args[1].end());
     483                 :      40618 :     std::vector<Node> lits(args[2].begin(), args[2].end());
     484 [ -  + ][ -  + ]:      40618 :     Assert(lits.size() == pols.size());
                 [ -  - ]
     485 [ -  + ][ -  + ]:      40618 :     Assert(pols.size() == children.size() - 1);
                 [ -  - ]
     486                 :      40618 :     NodeManager* nm = nodeManager();
     487                 :      40618 :     std::vector<Node> chainResArgs(args.begin() + 1, args.end());
     488                 :      40618 :     Node chainConclusion = d_pc->checkDebug(
     489                 :      40618 :         ProofRule::CHAIN_RESOLUTION, children, chainResArgs, Node::null(), "");
     490         [ +  - ]:      40618 :     Trace("smt-proof-pp-debug") << "Original conclusion: " << args[0] << "\n";
     491         [ +  - ]:      81236 :     Trace("smt-proof-pp-debug")
     492                 :      40618 :         << "chainRes conclusion: " << chainConclusion << "\n";
     493         [ +  - ]:      81236 :     Trace("crowding-lits")
     494                 :      40618 :         << "Original conclusion and chainRes conclusion differ\n";
     495                 :            :     // There are n cases:
     496                 :            :     // - if the conclusion is the same, just replace
     497                 :            :     // - if they have the same literals but in different quantity, add a
     498                 :            :     //   FACTORING step
     499                 :            :     // - if the order is not the same, add a REORDERING step
     500                 :            :     // - if there are literals in chainConclusion that are not in the original
     501                 :            :     //   conclusion, we need to transform the CHAIN_M_RESOLUTION into a series
     502                 :            :     //   of CHAIN_RESOLUTION + FACTORING steps, so that we explicitly eliminate
     503                 :            :     //   all these "crowding" literals. We do this via FACTORING so we avoid
     504                 :            :     //   adding an exponential number of premises, which would happen if we just
     505                 :            :     //   repeated in the premises the clauses needed for eliminating crowding
     506                 :            :     //   literals, which could themselves add crowding literals.
     507         [ +  + ]:      40618 :     if (chainConclusion == args[0])
     508                 :            :     {
     509         [ +  - ]:      17183 :       Trace("smt-proof-pp-debug") << "..same conclusion, DONE.\n";
     510         [ +  - ]:      17183 :       Trace("crowding-lits") << "..same conclusion, DONE.\n";
     511                 :      17183 :       cdp->addStep(
     512                 :            :           chainConclusion, ProofRule::CHAIN_RESOLUTION, children, chainResArgs);
     513                 :      17183 :       return chainConclusion;
     514                 :            :     }
     515                 :      23435 :     size_t initProofSize = cdp->getNumProofNodes();
     516                 :            :     // If we got here, then chainConclusion is NECESSARILY an OR node
     517 [ -  + ][ -  + ]:      23435 :     Assert(chainConclusion.getKind() == Kind::OR);
                 [ -  - ]
     518                 :            :     // get the literals in the chain conclusion
     519                 :      23435 :     std::vector<Node> chainConclusionLits{chainConclusion.begin(),
     520                 :      23435 :                                           chainConclusion.end()};
     521                 :      23435 :     std::set<Node> chainConclusionLitsSet{chainConclusion.begin(),
     522                 :      23435 :                                           chainConclusion.end()};
     523         [ +  - ]:      46870 :     Trace("smt-proof-pp-debug2")
     524                 :      23435 :         << "..chainConclusionLits: " << chainConclusionLits << "\n";
     525         [ +  - ]:      46870 :     Trace("smt-proof-pp-debug2")
     526                 :      23435 :         << "..chainConclusionLitsSet: " << chainConclusionLitsSet << "\n";
     527                 :      23435 :     std::vector<Node> conclusionLits;
     528                 :            :     // is args[0] a singleton clause? Yes if it's not an OR node. One might also
     529                 :            :     // think that it is a singleton if args[0] occurs in chainConclusionLitsSet.
     530                 :            :     // However it's not possible to know this only looking at the sets. For
     531                 :            :     // example with
     532                 :            :     //
     533                 :            :     //  args[0]                : (or b c)
     534                 :            :     //  chairConclusionLitsSet : {b, c, (or b c)}
     535                 :            :     //
     536                 :            :     // we have that if args[0] occurs in the set but as a crowding literal, then
     537                 :            :     // args[0] is *not* a singleton clause. But if b and c were crowding
     538                 :            :     // literals, then args[0] would be a singleton clause. Since our intention
     539                 :            :     // is to determine who are the crowding literals exactly based on whether
     540                 :            :     // args[0] is a singleton or not, we must determine in another way whether
     541                 :            :     // args[0] is a singleton.
     542                 :            :     //
     543                 :            :     // Thus we rely on the standard utility to determine if args[0] is singleton
     544                 :            :     // based on the premises and arguments of the resolution
     545                 :      23435 :     std::vector<Node> chainResArgsOrig;
     546                 :            :     // the proof utilities below expect to interleave literals and polarities
     547         [ +  + ]:     557757 :     for (size_t i = 0, nsteps = args[1].getNumChildren(); i < nsteps; i++)
     548                 :            :     {
     549                 :     534322 :       chainResArgsOrig.push_back(args[1][i]);
     550                 :     534322 :       chainResArgsOrig.push_back(args[2][i]);
     551                 :            :     }
     552         [ +  + ]:      23435 :     if (proof::isSingletonClause(args[0], children, chainResArgsOrig))
     553                 :            :     {
     554                 :       1058 :       conclusionLits.push_back(args[0]);
     555                 :            :     }
     556                 :            :     else
     557                 :            :     {
     558 [ -  + ][ -  + ]:      22377 :       Assert(args[0].getKind() == Kind::OR);
                 [ -  - ]
     559                 :      67131 :       conclusionLits.insert(
     560                 :      89508 :           conclusionLits.end(), args[0].begin(), args[0].end());
     561                 :            :     }
     562                 :      23435 :     std::set<Node> conclusionLitsSet{conclusionLits.begin(),
     563                 :      23435 :                                      conclusionLits.end()};
     564                 :            :     // If the sets are different, there are "crowding" literals, i.e. literals
     565                 :            :     // that were removed by implicit multi-usage of premises in the resolution
     566                 :            :     // chain.
     567         [ +  + ]:      23435 :     if (chainConclusionLitsSet != conclusionLitsSet)
     568                 :            :     {
     569                 :      20549 :       chainResArgsOrig.insert(chainResArgsOrig.begin(), args[0]);
     570         [ +  - ]:      20549 :       Trace("smt-proof-pp-debug") << "..need to eliminate crowding lits.\n";
     571         [ +  - ]:      20549 :       Trace("crowding-lits") << "..need to eliminate crowding lits.\n";
     572         [ +  - ]:      20549 :       Trace("crowding-lits") << "..premises: " << children << "\n";
     573         [ +  - ]:      20549 :       Trace("crowding-lits") << "..args: " << chainResArgsOrig << "\n";
     574                 :            :       chainConclusion =
     575                 :      20549 :           proof::eliminateCrowdingLits(nm,
     576                 :      20549 :                                        d_env.getOptions().proof.optResReconSize,
     577                 :            :                                        chainConclusionLits,
     578                 :            :                                        conclusionLits,
     579                 :            :                                        children,
     580                 :            :                                        chainResArgsOrig,
     581                 :            :                                        cdp,
     582                 :      20549 :                                        pnm);
     583                 :            :       // update vector of lits. Note that the set is no longer used, so we don't
     584                 :            :       // need to update it
     585                 :            :       //
     586                 :            :       // We need again to check whether chainConclusion is a singleton
     587                 :            :       // clause. As above, it's a singleton if it's in the original
     588                 :            :       // chainConclusionLitsSet.
     589                 :      20549 :       chainConclusionLits.clear();
     590         [ -  + ]:      20549 :       if (chainConclusionLitsSet.count(chainConclusion))
     591                 :            :       {
     592                 :          0 :         chainConclusionLits.push_back(chainConclusion);
     593                 :            :       }
     594                 :            :       else
     595                 :            :       {
     596 [ -  + ][ -  + ]:      20549 :         Assert(chainConclusion.getKind() == Kind::OR);
                 [ -  - ]
     597                 :      20549 :         chainConclusionLits.insert(chainConclusionLits.end(),
     598                 :            :                                    chainConclusion.begin(),
     599                 :            :                                    chainConclusion.end());
     600                 :            :       }
     601                 :            :     }
     602                 :            :     else
     603                 :            :     {
     604         [ +  - ]:       2886 :       Trace("smt-proof-pp-debug") << "..add chainRes step directly.\n";
     605                 :       2886 :       cdp->addStep(
     606                 :            :           chainConclusion, ProofRule::CHAIN_RESOLUTION, children, chainResArgs);
     607                 :            :     }
     608         [ +  - ]:      46870 :     Trace("smt-proof-pp-debug")
     609                 :      23435 :         << "Conclusion after chain_res/elimCrowd: " << chainConclusion << "\n";
     610         [ +  - ]:      46870 :     Trace("smt-proof-pp-debug")
     611                 :      23435 :         << "Conclusion lits: " << chainConclusionLits << "\n";
     612                 :            :     // Placeholder for running conclusion
     613                 :      23435 :     Node n = chainConclusion;
     614                 :            :     // factoring
     615         [ +  + ]:      23435 :     if (chainConclusionLits.size() != conclusionLits.size())
     616                 :            :     {
     617         [ +  - ]:      22554 :       Trace("smt-proof-pp-debug") << "..add factoring step.\n";
     618                 :            :       // We build it rather than taking conclusionLits because the order may be
     619                 :            :       // different
     620                 :      22554 :       std::vector<Node> factoredLits;
     621                 :      22554 :       std::unordered_set<TNode> clauseSet;
     622         [ +  + ]:     766936 :       for (size_t i = 0, size = chainConclusionLits.size(); i < size; ++i)
     623                 :            :       {
     624         [ +  + ]:     744382 :         if (clauseSet.count(chainConclusionLits[i]))
     625                 :            :         {
     626                 :     326736 :           continue;
     627                 :            :         }
     628                 :     417646 :         factoredLits.push_back(n[i]);
     629                 :     417646 :         clauseSet.insert(n[i]);
     630                 :            :       }
     631                 :      22554 :       Node factored = factoredLits.empty() ? nm->mkConst(false)
     632                 :      22554 :                       : factoredLits.size() == 1
     633                 :       1058 :                           ? factoredLits[0]
     634 [ -  + ][ +  + ]:      46166 :                           : nm->mkNode(Kind::OR, factoredLits);
     635                 :      45108 :       cdp->addStep(factored, ProofRule::FACTORING, {n}, {});
     636                 :      22554 :       n = factored;
     637                 :      22554 :     }
     638                 :            :     // either same node or n as a clause
     639 [ +  + ][ +  - ]:      23435 :     Assert(n == args[0] || n.getKind() == Kind::OR);
         [ -  + ][ -  + ]
                 [ -  - ]
     640                 :            :     // reordering
     641         [ +  + ]:      23435 :     if (n != args[0])
     642                 :            :     {
     643         [ +  - ]:      20264 :       Trace("smt-proof-pp-debug") << "..add reordering step.\n";
     644                 :      60792 :       cdp->addStep(args[0], ProofRule::REORDERING, {n}, {args[0]});
     645                 :            :     }
     646         [ +  - ]:      46870 :     Trace("crowding-lits") << "Number of added proof nodes: "
     647                 :      23435 :                            << cdp->getNumProofNodes() - initProofSize << "\n";
     648                 :      23435 :     return args[0];
     649                 :      40618 :   }
     650         [ +  + ]:     381177 :   else if (id == ProofRule::SUBS)
     651                 :            :   {
     652                 :      17361 :     NodeManager* nm = nodeManager();
     653                 :            :     // Notice that a naive way to reconstruct SUBS is to do a term conversion
     654                 :            :     // proof for each substitution.
     655                 :            :     // The proof of f(a) * { a -> g(b) } * { b -> c } = f(g(c)) is:
     656                 :            :     //   TRANS( CONG{f}( a=g(b) ), CONG{f}( CONG{g}( b=c ) ) )
     657                 :            :     // Notice that more optimal proofs are possible that do a single traversal
     658                 :            :     // over t. This is done by applying later substitutions to the range of
     659                 :            :     // previous substitutions, until a final simultaneous substitution is
     660                 :            :     // applied to t.  For instance, in the above example, we first prove:
     661                 :            :     //   CONG{g}( b = c )
     662                 :            :     // by applying the second substitution { b -> c } to the range of the first,
     663                 :            :     // giving us a proof of g(b)=g(c). We then construct the updated proof
     664                 :            :     // by tranitivity:
     665                 :            :     //   TRANS( a=g(b), CONG{g}( b=c ) )
     666                 :            :     // We then apply the substitution { a -> g(c), b -> c } to f(a), to obtain:
     667                 :            :     //   CONG{f}( TRANS( a=g(b), CONG{g}( b=c ) ) )
     668                 :            :     // which notice is more compact than the proof above.
     669                 :      17361 :     Node t = args[0];
     670                 :            :     // get the kind of substitution
     671                 :      17361 :     MethodId ids = MethodId::SB_DEFAULT;
     672         [ +  + ]:      17361 :     if (args.size() >= 2)
     673                 :            :     {
     674                 :       9235 :       getMethodId(args[1], ids);
     675                 :            :     }
     676                 :      17361 :     MethodId ida = MethodId::SBA_SEQUENTIAL;
     677         [ +  + ]:      17361 :     if (args.size() >= 3)
     678                 :            :     {
     679                 :       9061 :       getMethodId(args[2], ida);
     680                 :            :     }
     681         [ +  - ]:      34722 :     Trace("smt-proof-pp-debug")
     682                 :      17361 :         << "Expand SUBS " << ids << " " << ida << std::endl;
     683                 :      17361 :     std::vector<std::shared_ptr<CDProof>> pfs;
     684                 :      17361 :     std::vector<TNode> vsList;
     685                 :      17361 :     std::vector<TNode> ssList;
     686                 :      17361 :     std::vector<TNode> fromList;
     687                 :      17361 :     std::vector<ProofGenerator*> pgs;
     688                 :            :     // first, compute the entire substitution
     689         [ +  + ]:      35627 :     for (size_t i = 0, nchild = children.size(); i < nchild; i++)
     690                 :            :     {
     691                 :            :       // get the substitution
     692                 :      18266 :       builtin::BuiltinProofRuleChecker::getSubstitutionFor(
     693                 :      18266 :           children[i], vsList, ssList, fromList, ids);
     694                 :            :       // ensure proofs for each formula in fromList
     695 [ +  + ][ +  - ]:      18266 :       if (children[i].getKind() == Kind::AND && ids == MethodId::SB_DEFAULT)
                 [ +  + ]
     696                 :            :       {
     697         [ +  + ]:    1070521 :         for (size_t j = 0, nchildi = children[i].getNumChildren(); j < nchildi;
     698                 :            :              j++)
     699                 :            :         {
     700                 :    1062945 :           Node nodej = nm->mkConstInt(Rational(j));
     701                 :    5314725 :           cdp->addStep(
     702                 :    2125890 :               children[i][j], ProofRule::AND_ELIM, {children[i]}, {nodej});
     703                 :    1062945 :         }
     704                 :            :       }
     705                 :            :     }
     706                 :      17361 :     std::vector<Node> vvec;
     707                 :      17361 :     std::vector<Node> svec;
     708         [ +  + ]:    1090996 :     for (size_t i = 0, nvs = vsList.size(); i < nvs; i++)
     709                 :            :     {
     710                 :            :       // Note we process in forward order, since later substitution should be
     711                 :            :       // applied to earlier ones, and the last child of a SUBS is processed
     712                 :            :       // first.
     713                 :    1073635 :       TNode var = vsList[i];
     714                 :    1073635 :       TNode subs = ssList[i];
     715                 :    1073635 :       TNode childFrom = fromList[i];
     716         [ +  - ]:    2147270 :       Trace("smt-proof-pp-debug")
     717                 :          0 :           << "...process " << var << " -> " << subs << " (" << childFrom << ", "
     718                 :    1073635 :           << ids << ")" << std::endl;
     719                 :            :       // apply the current substitution to the range
     720 [ +  + ][ +  + ]:    1073635 :       if (!vvec.empty() && ida == MethodId::SBA_SEQUENTIAL)
                 [ +  + ]
     721                 :            :       {
     722                 :            :         Node ss =
     723                 :        905 :             subs.substitute(vvec.begin(), vvec.end(), svec.begin(), svec.end());
     724         [ +  + ]:        905 :         if (ss != subs)
     725                 :            :         {
     726         [ +  - ]:        664 :           Trace("smt-proof-pp-debug")
     727                 :          0 :               << "......updated to " << var << " -> " << ss
     728                 :        332 :               << " based on previous substitution" << std::endl;
     729                 :            :           // make the proof for the tranitivity step
     730                 :        332 :           std::shared_ptr<CDProof> pf = std::make_shared<CDProof>(d_env);
     731                 :        332 :           pfs.push_back(pf);
     732                 :            :           // prove the updated substitution
     733                 :            :           TConvProofGenerator tcg(d_env,
     734                 :            :                                   nullptr,
     735                 :            :                                   TConvPolicy::ONCE,
     736                 :            :                                   TConvCachePolicy::NEVER,
     737                 :            :                                   "nested_SUBS_TConvProofGenerator",
     738                 :            :                                   nullptr,
     739                 :        664 :                                   true);
     740                 :            :           // add previous rewrite steps
     741         [ +  + ]:       2140 :           for (unsigned j = 0, nvars = vvec.size(); j < nvars; j++)
     742                 :            :           {
     743                 :            :             // substitutions are pre-rewrites
     744                 :       1808 :             tcg.addRewriteStep(vvec[j], svec[j], pgs[j], true);
     745                 :            :           }
     746                 :            :           // get the proof for the update to the current substitution
     747                 :        332 :           Node seqss = subs.eqNode(ss);
     748                 :        332 :           std::shared_ptr<ProofNode> pfn = tcg.getProofFor(seqss);
     749 [ -  + ][ -  + ]:        332 :           Assert(pfn != nullptr);
                 [ -  - ]
     750                 :            :           // add the proof
     751                 :        332 :           pf->addProof(pfn);
     752                 :            :           // get proof for childFrom from cdp
     753                 :        332 :           pfn = cdp->getProofFor(childFrom);
     754                 :        332 :           pf->addProof(pfn);
     755                 :            :           // ensure we have a proof of var = subs
     756                 :        664 :           Node veqs = addProofForSubsStep(var, subs, childFrom, pf.get());
     757                 :            :           // transitivity
     758 [ +  + ][ -  - ]:        996 :           pf->addStep(var.eqNode(ss), ProofRule::TRANS, {veqs, seqss}, {});
     759                 :            :           // add to the substitution
     760                 :        332 :           vvec.push_back(var);
     761                 :        332 :           svec.push_back(ss);
     762         [ +  - ]:        332 :           pgs.push_back(pf.get());
     763                 :        332 :           continue;
     764                 :        332 :         }
     765         [ +  + ]:        905 :       }
     766                 :            :       // Just use equality from CDProof, but ensure we have a proof in cdp.
     767                 :            :       // This may involve a TRUE_INTRO/FALSE_INTRO if the substitution step
     768                 :            :       // uses the assumption childFrom as a Boolean assignment (e.g.
     769                 :            :       // childFrom = true if we are using MethodId::SB_LITERAL).
     770                 :    1073303 :       addProofForSubsStep(var, subs, childFrom, cdp);
     771                 :    1073303 :       vvec.push_back(var);
     772                 :    1073303 :       svec.push_back(subs);
     773         [ +  - ]:    1073303 :       pgs.push_back(cdp);
     774 [ +  + ][ +  + ]:    1074299 :     }
                 [ +  + ]
     775                 :            :     // should be implied by the substitution now
     776                 :      17361 :     TConvPolicy tcpolicy = ida == MethodId::SBA_FIXPOINT ? TConvPolicy::FIXPOINT
     777                 :            :                                                          : TConvPolicy::ONCE;
     778                 :            :     TConvProofGenerator tcpg(d_env,
     779                 :            :                              nullptr,
     780                 :            :                              tcpolicy,
     781                 :            :                              TConvCachePolicy::NEVER,
     782                 :            :                              "SUBS_TConvProofGenerator",
     783                 :            :                              nullptr,
     784                 :      34722 :                              true);
     785         [ +  + ]:    1090996 :     for (unsigned j = 0, nvars = vvec.size(); j < nvars; j++)
     786                 :            :     {
     787                 :            :       // substitutions are pre-rewrites
     788                 :    1073635 :       tcpg.addRewriteStep(vvec[j], svec[j], pgs[j], true);
     789         [ +  + ]:    1073635 :       if (ida == MethodId::SBA_FIXPOINT)
     790                 :            :       {
     791                 :            :         // fixed point substitutions are also post-rewrites
     792                 :    1064394 :         tcpg.addRewriteStep(vvec[j], svec[j], pgs[j], false);
     793                 :            :       }
     794                 :            :     }
     795                 :            :     // add the proof constructed by the term conversion utility
     796                 :      17361 :     std::shared_ptr<ProofNode> pfn = tcpg.getProofForRewriting(t);
     797                 :      17361 :     Node eq = pfn->getResult();
     798                 :            :     Node ts = builtin::BuiltinProofRuleChecker::applySubstitution(
     799                 :      17361 :         t, children, ids, ida);
     800                 :      17361 :     Node eqq = t.eqNode(ts);
     801                 :            :     // should have the same conclusion, if not, then tcpg does not agree with
     802                 :            :     // the substitution.
     803         [ -  + ]:      17361 :     if (eq != eqq)
     804                 :            :     {
     805                 :            :       // this can happen in very rare cases where e.g. x -> a; f(x) -> b
     806                 :            :       // and t*{x -> a} = t*{x -> a}*{f(x) -> b} != t*{x -> a, f(x) -> b}
     807 [ -  - ][ -  - ]:          0 :       if (ida == MethodId::SBA_SEQUENTIAL && vsList.size() > 1)
                 [ -  - ]
     808                 :            :       {
     809         [ -  - ]:          0 :         Trace("smt-proof-pp-debug")
     810                 :          0 :             << "resort to sequential reconstruction" << std::endl;
     811                 :            :         // just do the naive sequential reconstruction,
     812                 :            :         // (SUBS F1 ... Fn t) ---> (TRANS (SUBS F1 t) ... (SUBS Fn tn))
     813                 :          0 :         Node curr = t;
     814                 :          0 :         std::vector<Node> transChildren;
     815         [ -  - ]:          0 :         for (size_t i = 0, nvs = vsList.size(); i < nvs; i++)
     816                 :            :         {
     817                 :          0 :           size_t ii = nvs - 1 - i;
     818                 :          0 :           TNode var = vsList[ii];
     819                 :          0 :           TNode subs = ssList[ii];
     820                 :          0 :           Node next = curr.substitute(var, subs);
     821         [ -  - ]:          0 :           if (next != curr)
     822                 :            :           {
     823                 :          0 :             Node eqo = curr.eqNode(next);
     824                 :          0 :             transChildren.push_back(eqo);
     825                 :            :             // ensure the proof for the substitution exists
     826                 :          0 :             addProofForSubsStep(var, subs, fromList[ii], cdp);
     827                 :            :             // do the single step SUBS on curr with the default arguments
     828                 :          0 :             cdp->addStep(eqo, ProofRule::SUBS, {var.eqNode(subs)}, {curr});
     829                 :          0 :             curr = next;
     830                 :          0 :           }
     831                 :          0 :         }
     832                 :          0 :         Assert(curr == ts);
     833                 :          0 :         cdp->addStep(eqq, ProofRule::TRANS, transChildren, {});
     834                 :          0 :       }
     835                 :            :       else
     836                 :            :       {
     837         [ -  - ]:          0 :         Trace("smt-proof-pp-debug")
     838                 :          0 :             << "resort to TRUST_SUBS" << std::endl
     839                 :          0 :             << eq << std::endl
     840                 :          0 :             << eqq << std::endl
     841                 :          0 :             << "from " << children << " applied to " << t << std::endl;
     842                 :          0 :         cdp->addTrustedStep(eqq, TrustId::SUBS_NO_ELABORATE, children, {});
     843                 :            :       }
     844                 :            :     }
     845                 :            :     else
     846                 :            :     {
     847                 :      17361 :       cdp->addProof(pfn);
     848                 :            :     }
     849                 :      17361 :     return eqq;
     850                 :      17361 :   }
     851         [ +  + ]:     363816 :   else if (id == ProofRule::MACRO_REWRITE)
     852                 :            :   {
     853                 :            :     // get the kind of rewrite
     854                 :     316698 :     MethodId idr = MethodId::RW_REWRITE;
     855                 :     316698 :     TheoryId theoryId = d_env.theoryOf(args[0]);
     856         [ +  + ]:     316698 :     if (args.size() >= 2)
     857                 :            :     {
     858                 :       4584 :       getMethodId(args[1], idr);
     859                 :            :     }
     860                 :     316698 :     Rewriter* rr = d_env.getRewriter();
     861                 :     316698 :     Node ret = d_env.rewriteViaMethod(args[0], idr);
     862                 :     316698 :     Node eq = args[0].eqNode(ret);
     863 [ +  + ][ +  + ]:     316698 :     if (idr == MethodId::RW_REWRITE || idr == MethodId::RW_REWRITE_EQ_EXT)
     864                 :            :     {
     865                 :            :       // rewrites from theory::Rewriter
     866                 :     314786 :       bool isExtEq = (idr == MethodId::RW_REWRITE_EQ_EXT);
     867                 :            :       // use rewrite with proof interface
     868                 :     314786 :       TrustNode trn = rr->rewriteWithProof(args[0], isExtEq);
     869                 :     314786 :       std::shared_ptr<ProofNode> pfn = trn.toProofNode();
     870         [ +  + ]:     314786 :       if (pfn == nullptr)
     871                 :            :       {
     872         [ +  - ]:       1712 :         Trace("smt-proof-pp-debug")
     873                 :        856 :             << "Use TRUST_REWRITE for " << eq << std::endl;
     874                 :            :         // did not have a proof of rewriting, probably isExtEq is true
     875         [ +  - ]:        856 :         if (isExtEq)
     876                 :            :         {
     877                 :            :           // update to TRUST_THEORY_REWRITE with idr
     878 [ -  + ][ -  + ]:        856 :           Assert(args.size() >= 1);
                 [ -  - ]
     879                 :            :           Node tid = builtin::BuiltinProofRuleChecker::mkTheoryIdNode(
     880                 :        856 :               nodeManager(), theoryId);
     881 [ +  + ][ -  - ]:       4280 :           cdp->addStep(
     882                 :        856 :               eq, ProofRule::TRUST_THEORY_REWRITE, {}, {eq, tid, args[1]});
     883                 :        856 :         }
     884                 :            :         else
     885                 :            :         {
     886                 :            :           // this should never be applied
     887                 :          0 :           cdp->addTrustedStep(eq, TrustId::REWRITE_NO_ELABORATE, {}, {});
     888                 :            :         }
     889                 :            :       }
     890                 :            :       else
     891                 :            :       {
     892                 :     313930 :         cdp->addProof(pfn);
     893                 :            :       }
     894                 :     629572 :       Assert(trn.getNode() == ret)
     895 [ -  + ][ -  - ]:     314786 :           << "Unexpected rewrite " << args[0] << std::endl
     896                 :     314786 :           << "Got: " << trn.getNode() << std::endl
     897                 :          0 :           << "Expected: " << ret;
     898                 :     314786 :     }
     899         [ -  + ]:       1912 :     else if (idr == MethodId::RW_EVALUATE)
     900                 :            :     {
     901                 :            :       // change to evaluate, which is never eliminated
     902                 :          0 :       cdp->addStep(eq, ProofRule::EVALUATE, {}, {args[0]});
     903                 :            :     }
     904                 :            :     else
     905                 :            :     {
     906                 :       1912 :       Node retCurr = args[0];
     907                 :       1912 :       std::vector<Node> transEq;
     908                 :            :       // try to reconstruct the (extended) rewrite
     909                 :            :       // first, use the standard rewriter followed by the extended equality
     910                 :            :       // rewriter
     911         [ +  + ]:       2254 :       for (size_t i = 0; i < 2; i++)
     912                 :            :       {
     913 [ +  + ][ +  + ]:       2190 :         if (i == 1 && retCurr.getKind() != Kind::EQUAL)
                 [ +  + ]
     914                 :            :         {
     915                 :       1848 :           break;
     916                 :            :         }
     917                 :       2150 :         MethodId midi =
     918         [ +  + ]:       2150 :             i == 0 ? MethodId::RW_REWRITE : MethodId::RW_REWRITE_EQ_EXT;
     919                 :       2150 :         Node retDef = d_env.rewriteViaMethod(retCurr, midi);
     920         [ +  + ]:       2150 :         if (retDef != retCurr)
     921                 :            :         {
     922                 :            :           // will expand this as a default rewrite if needed
     923                 :       2006 :           Node eqd = retCurr.eqNode(retDef);
     924                 :       2006 :           Node mid = mkMethodId(nodeManager(), midi);
     925 [ +  + ][ -  - ]:       6018 :           cdp->addStep(eqd, ProofRule::MACRO_REWRITE, {}, {retCurr, mid});
     926                 :       2006 :           transEq.push_back(eqd);
     927                 :       2006 :         }
     928                 :       2150 :         retCurr = retDef;
     929         [ +  + ]:       2150 :         if (retCurr == ret)
     930                 :            :         {
     931                 :            :           // already successful
     932                 :       1808 :           break;
     933                 :            :         }
     934         [ +  + ]:       2150 :       }
     935         [ +  + ]:       1912 :       if (retCurr != ret)
     936                 :            :       {
     937                 :            :         // We were unable to show it via ordinary rewriting, so we insert
     938                 :            :         // a trusted step. This cannot be TRUST_THEORY_REWRITE since it is
     939                 :            :         // not an ordinary theory rewrite.
     940                 :        104 :         Node eqp = retCurr.eqNode(ret);
     941                 :        104 :         cdp->addTrustedStep(eqp, TrustId::EXT_THEORY_REWRITE, {}, {});
     942                 :        104 :         transEq.push_back(eqp);
     943                 :        104 :       }
     944         [ +  + ]:       1912 :       if (transEq.size() > 1)
     945                 :            :       {
     946                 :            :         // put together with transitivity
     947                 :        194 :         cdp->addStep(eq, ProofRule::TRANS, transEq, {});
     948                 :            :       }
     949                 :       1912 :     }
     950         [ -  + ]:     316698 :     if (args[0] == ret)
     951                 :            :     {
     952                 :            :       // should not be necessary typically
     953                 :          0 :       cdp->addStep(eq, ProofRule::REFL, {}, {args[0]});
     954                 :            :     }
     955                 :     316698 :     return eq;
     956                 :     316698 :   }
     957         [ +  + ]:      47118 :   else if (id == ProofRule::MACRO_ARITH_SCALE_SUM_UB)
     958                 :            :   {
     959                 :            :     Node sumBounds =
     960                 :      30672 :         theory::arith::expandMacroSumUb(nodeManager(), children, args, cdp);
     961 [ -  + ][ -  + ]:      30672 :     Assert(!sumBounds.isNull());
                 [ -  - ]
     962 [ +  - ][ +  - ]:      30672 :     Assert(res.isNull() || sumBounds == res);
         [ -  + ][ -  + ]
                 [ -  - ]
     963                 :      30672 :     return sumBounds;
     964                 :      30672 :   }
     965         [ +  + ]:      16446 :   else if (id == ProofRule::MACRO_STRING_INFERENCE)
     966                 :            :   {
     967                 :            :     // get the arguments
     968                 :       9151 :     Node conc;
     969                 :            :     InferenceId iid;
     970                 :            :     bool isRev;
     971                 :       9151 :     std::vector<Node> exp;
     972         [ +  - ]:       9151 :     if (theory::strings::InferProofCons::unpackArgs(
     973                 :            :             args, conc, iid, isRev, exp))
     974                 :            :     {
     975         [ +  - ]:       9151 :       if (theory::strings::InferProofCons::convert(
     976                 :            :               d_env, iid, isRev, conc, exp, cdp))
     977                 :            :       {
     978                 :       9151 :         return conc;
     979                 :            :       }
     980                 :            :     }
     981 [ -  + ][ -  + ]:      18302 :   }
     982         [ +  - ]:       7295 :   else if (id == ProofRule::MACRO_BV_BITBLAST)
     983                 :            :   {
     984                 :       7295 :     bv::BBProof bb(d_env, nullptr, true);
     985                 :       7295 :     Node eq = args[0];
     986 [ -  + ][ -  + ]:       7295 :     Assert(eq.getKind() == Kind::EQUAL);
                 [ -  - ]
     987                 :       7295 :     bb.bbAtom(eq[0]);
     988                 :      14590 :     Node bbAtom = bb.getStoredBBAtom(eq[0]);
     989                 :       7295 :     bb.getProofGenerator()->addProofTo(eq[0].eqNode(bbAtom), cdp);
     990                 :       7295 :     return eq;
     991                 :       7295 :   }
     992                 :          0 :   return Node::null();
     993                 :            : }
     994                 :            : 
     995                 :      73944 : Node ProofPostprocessCallback::addExpandStep(ProofRule id,
     996                 :            :                                              const std::vector<Node>& children,
     997                 :            :                                              const std::vector<Node>& args,
     998                 :            :                                              CDProof* cdp)
     999                 :            : {
    1000                 :            :   // For now, this is a (locally) recursive call to expand macros; alternatively
    1001                 :            :   // we could add the step to cdp and allow the proof node updater to call us
    1002                 :            :   // again. This has the advantage that it may be possible to do more aggressive
    1003                 :            :   // merging, e.g. if a subproof in expanded call was duplicated in multiple
    1004                 :            :   // expansions, at the cost of generating more intermediate proof nodes. At
    1005                 :            :   // the moment, this is not worthwhile.
    1006                 :      73944 :   return expandMacros(id, children, args, cdp);
    1007                 :            : }
    1008                 :            : 
    1009                 :      25918 : Node ProofPostprocessCallback::addProofForWitnessForm(Node t, CDProof* cdp)
    1010                 :            : {
    1011                 :      25918 :   Node tw = SkolemManager::getOriginalForm(t);
    1012                 :      25918 :   Node eq = t.eqNode(tw);
    1013         [ +  + ]:      25918 :   if (t == tw)
    1014                 :            :   {
    1015                 :            :     // not necessary, add REFL step
    1016                 :       2560 :     cdp->addStep(eq, ProofRule::REFL, {}, {t});
    1017                 :       1280 :     return eq;
    1018                 :            :   }
    1019                 :      24638 :   std::shared_ptr<ProofNode> pn = d_wfpm.getProofFor(eq);
    1020         [ +  - ]:      24638 :   if (pn != nullptr)
    1021                 :            :   {
    1022                 :            :     // add the proof
    1023                 :      24638 :     cdp->addProof(pn);
    1024                 :            :   }
    1025                 :            :   else
    1026                 :            :   {
    1027                 :          0 :     DebugUnhandled() << "ProofPostprocessCallback::addProofForWitnessForm: failed "
    1028                 :          0 :                      "to add proof for witness form of "
    1029                 :            :                   << t;
    1030                 :            :   }
    1031                 :      24638 :   return eq;
    1032                 :      25918 : }
    1033                 :            : 
    1034                 :     698887 : Node ProofPostprocessCallback::addProofForTrans(
    1035                 :            :     const std::vector<Node>& tchildren, CDProof* cdp)
    1036                 :            : {
    1037                 :     698887 :   size_t tsize = tchildren.size();
    1038         [ +  + ]:     698887 :   if (tsize > 1)
    1039                 :            :   {
    1040                 :      48870 :     Node lhs = tchildren[0][0];
    1041                 :      48870 :     Node rhs = tchildren[tsize - 1][1];
    1042                 :      48870 :     Node eq = lhs.eqNode(rhs);
    1043                 :      48870 :     cdp->addStep(eq, ProofRule::TRANS, tchildren, {});
    1044                 :      48870 :     return eq;
    1045                 :      48870 :   }
    1046         [ +  + ]:     650017 :   else if (tsize == 1)
    1047                 :            :   {
    1048                 :     595996 :     return tchildren[0];
    1049                 :            :   }
    1050                 :      54021 :   return Node::null();
    1051                 :            : }
    1052                 :            : 
    1053                 :    1073635 : Node ProofPostprocessCallback::addProofForSubsStep(Node var,
    1054                 :            :                                                    Node subs,
    1055                 :            :                                                    Node assump,
    1056                 :            :                                                    CDProof* cdp)
    1057                 :            : {
    1058                 :            :   // ensure we have a proof of var = subs
    1059                 :    1073635 :   Node veqs = var.eqNode(subs);
    1060         [ +  + ]:    1073635 :   if (veqs != assump)
    1061                 :            :   {
    1062                 :            :     // should be true intro or false intro
    1063 [ -  + ][ -  + ]:        174 :     Assert(subs.isConst());
                 [ -  - ]
    1064                 :        522 :     cdp->addStep(
    1065                 :            :         veqs,
    1066         [ +  - ]:        174 :         subs.getConst<bool>() ? ProofRule::TRUE_INTRO : ProofRule::FALSE_INTRO,
    1067                 :            :         {assump},
    1068                 :            :         {});
    1069                 :            :   }
    1070                 :    1073635 :   return veqs;
    1071                 :          0 : }
    1072                 :            : 
    1073                 :     582718 : bool ProofPostprocessCallback::addToTransChildren(Node eq,
    1074                 :            :                                                   std::vector<Node>& tchildren,
    1075                 :            :                                                   bool isSymm)
    1076                 :            : {
    1077 [ -  + ][ -  + ]:     582718 :   Assert(!eq.isNull());
                 [ -  - ]
    1078 [ -  + ][ -  + ]:     582718 :   Assert(eq.getKind() == Kind::EQUAL);
                 [ -  - ]
    1079         [ +  + ]:     582718 :   if (eq[0] == eq[1])
    1080                 :            :   {
    1081                 :     177762 :     return false;
    1082                 :            :   }
    1083                 :     533691 :   Node equ = isSymm ? eq[1].eqNode(eq[0]) : eq;
    1084                 :     404956 :   Assert(tchildren.empty()
    1085                 :            :          || (tchildren[tchildren.size() - 1].getKind() == Kind::EQUAL
    1086                 :            :              && tchildren[tchildren.size() - 1][1] == equ[0]));
    1087                 :     404956 :   tchildren.push_back(equ);
    1088                 :     404956 :   return true;
    1089                 :     404956 : }
    1090                 :            : 
    1091                 :      18896 : ProofPostprocess::ProofPostprocess(Env& env,
    1092                 :            :                                    rewriter::RewriteDb* rdb,
    1093                 :      18896 :                                    bool updateScopedAssumptions)
    1094                 :            :     : EnvObj(env),
    1095                 :      18896 :       d_cb(env, updateScopedAssumptions),
    1096                 :      18896 :       d_elimTrustedRules(false),
    1097                 :            :       // the update merges subproofs if proofPpMerge is true
    1098                 :      18896 :       d_updater(env, d_cb, options().proof.proofPpMerge)
    1099                 :            : {
    1100         [ +  + ]:      18896 :   if (rdb != nullptr)
    1101                 :            :   {
    1102                 :       6655 :     d_ppdsl.reset(new ProofPostprocessDsl(env, rdb));
    1103                 :            :   }
    1104                 :      18896 : }
    1105                 :            : 
    1106                 :      37764 : ProofPostprocess::~ProofPostprocess() {}
    1107                 :            : 
    1108                 :      13591 : void ProofPostprocess::process(std::shared_ptr<ProofNode> pf,
    1109                 :            :                                ProofGenerator* pppg)
    1110                 :            : {
    1111                 :            :   // Initialize the callback, which computes necessary static information about
    1112                 :            :   // how to process, including how to process assumptions in pf.
    1113                 :      13591 :   d_cb.initializeUpdate(pppg);
    1114                 :            :   // now, process
    1115                 :      13591 :   d_updater.process(pf);
    1116                 :            : 
    1117                 :            :   // eliminate subtypes if option is specified
    1118         [ +  - ]:      13591 :   if (options().proof.proofElimSubtypes)
    1119                 :            :   {
    1120                 :      13591 :     SubtypeElimConverterCallback secc(d_env);
    1121                 :      13591 :     ProofNodeConverter subtypeConvert(d_env, secc);
    1122                 :      13591 :     std::shared_ptr<ProofNode> pfc = subtypeConvert.process(pf);
    1123 [ -  + ][ -  + ]:      13591 :     AlwaysAssert(pfc != nullptr);
                 [ -  - ]
    1124                 :            :     // now update
    1125                 :      13591 :     d_env.getProofNodeManager()->updateNode(pf.get(), pfc.get());
    1126                 :      13591 :   }
    1127 [ +  + ][ +  - ]:      13591 :   if (d_elimTrustedRules && d_ppdsl != nullptr)
                 [ +  + ]
    1128                 :            :   {
    1129                 :            :     // go back and find the (possibly new) trusted steps
    1130                 :       5618 :     std::vector<std::shared_ptr<ProofNode>> tproofs;
    1131                 :            :     std::unordered_set<ProofRule> trustRules{ProofRule::TRUST,
    1132                 :       5618 :                                              ProofRule::TRUST_THEORY_REWRITE};
    1133                 :       5618 :     expr::getSubproofRules(pf, trustRules, tproofs);
    1134                 :       5618 :     d_ppdsl->reconstruct(tproofs);
    1135                 :       5618 :   }
    1136                 :      13591 : }
    1137                 :            : 
    1138                 :     103525 : void ProofPostprocess::setEliminateRule(ProofRule rule)
    1139                 :            : {
    1140                 :     103525 :   d_cb.setEliminateRule(rule);
    1141                 :     103525 : }
    1142                 :            : 
    1143                 :       6655 : void ProofPostprocess::setEliminateAllTrustedRules()
    1144                 :            : {
    1145                 :       6655 :   d_elimTrustedRules = true;
    1146                 :       6655 : }
    1147                 :            : 
    1148                 :      10173 : void ProofPostprocess::setAssertions(const std::vector<Node>& assertions,
    1149                 :            :                                      bool doDebug)
    1150                 :            : {
    1151                 :      10173 :   d_updater.setFreeAssumptions(assertions, doDebug);
    1152                 :      10173 : }
    1153                 :            : 
    1154                 :            : }  // namespace smt
    1155                 :            : }  // namespace cvc5::internal

Generated by: LCOV version 1.14