LCOV - code coverage report
Current view: top level - buildbot/coverage/build/src/rewriter - rewrite_proof_rule.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 139 161 86.3 %
Date: 2026-03-05 11:40:39 Functions: 15 19 78.9 %
Branches: 68 106 64.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                 :            :  * proof rewrite rule class
      11                 :            :  */
      12                 :            : 
      13                 :            : #include "rewriter/rewrite_proof_rule.h"
      14                 :            : 
      15                 :            : #include <sstream>
      16                 :            : 
      17                 :            : #include "expr/aci_norm.h"
      18                 :            : #include "expr/nary_term_util.h"
      19                 :            : #include "expr/node_algorithm.h"
      20                 :            : #include "proof/proof_checker.h"
      21                 :            : 
      22                 :            : using namespace cvc5::internal::kind;
      23                 :            : 
      24                 :            : namespace cvc5::internal {
      25                 :            : namespace rewriter {
      26                 :            : 
      27                 :    2938383 : RewriteProofRule::RewriteProofRule() : d_id(ProofRewriteRule::NONE) {}
      28                 :            : 
      29                 :    2938383 : void RewriteProofRule::init(ProofRewriteRule id,
      30                 :            :                             const std::vector<Node>& userFvs,
      31                 :            :                             const std::vector<Node>& fvs,
      32                 :            :                             const std::vector<Node>& cond,
      33                 :            :                             Node conc,
      34                 :            :                             Node context,
      35                 :            :                             Level _level)
      36                 :            : {
      37                 :            :   // not initialized yet
      38 [ +  - ][ +  - ]:    2938383 :   Assert(d_cond.empty() && d_fvs.empty());
         [ -  + ][ -  + ]
                 [ -  - ]
      39                 :    2938383 :   d_id = id;
      40                 :    2938383 :   d_userFvs = userFvs;
      41                 :    2938383 :   d_level = _level;
      42                 :    2938383 :   std::map<Node, Node> condDef;
      43         [ +  + ]:    5283759 :   for (const Node& c : cond)
      44                 :            :   {
      45         [ -  + ]:    2345376 :     if (!expr::getListVarContext(c, d_listVarCtx))
      46                 :            :     {
      47                 :          0 :       Unhandled() << "Ambiguous or illegal context for list variables in "
      48                 :          0 :                      "condition of rule "
      49                 :          0 :                   << id;
      50                 :            :     }
      51                 :    2345376 :     d_cond.push_back(c);
      52 [ +  - ][ +  + ]:    2345376 :     if (c.getKind() == Kind::EQUAL && c[0].getKind() == Kind::BOUND_VARIABLE)
         [ +  - ][ +  + ]
                 [ -  - ]
      53                 :            :     {
      54                 :     979461 :       condDef[c[0]] = c[1];
      55                 :            :     }
      56                 :            :   }
      57                 :    2938383 :   d_conc = conc;
      58                 :    2938383 :   d_context = context;
      59         [ -  + ]:    2938383 :   if (!expr::getListVarContext(conc, d_listVarCtx))
      60                 :            :   {
      61                 :          0 :     Unhandled() << "Ambiguous or illegal context for list variables in "
      62                 :          0 :                    "conclusion of rule "
      63                 :          0 :                 << id;
      64                 :            :   }
      65                 :            : 
      66                 :    2938383 :   std::unordered_set<Node> fvsCond;
      67         [ +  + ]:    5283759 :   for (const Node& c : d_cond)
      68                 :            :   {
      69                 :    2345376 :     expr::getFreeVariables(c, fvsCond);
      70                 :            :   }
      71                 :            : 
      72                 :            :   // ensure free variables in conditions and right hand side are either matched
      73                 :            :   // or are in defined conditions.
      74                 :    2938383 :   std::unordered_set<Node> fvsLhs;
      75                 :    2938383 :   expr::getFreeVariables(d_conc[0], fvsLhs);
      76                 :    2938383 :   std::unordered_set<Node> fvsUnmatched;
      77                 :    2938383 :   expr::getFreeVariables(d_conc[1], fvsUnmatched);
      78                 :    2938383 :   fvsUnmatched.insert(fvsCond.begin(), fvsCond.end());
      79                 :    2938383 :   std::map<Node, Node>::iterator itc;
      80         [ +  + ]:   10001163 :   for (const Node& v : fvsUnmatched)
      81                 :            :   {
      82         [ +  + ]:    7062780 :     if (fvsLhs.find(v) != fvsLhs.end())
      83                 :            :     {
      84                 :            :       // variable on left hand side
      85                 :    6209916 :       continue;
      86                 :            :     }
      87                 :     852864 :     itc = condDef.find(v);
      88         [ -  + ]:     852864 :     if (itc == condDef.end())
      89                 :            :     {
      90                 :          0 :       Unhandled()
      91                 :          0 :           << "Free variable " << v << " in rule " << id
      92                 :          0 :           << " is not on the left hand side, nor is defined in a condition";
      93                 :            :     }
      94                 :            :     // variable defined in the condition
      95                 :     852864 :     d_condDefinedVars[v] = itc->second;
      96                 :            :     // ensure the defining term does not itself contain free variables
      97                 :     852864 :     std::unordered_set<Node> fvst;
      98                 :     852864 :     expr::getFreeVariables(itc->second, fvst);
      99         [ +  + ]:    2145486 :     for (const Node& vt : fvst)
     100                 :            :     {
     101         [ -  + ]:    1292622 :       if (fvsLhs.find(vt) == fvsLhs.end())
     102                 :            :       {
     103                 :          0 :         Unhandled() << "Free variable " << vt << " in rule " << id
     104                 :            :                     << " is not on the left hand side of the rule, and it is "
     105                 :          0 :                        "used to give a definition to the free variable "
     106                 :          0 :                     << v;
     107                 :            :       }
     108                 :            :     }
     109                 :     852864 :   }
     110                 :            : 
     111                 :    2938383 :   d_numFv = fvs.size();
     112                 :            : 
     113         [ +  + ]:   11420382 :   for (const Node& v : fvs)
     114                 :            :   {
     115                 :    8481999 :     d_fvs.push_back(v);
     116         [ +  + ]:    8481999 :     if (fvsCond.find(v) == fvsCond.end())
     117                 :            :     {
     118                 :    4970598 :       d_noOccVars.insert(v);
     119                 :            :     }
     120                 :            :   }
     121                 :            :   // if fixed point, initialize match utility
     122         [ +  + ]:    2938383 :   if (d_context != Node::null())
     123                 :            :   {
     124                 :     113271 :     d_mt.addTerm(conc[0]);
     125                 :            : 
     126 [ -  + ][ -  + ]:     113271 :     Assert(d_context.getKind() == Kind::LAMBDA);
                 [ -  - ]
     127                 :     113271 :     Node var = d_context[0][0];
     128                 :     113271 :     Node curr = d_context[1];
     129         [ +  + ]:     193227 :     while (curr != var)
     130                 :            :     {
     131                 :      79956 :       size_t nchild = curr.getNumChildren();
     132                 :      79956 :       size_t cfind = nchild;
     133         [ +  - ]:     166575 :       for (size_t i = 0; i < nchild; i++)
     134                 :            :       {
     135                 :            :         // TODO (wishue #160): could use utility for finding path
     136         [ +  + ]:     166575 :         if (expr::hasSubterm(curr[i], var))
     137                 :            :         {
     138                 :      79956 :           cfind = i;
     139                 :      79956 :           break;
     140                 :            :         }
     141                 :            :       }
     142         [ -  + ]:      79956 :       if (cfind == nchild)
     143                 :            :       {
     144                 :          0 :         Unhandled() << "Failed to find context variable";
     145                 :            :       }
     146                 :      79956 :       d_pathToCtx.emplace_back(cfind);
     147                 :      79956 :       curr = curr[cfind];
     148                 :            :     }
     149                 :     113271 :   }
     150                 :    2938383 : }
     151                 :            : 
     152                 :    1234802 : ProofRewriteRule RewriteProofRule::getId() const { return d_id; }
     153                 :            : 
     154                 :          0 : const char* RewriteProofRule::getName() const { return toString(d_id); }
     155                 :            : 
     156                 :          2 : const std::vector<Node>& RewriteProofRule::getUserVarList() const
     157                 :            : {
     158                 :          2 :   return d_userFvs;
     159                 :            : }
     160                 :     293251 : const std::vector<Node>& RewriteProofRule::getVarList() const { return d_fvs; }
     161                 :            : 
     162                 :       9884 : std::vector<Node> RewriteProofRule::getExplicitTypeOfList() const
     163                 :            : {
     164                 :       9884 :   std::vector<Node> ret;
     165                 :       9884 :   Node conc = getConclusion(true);
     166                 :       9884 :   std::unordered_set<Node> ccts;
     167                 :       9884 :   expr::getKindSubterms(conc, Kind::TYPE_OF, true, ccts);
     168         [ +  + ]:      11803 :   for (const Node& c : d_cond)
     169                 :            :   {
     170                 :       1919 :     expr::getKindSubterms(c, Kind::TYPE_OF, true, ccts);
     171                 :            :   }
     172         [ +  + ]:      10040 :   for (const Node& t : ccts)
     173                 :            :   {
     174                 :        156 :     ret.emplace_back(t);
     175                 :            :   }
     176                 :      19768 :   return ret;
     177                 :       9884 : }
     178                 :            : 
     179                 :         12 : bool RewriteProofRule::isExplicitVar(Node v) const
     180                 :            : {
     181 [ -  + ][ -  + ]:         12 :   Assert(std::find(d_fvs.begin(), d_fvs.end(), v) != d_fvs.end());
                 [ -  - ]
     182                 :         12 :   return d_noOccVars.find(v) != d_noOccVars.end();
     183                 :            : }
     184                 :          0 : Kind RewriteProofRule::getListContext(Node v) const
     185                 :            : {
     186                 :          0 :   std::map<Node, Node>::const_iterator it = d_listVarCtx.find(v);
     187         [ -  - ]:          0 :   if (it != d_listVarCtx.end())
     188                 :            :   {
     189                 :          0 :     return it->second.getKind();
     190                 :            :   }
     191                 :          0 :   return Kind::UNDEFINED_KIND;
     192                 :            : }
     193                 :          0 : bool RewriteProofRule::hasConditions() const { return !d_cond.empty(); }
     194                 :            : 
     195                 :      91748 : const std::vector<Node>& RewriteProofRule::getConditions() const
     196                 :            : {
     197                 :      91748 :   return d_cond;
     198                 :            : }
     199                 :            : 
     200                 :    1418552 : bool RewriteProofRule::getObligations(const std::vector<Node>& vs,
     201                 :            :                                       const std::vector<Node>& ss,
     202                 :            :                                       std::vector<Node>& vcs) const
     203                 :            : {
     204                 :            :   // substitute into each condition
     205         [ +  + ]:    1842431 :   for (const Node& c : d_cond)
     206                 :            :   {
     207                 :     423879 :     Node sc = expr::narySubstitute(c, vs, ss);
     208                 :     423879 :     vcs.push_back(sc);
     209                 :     423879 :   }
     210                 :    1418552 :   return true;
     211                 :            : }
     212                 :            : 
     213                 :      70230 : void RewriteProofRule::getMatches(Node h, expr::NotifyMatch* ntm) const
     214                 :            : {
     215                 :      70230 :   d_mt.getMatches(h, ntm);
     216                 :      70230 : }
     217                 :            : 
     218                 :    3000892 : Node RewriteProofRule::getConclusion(bool includeContext) const
     219                 :            : {
     220                 :    3000892 :   Node conc = d_conc;
     221                 :            :   // if the rule has conclusion s, and term context (lambda x. t[x]), then the
     222                 :            :   // conclusion is t[s], which we compute in the block below.
     223 [ +  + ][ +  + ]:    3000892 :   if (includeContext && isFixedPoint())
                 [ +  + ]
     224                 :            :   {
     225                 :     146968 :     Node context = d_context;
     226                 :     293936 :     Node rhs = context[1].substitute(TNode(context[0][0]), TNode(conc[1]));
     227                 :     146968 :     conc = conc[0].eqNode(rhs);
     228                 :     146968 :   }
     229                 :    3000892 :   return conc;
     230                 :          0 : }
     231                 :            : 
     232                 :     292721 : Node RewriteProofRule::getConclusionFor(const std::vector<Node>& ss) const
     233                 :            : {
     234 [ -  + ][ -  + ]:     292721 :   Assert(d_fvs.size() == ss.size());
                 [ -  - ]
     235                 :     292721 :   Node conc = getConclusion(true);
     236                 :     585442 :   return expr::narySubstitute(conc, d_fvs, ss);
     237                 :     292721 : }
     238                 :            : 
     239                 :     207620 : Node RewriteProofRule::getConclusionFor(
     240                 :            :     const std::vector<Node>& ss,
     241                 :            :     std::vector<std::pair<Kind, std::vector<Node>>>& witnessTerms) const
     242                 :            : {
     243 [ -  + ][ -  + ]:     207620 :   Assert(d_fvs.size() == ss.size());
                 [ -  - ]
     244                 :     207620 :   Node conc = getConclusion(true);
     245                 :     207620 :   NodeManager* nm = conc.getNodeManager();
     246                 :     207620 :   std::unordered_map<TNode, Node> visited;
     247                 :     207620 :   Node ret = expr::narySubstitute(conc, d_fvs, ss, visited);
     248                 :            :   // also compute for the condition
     249         [ +  + ]:     216155 :   for (const Node& c : d_cond)
     250                 :            :   {
     251                 :       8535 :     expr::narySubstitute(c, d_fvs, ss, visited);
     252                 :            :   }
     253                 :     207620 :   std::map<Node, Node>::const_iterator itl;
     254         [ +  + ]:     600916 :   for (size_t i = 0, nfvs = ss.size(); i < nfvs; i++)
     255                 :            :   {
     256                 :     393296 :     TNode v = d_fvs[i];
     257                 :     393296 :     Kind wk = Kind::UNDEFINED_KIND;
     258                 :     393296 :     std::vector<Node> wargs;
     259         [ +  + ]:     393296 :     if (!expr::isListVar(v))
     260                 :            :     {
     261                 :            :       // if not a list variable, it is the given term
     262                 :     378086 :       wargs.push_back(ss[i]);
     263                 :            :     }
     264                 :            :     else
     265                 :            :     {
     266                 :      15210 :       itl = d_listVarCtx.find(v);
     267 [ -  + ][ -  + ]:      15210 :       Assert(itl != d_listVarCtx.end());
                 [ -  - ]
     268                 :      15210 :       Node ctx = itl->second;
     269         [ +  + ]:      15210 :       if (ss[i].getNumChildren() == 0)
     270                 :            :       {
     271                 :            :         // to determine the type, we get the type of the substitution of the
     272                 :            :         // list context of the variable.
     273                 :       7744 :         Node subsCtx = visited[ctx];
     274                 :       7744 :         Assert(!subsCtx.isNull()) << "Failed to get context for " << ctx << " in " << d_id;
     275                 :       7744 :         Node nt = expr::getNullTerminator(nm, ctx.getKind(), subsCtx.getType());
     276                 :       7744 :         wargs.push_back(nt);
     277                 :       7744 :       }
     278                 :            :       else
     279                 :            :       {
     280                 :       7466 :         wk = ctx.getKind();
     281                 :       7466 :         wargs.insert(wargs.end(), ss[i].begin(), ss[i].end());
     282                 :            :       }
     283                 :      15210 :     }
     284                 :     393296 :     witnessTerms.emplace_back(wk, wargs);
     285                 :     393296 :   }
     286                 :     415240 :   return ret;
     287                 :     207620 : }
     288                 :            : 
     289                 :    2947059 : bool RewriteProofRule::isFixedPoint() const
     290                 :            : {
     291                 :    2947059 :   return d_context != Node::null();
     292                 :            : }
     293                 :            : 
     294                 :      91854 : void RewriteProofRule::getConditionalDefinitions(const std::vector<Node>& vs,
     295                 :            :                                                  const std::vector<Node>& ss,
     296                 :            :                                                  std::vector<Node>& dvs,
     297                 :            :                                                  std::vector<Node>& dss) const
     298                 :            : {
     299         [ +  + ]:     141775 :   for (const std::pair<const Node, Node>& cv : d_condDefinedVars)
     300                 :            :   {
     301                 :      49921 :     dvs.push_back(cv.first);
     302                 :      49921 :     Node cvs = expr::narySubstitute(cv.second, vs, ss);
     303                 :      49921 :     dss.push_back(cvs);
     304                 :      49921 :   }
     305                 :      91854 : }
     306                 :            : 
     307                 :          0 : Level RewriteProofRule::getSignatureLevel() const { return d_level; }
     308                 :            : 
     309                 :            : }  // namespace rewriter
     310                 :            : }  // namespace cvc5::internal

Generated by: LCOV version 1.14