LCOV - code coverage report
Current view: top level - buildbot/coverage/build/src/rewriter - basic_rewrite_rcons.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 260 305 85.2 %
Date: 2024-10-14 11:38:00 Functions: 11 12 91.7 %
Branches: 152 306 49.7 %

           Branch data     Line data    Source code
       1                 :            : /******************************************************************************
       2                 :            :  * Top contributors (to current version):
       3                 :            :  *   Andrew Reynolds, Hans-Joerg Schurr, Aina Niemetz
       4                 :            :  *
       5                 :            :  * This file is part of the cvc5 project.
       6                 :            :  *
       7                 :            :  * Copyright (c) 2009-2024 by the authors listed in the file AUTHORS
       8                 :            :  * in the top-level source directory and their institutional affiliations.
       9                 :            :  * All rights reserved.  See the file COPYING in the top-level source
      10                 :            :  * directory for licensing information.
      11                 :            :  * ****************************************************************************
      12                 :            :  *
      13                 :            :  * The module for basic (non-DSL-dependent) automatic reconstructing proofs of
      14                 :            :  * THEORY_REWRITE steps.
      15                 :            :  */
      16                 :            : 
      17                 :            : #include "rewriter/basic_rewrite_rcons.h"
      18                 :            : 
      19                 :            : #include "expr/nary_term_util.h"
      20                 :            : #include "proof/conv_proof_generator.h"
      21                 :            : #include "proof/proof_checker.h"
      22                 :            : #include "proof/proof_node_algorithm.h"
      23                 :            : #include "rewriter/rewrite_db_term_process.h"
      24                 :            : #include "rewriter/rewrites.h"
      25                 :            : #include "smt/env.h"
      26                 :            : #include "theory/arith/arith_poly_norm.h"
      27                 :            : #include "theory/arith/arith_proof_utilities.h"
      28                 :            : #include "theory/booleans/theory_bool_rewriter.h"
      29                 :            : #include "theory/bv/theory_bv_rewrite_rules.h"
      30                 :            : #include "theory/rewriter.h"
      31                 :            : #include "theory/strings/arith_entail.h"
      32                 :            : #include "theory/strings/strings_entail.h"
      33                 :            : #include "theory/strings/theory_strings_utils.h"
      34                 :            : #include "util/rational.h"
      35                 :            : 
      36                 :            : using namespace cvc5::internal::kind;
      37                 :            : 
      38                 :            : namespace cvc5::internal {
      39                 :            : namespace rewriter {
      40                 :            : 
      41                 :          0 : std::ostream& operator<<(std::ostream& os, TheoryRewriteMode tm)
      42                 :            : {
      43 [ -  - ][ -  - ]:          0 :   switch (tm)
      44                 :            :   {
      45                 :          0 :     case TheoryRewriteMode::STANDARD: return os << "STANDARD";
      46                 :          0 :     case TheoryRewriteMode::RESORT: return os << "RESORT";
      47                 :          0 :     case TheoryRewriteMode::NEVER: return os << "NEVER";
      48                 :            :   }
      49                 :          0 :   Unreachable();
      50                 :            :   return os;
      51                 :            : }
      52                 :            : 
      53                 :       3187 : BasicRewriteRCons::BasicRewriteRCons(Env& env) : EnvObj(env)
      54                 :            : {
      55                 :            : 
      56                 :       3187 : }
      57                 :            : 
      58                 :     320369 : bool BasicRewriteRCons::prove(CDProof* cdp,
      59                 :            :                               Node a,
      60                 :            :                               Node b,
      61                 :            :                               std::vector<std::shared_ptr<ProofNode>>& subgoals,
      62                 :            :                               TheoryRewriteMode tmode)
      63                 :            : {
      64                 :     640738 :   Node eq = a.eqNode(b);
      65         [ +  - ]:     320369 :   Trace("trewrite-rcons") << "Reconstruct " << eq << std::endl;
      66                 :     640738 :   Node lhs = eq[0];
      67                 :     640738 :   Node rhs = eq[1];
      68                 :            :   // this probably should never happen
      69         [ -  + ]:     320369 :   if (eq[0] == eq[1])
      70                 :            :   {
      71         [ -  - ]:          0 :     Trace("trewrite-rcons") << "...REFL" << std::endl;
      72                 :          0 :     cdp->addStep(eq, ProofRule::REFL, {}, {eq[0]});
      73                 :          0 :     return true;
      74                 :            :   }
      75                 :            :   // first, check that maybe its just an evaluation step
      76 [ +  + ][ +  + ]:     640738 :   if (tryRule(cdp, eq, ProofRule::EVALUATE, {eq[0]}))
                 [ -  - ]
      77                 :            :   {
      78         [ +  - ]:      27751 :     Trace("trewrite-rcons") << "...EVALUATE" << std::endl;
      79                 :      27751 :     return true;
      80                 :            :   }
      81                 :            : 
      82                 :            :   // try theory rewrite (pre-rare)
      83         [ +  + ]:     292618 :   if (tmode == TheoryRewriteMode::STANDARD)
      84                 :            :   {
      85         [ +  + ]:     289926 :     if (tryTheoryRewrite(cdp, eq, theory::TheoryRewriteCtx::PRE_DSL, subgoals))
      86                 :            :     {
      87         [ +  - ]:       9218 :       Trace("trewrite-rcons")
      88                 :       4609 :           << "Reconstruct (pre) " << eq << " via theory rewrite" << std::endl;
      89                 :       4609 :       return true;
      90                 :            :     }
      91                 :            :   }
      92         [ +  - ]:     288009 :   Trace("trewrite-rcons") << "...(fail)" << std::endl;
      93                 :     288009 :   return false;
      94                 :            : }
      95                 :            : 
      96                 :       7021 : bool BasicRewriteRCons::postProve(
      97                 :            :     CDProof* cdp,
      98                 :            :     Node a,
      99                 :            :     Node b,
     100                 :            :     std::vector<std::shared_ptr<ProofNode>>& subgoals,
     101                 :            :     TheoryRewriteMode tmode)
     102                 :            : {
     103                 :       7021 :   Node eq = a.eqNode(b);
     104                 :            :   // try theory rewrite (post-rare), which may try both pre and post if
     105                 :            :   // the proof-granularity mode is dsl-rewrite-strict.
     106                 :       7021 :   bool success = false;
     107         [ -  + ]:       7021 :   if (tmode == TheoryRewriteMode::RESORT)
     108                 :            :   {
     109         [ -  - ]:          0 :     if (tryTheoryRewrite(cdp, eq, theory::TheoryRewriteCtx::PRE_DSL, subgoals))
     110                 :            :     {
     111                 :          0 :       success = true;
     112                 :            :     }
     113                 :            :   }
     114         [ +  - ]:       7021 :   if (!success && tmode != TheoryRewriteMode::NEVER
     115 [ +  - ][ +  + ]:      14042 :       && tryTheoryRewrite(
                 [ +  + ]
     116                 :            :           cdp, eq, theory::TheoryRewriteCtx::POST_DSL, subgoals))
     117                 :            :   {
     118                 :        683 :     success = true;
     119                 :            :   }
     120         [ +  + ]:       7021 :   if (success)
     121                 :            :   {
     122         [ +  - ]:       1366 :     Trace("trewrite-rcons")
     123                 :        683 :         << "Reconstruct (post) " << eq << " via theory rewrite" << std::endl;
     124                 :            :   }
     125                 :            :   else
     126                 :            :   {
     127         [ +  - ]:       6338 :     Trace("trewrite-rcons") << "...(fail)" << std::endl;
     128                 :            :   }
     129                 :      14042 :   return success;
     130                 :            : }
     131                 :            : 
     132                 :     325661 : bool BasicRewriteRCons::tryRule(CDProof* cdp,
     133                 :            :                                 Node eq,
     134                 :            :                                 ProofRule r,
     135                 :            :                                 const std::vector<Node>& args,
     136                 :            :                                 bool addStep)
     137                 :            : {
     138         [ +  - ]:     325661 :   Trace("trewrite-rcons-debug") << "Try " << r << std::endl;
     139                 :     325661 :   ProofChecker* pc = d_env.getProofNodeManager()->getChecker();
     140                 :            :   // do not provide expected, as this will always succeed if proof checking
     141                 :            :   // is disabled
     142                 :     976983 :   Node res = pc->checkDebug(r, {}, args, Node::null(), "trewrite-rcons");
     143 [ +  + ][ +  + ]:     325661 :   if (!res.isNull() && res == eq)
                 [ +  + ]
     144                 :            :   {
     145         [ +  + ]:      33043 :     if (addStep)
     146                 :            :     {
     147                 :      27751 :       cdp->addStep(eq, r, {}, args);
     148                 :            :     }
     149                 :      33043 :     return true;
     150                 :            :   }
     151                 :     292618 :   return false;
     152                 :            : }
     153                 :            : 
     154                 :       2654 : void BasicRewriteRCons::ensureProofForEncodeTransform(CDProof* cdp,
     155                 :            :                                                       const Node& eq,
     156                 :            :                                                       const Node& eqi)
     157                 :            : {
     158                 :       5308 :   ProofRewriteDbNodeConverter rdnc(d_env);
     159                 :       5308 :   std::shared_ptr<ProofNode> pfn = rdnc.convert(eq);
     160                 :       5308 :   Node equiv = eq.eqNode(eqi);
     161 [ -  + ][ -  + ]:       2654 :   Assert(pfn->getResult() == equiv);
                 [ -  - ]
     162                 :       2654 :   cdp->addProof(pfn);
     163                 :       2654 :   Node equivs = eqi.eqNode(eq);
     164                 :       5308 :   cdp->addStep(equivs, ProofRule::SYMM, {equiv}, {});
     165 [ +  + ][ -  - ]:       7962 :   cdp->addStep(eq, ProofRule::EQ_RESOLVE, {eqi, equivs}, {});
     166                 :       2654 : }
     167                 :            : 
     168                 :       6062 : void BasicRewriteRCons::ensureProofForTheoryRewrite(
     169                 :            :     CDProof* cdp,
     170                 :            :     ProofRewriteRule id,
     171                 :            :     const Node& eq,
     172                 :            :     std::vector<std::shared_ptr<ProofNode>>& subgoals)
     173                 :            : {
     174                 :       6062 :   bool handledMacro = false;
     175 [ +  + ][ +  + ]:       6062 :   switch (id)
     176                 :            :   {
     177                 :        573 :     case ProofRewriteRule::MACRO_BOOL_NNF_NORM:
     178         [ +  - ]:        573 :       if (ensureProofMacroBoolNnfNorm(cdp, eq))
     179                 :            :       {
     180                 :        573 :         handledMacro = true;
     181                 :            :       }
     182                 :        573 :       break;
     183                 :       1337 :     case ProofRewriteRule::MACRO_ARITH_STRING_PRED_ENTAIL:
     184         [ +  - ]:       1337 :       if (ensureProofMacroArithStringPredEntail(cdp, eq))
     185                 :            :       {
     186                 :       1337 :         handledMacro = true;
     187                 :            :       }
     188                 :       1337 :       break;
     189                 :         10 :     case ProofRewriteRule::MACRO_SUBSTR_STRIP_SYM_LENGTH:
     190         [ +  - ]:         10 :       if (ensureProofMacroSubstrStripSymLength(cdp, eq))
     191                 :            :       {
     192                 :         10 :         handledMacro = true;
     193                 :            :       }
     194                 :         10 :       break;
     195                 :       4142 :     default: break;
     196                 :            :   }
     197         [ +  + ]:       6062 :   if (handledMacro)
     198                 :            :   {
     199                 :       1920 :     std::shared_ptr<ProofNode> pfn = cdp->getProofFor(eq);
     200         [ +  - ]:       1920 :     Trace("brc-macro") << "...proof is " << *pfn.get() << std::endl;
     201                 :       1920 :     expr::getSubproofRule(pfn, ProofRule::TRUST, subgoals);
     202                 :       1920 :     return;
     203                 :            :   }
     204                 :            :   // default, just add the rewrite
     205                 :       4142 :   std::vector<Node> args;
     206                 :       4142 :   args.push_back(
     207                 :       8284 :       nodeManager()->mkConstInt(Rational(static_cast<uint32_t>(id))));
     208                 :       4142 :   args.push_back(eq);
     209                 :       4142 :   cdp->addStep(eq, ProofRule::THEORY_REWRITE, {}, args);
     210                 :            : }
     211                 :            : 
     212                 :        573 : bool BasicRewriteRCons::ensureProofMacroBoolNnfNorm(CDProof* cdp,
     213                 :            :                                                     const Node& eq)
     214                 :            : {
     215                 :       1146 :   Trace("brc-macro") << "Expand Bool NNF norm " << eq[0] << " == " << eq[1]
     216                 :        573 :                      << std::endl;
     217                 :            :   // Call the utility again with proof tracking and construct the term
     218                 :            :   // conversion proof. This proof itself may have trust steps in it.
     219                 :       1719 :   TConvProofGenerator tcpg(d_env, nullptr);
     220                 :            :   Node nr = theory::booleans::TheoryBoolRewriter::computeNnfNorm(
     221                 :       1146 :       nodeManager(), eq[0], &tcpg);
     222                 :        573 :   std::shared_ptr<ProofNode> pfn = tcpg.getProofFor(eq);
     223         [ +  - ]:        573 :   Trace("brc-macro") << "...proof is " << *pfn.get() << std::endl;
     224                 :        573 :   cdp->addProof(pfn);
     225                 :       1146 :   return true;
     226                 :            : }
     227                 :            : 
     228                 :       1337 : bool BasicRewriteRCons::ensureProofMacroArithStringPredEntail(CDProof* cdp,
     229                 :            :                                                               const Node& eq)
     230                 :            : {
     231 [ -  + ][ -  + ]:       1337 :   Assert(eq.getKind() == Kind::EQUAL);
                 [ -  - ]
     232         [ +  - ]:       1337 :   Trace("brc-macro") << "Expand entailment for " << eq << std::endl;
     233                 :       2674 :   theory::strings::ArithEntail ae(nullptr);
     234                 :       2674 :   Node lhs = eq[0];
     235                 :       2674 :   Node eqi = eq;
     236                 :            :   // First normalize LT/GT/LEQ to GEQ.
     237 [ +  + ][ +  + ]:       1337 :   if (lhs.getKind() != Kind::EQUAL && lhs.getKind() != Kind::GEQ)
                 [ +  + ]
     238                 :            :   {
     239                 :        122 :     Node lhsn = ae.normalizeGeq(lhs);
     240                 :         61 :     Node eqLhs = lhs.eqNode(lhsn);
     241                 :         61 :     cdp->addTrustedStep(
     242                 :            :         eqLhs, TrustId::MACRO_THEORY_REWRITE_RCONS_SIMPLE, {}, {});
     243                 :         61 :     eqi = lhsn.eqNode(eq[1]);
     244 [ +  + ][ -  - ]:        183 :     cdp->addStep(eq, ProofRule::TRANS, {eqLhs, eqi}, {});
     245         [ +  - ]:         61 :     Trace("brc-macro") << "- GEQ normalize is " << eqi << std::endl;
     246                 :            :   }
     247                 :            :   // Then do basic length intro, which rewrites (str.len (str.++ x y))
     248                 :            :   // to (+ (str.len x) (str.len y)).
     249                 :       4011 :   TConvProofGenerator tcpg(d_env, nullptr);
     250                 :       2674 :   Node eqii = ae.rewriteLengthIntro(eqi, &tcpg);
     251         [ +  + ]:       1337 :   if (eqii != eqi)
     252                 :            :   {
     253                 :       1048 :     Node equiv = eqi.eqNode(eqii);
     254                 :       1048 :     std::shared_ptr<ProofNode> pfn = tcpg.getProofFor(equiv);
     255                 :        524 :     cdp->addProof(pfn);
     256                 :        524 :     Node equivs = eqii.eqNode(eqi);
     257                 :       1048 :     cdp->addStep(equivs, ProofRule::SYMM, {equiv}, {});
     258 [ +  + ][ -  - ]:       1572 :     cdp->addStep(eqi, ProofRule::EQ_RESOLVE, {eqii, equivs}, {});
     259         [ +  - ]:        524 :     Trace("brc-macro") << "- length intro is " << eqii << std::endl;
     260                 :            :     // now, must prove eqii
     261                 :            :   }
     262                 :       1337 :   lhs = eqii[0];
     263                 :       2674 :   Node exp;
     264                 :       2674 :   Node ret = ae.rewritePredViaEntailment(lhs, exp, true);
     265 [ -  + ][ -  + ]:       1337 :   Assert(ret == eqii[1]);
                 [ -  - ]
     266         [ +  - ]:       1337 :   Trace("brc-macro") << "- explanation is " << exp << std::endl;
     267                 :            :   // if trivially true equality
     268         [ +  + ]:       1337 :   if (exp.isNull())
     269                 :            :   {
     270                 :            :     // explanation true if we are an equality that is trivially true
     271 [ -  + ][ -  + ]:       1022 :     Assert(eqii[0].getKind() == Kind::EQUAL);
                 [ -  - ]
     272         [ +  + ]:       1022 :     if (eqii[0][0] == eqii[0][1])
     273                 :            :     {
     274                 :       2040 :       cdp->addStep(eqii[0], ProofRule::REFL, {}, {eqii[0][0]});
     275                 :            :     }
     276                 :            :     else
     277                 :            :     {
     278 [ -  + ][ -  + ]:          2 :       Assert(theory::arith::PolyNorm::isArithPolyNorm(eqii[0][0], eqii[0][1]));
                 [ -  - ]
     279                 :            :       // prove via ARITH_POLY_NORM.
     280                 :          4 :       cdp->addStep(eqii[0], ProofRule::ARITH_POLY_NORM, {}, {eqii[0]});
     281                 :            :     }
     282                 :       2044 :     cdp->addStep(eqii, ProofRule::TRUE_INTRO, {eqii[0]}, {});
     283                 :       1022 :     return true;
     284                 :            :   }
     285                 :        630 :   Node expRew = ae.rewriteArith(exp);
     286                 :        630 :   Node zero = nodeManager()->mkConstInt(Rational(0));
     287                 :        945 :   Node geq = nodeManager()->mkNode(Kind::GEQ, expRew, zero);
     288         [ +  - ]:        315 :   Trace("brc-macro") << "- rewritten predicate is " << geq << std::endl;
     289                 :        630 :   Node approx = ae.findApprox(expRew, true);
     290         [ -  + ]:        315 :   if (approx.isNull())
     291                 :            :   {
     292         [ -  - ]:          0 :     Trace("brc-macro") << "...failed to find approximation" << std::endl;
     293                 :          0 :     Assert(false);
     294                 :            :     return false;
     295                 :            :   }
     296                 :        630 :   Node truen = nodeManager()->mkConst(true);
     297                 :        630 :   Node approxRew = ae.rewriteArith(approx);
     298                 :        945 :   Node approxGeq = nodeManager()->mkNode(Kind::GEQ, approx, zero);
     299                 :        945 :   Node approxRewGeq = nodeManager()->mkNode(Kind::GEQ, approxRew, zero);
     300         [ +  - ]:        630 :   Trace("brc-macro") << "- approximation predicate is " << approxGeq
     301                 :        315 :                      << std::endl;
     302                 :        630 :   std::vector<Node> transEq;
     303         [ +  + ]:        315 :   if (expRew != approx)
     304                 :            :   {
     305                 :        208 :     Node aeq = geq.eqNode(approxGeq);
     306                 :            :     // (>= expRew 0) = (>= approx 0)
     307         [ +  - ]:        208 :     Trace("brc-macro") << "- prove " << aeq << " via pred-safe-approx"
     308                 :        104 :                        << std::endl;
     309                 :        104 :     cdp->addTheoryRewriteStep(aeq,
     310                 :            :                               ProofRewriteRule::ARITH_STRING_PRED_SAFE_APPROX);
     311                 :        104 :     transEq.push_back(aeq);
     312                 :            :   }
     313         [ +  + ]:        315 :   if (approx != approxRew)
     314                 :            :   {
     315                 :        104 :     Node areq = approxGeq.eqNode(approxRewGeq);
     316         [ +  - ]:        208 :     Trace("brc-macro") << "- prove " << areq << " via arith-poly-norm"
     317                 :        104 :                        << std::endl;
     318         [ -  + ]:        104 :     if (!ensureProofArithPolyNormRel(cdp, areq))
     319                 :            :     {
     320         [ -  - ]:          0 :       Trace("brc-macro") << "...failed to show normalization" << std::endl;
     321                 :          0 :       Assert(false);
     322                 :            :       return false;
     323                 :            :     }
     324                 :        104 :     transEq.push_back(areq);
     325                 :            :   }
     326                 :            :   // (>= approx 0) = true
     327                 :        630 :   Node teq = approxRewGeq.eqNode(truen);
     328                 :        945 :   Node ev = evaluate(approxRewGeq, {}, {});
     329         [ +  + ]:        315 :   if (ev == truen)
     330                 :            :   {
     331         [ +  - ]:        171 :     Trace("brc-macro") << "- prove " << teq << " via evaluate" << std::endl;
     332                 :        342 :     cdp->addStep(teq, ProofRule::EVALUATE, {}, {approxRewGeq});
     333                 :            :   }
     334                 :            :   else
     335                 :            :   {
     336         [ +  - ]:        144 :     Trace("brc-macro") << "- prove " << teq << " via pred-entail" << std::endl;
     337                 :        144 :     cdp->addTheoryRewriteStep(teq, ProofRewriteRule::ARITH_STRING_PRED_ENTAIL);
     338                 :            :   }
     339                 :        315 :   transEq.push_back(teq);
     340                 :            :   // put the above three steps together with TRANS
     341         [ +  + ]:        315 :   if (transEq.size() > 1)
     342                 :            :   {
     343                 :        104 :     teq = geq.eqNode(truen);
     344                 :        104 :     cdp->addStep(teq, ProofRule::TRANS, transEq, {});
     345                 :            :   }
     346                 :            : 
     347                 :            :   // now have (>= expRew 0) = true, stored in teq
     348                 :            : 
     349         [ -  + ]:        315 :   if (lhs == expRew)
     350                 :            :   {
     351         [ -  - ]:          0 :     Trace("brc-macro") << "...success (no normalization)" << std::endl;
     352                 :          0 :     return true;
     353                 :            :   }
     354         [ +  + ]:        315 :   if (!ret.getConst<bool>())
     355                 :            :   {
     356         [ +  - ]:         61 :     Trace("brc-macro") << "- false case, setting up conflict" << std::endl;
     357                 :        122 :     cdp->addStep(geq, ProofRule::TRUE_ELIM, {teq}, {});
     358 [ -  + ][ -  + ]:         61 :     Assert(exp.getKind() == Kind::SUB);
                 [ -  - ]
     359 [ +  - ][ +  - ]:        122 :     Node posTerm = exp[0].getKind() == Kind::SUB ? exp[0][0] : exp[0];
                 [ -  - ]
     360                 :         61 :     Assert(posTerm == lhs[0] || posTerm == lhs[1]);
     361                 :         61 :     bool isLhs = posTerm == lhs[0];
     362         [ +  - ]:         61 :     Trace("brc-macro") << "- isLhs is " << isLhs << std::endl;
     363                 :         61 :     std::vector<Node> children;
     364                 :         61 :     children.push_back(geq);
     365                 :         61 :     children.push_back(lhs);
     366                 :         61 :     std::vector<Node> args;
     367                 :            :     // Must flip signs to ensure it is <=, as required by
     368                 :            :     // MACRO_ARITH_SCALE_SUM_UB. This rule sums inequalities based on the
     369                 :            :     // coefficients in args.
     370                 :         61 :     args.push_back(nodeManager()->mkConstInt(Rational(-1)));
     371         [ +  + ]:         61 :     args.push_back(nodeManager()->mkConstInt(Rational(isLhs ? 1 : -1)));
     372         [ +  - ]:        122 :     Trace("brc-macro") << "- compute sum bound for " << children << " " << args
     373                 :         61 :                        << std::endl;
     374                 :         61 :     Node sumBound = theory::arith::expandMacroSumUb(children, args, cdp);
     375         [ +  - ]:         61 :     Trace("brc-macro") << "- sum bound is " << sumBound << std::endl;
     376         [ -  + ]:         61 :     if (sumBound.isNull())
     377                 :            :     {
     378         [ -  - ]:          0 :       Trace("brc-macro") << "...failed to show normalization" << std::endl;
     379                 :          0 :       Assert(false);
     380                 :            :       return false;
     381                 :            :     }
     382 [ -  + ][ -  + ]:         61 :     Assert(sumBound.getNumChildren() == 2);
                 [ -  - ]
     383                 :        122 :     Node py = nodeManager()->mkNode(Kind::SUB, sumBound[0], sumBound[1]);
     384                 :         61 :     theory::arith::PolyNorm pn = theory::arith::PolyNorm::mkPolyNorm(py);
     385                 :         61 :     Rational pyr;
     386         [ -  + ]:         61 :     if (!pn.isConstant(pyr))
     387                 :            :     {
     388         [ -  - ]:          0 :       Trace("brc-macro") << "...failed to prove constant after normalization"
     389                 :          0 :                          << std::endl;
     390                 :          0 :       Assert(false);
     391                 :            :       return false;
     392                 :            :     }
     393                 :            :     Node cpred = nodeManager()->mkNode(
     394                 :        122 :         sumBound.getKind(), nodeManager()->mkConstInt(pyr), zero);
     395                 :         61 :     Node peq = sumBound.eqNode(cpred);
     396         [ -  + ]:         61 :     if (!ensureProofArithPolyNormRel(cdp, peq))
     397                 :            :     {
     398         [ -  - ]:          0 :       Trace("brc-macro") << "...failed to show normalization" << std::endl;
     399                 :          0 :       Assert(false);
     400                 :            :       return false;
     401                 :            :     }
     402                 :        122 :     Node cceq = cpred.eqNode(ret);
     403                 :        122 :     cdp->addStep(cceq, ProofRule::EVALUATE, {}, {cpred});
     404                 :        122 :     Node sumEqFalse = sumBound.eqNode(ret);
     405 [ +  + ][ -  - ]:        183 :     cdp->addStep(sumEqFalse, ProofRule::TRANS, {peq, cceq}, {});
     406                 :        122 :     Node notSum = sumBound.notNode();
     407                 :        122 :     cdp->addStep(notSum, ProofRule::FALSE_ELIM, {sumEqFalse}, {});
     408 [ +  + ][ -  - ]:        183 :     cdp->addStep(ret, ProofRule::CONTRA, {sumBound, notSum}, {});
     409                 :         61 :     Node notLhs = lhs.notNode();
     410                 :        183 :     cdp->addStep(notLhs, ProofRule::SCOPE, {ret}, {lhs});
     411                 :        122 :     cdp->addStep(eqii, ProofRule::FALSE_INTRO, {notLhs}, {});
     412                 :            :   }
     413                 :            :   else
     414                 :            :   {
     415         [ +  - ]:        254 :     Trace("brc-macro") << "- true case, prove equal" << std::endl;
     416 [ -  + ][ -  + ]:        254 :     Assert(lhs.getKind() == Kind::GEQ);
                 [ -  - ]
     417                 :            :     // should be able to show equivalence by polynomial normalization
     418                 :        254 :     Node peq = lhs.eqNode(geq);
     419         [ -  + ]:        254 :     if (!ensureProofArithPolyNormRel(cdp, peq))
     420                 :            :     {
     421         [ -  - ]:          0 :       Trace("brc-macro") << "...failed to show normalization (true case) "
     422                 :          0 :                          << lhs << " and " << geq << std::endl;
     423                 :          0 :       Assert(false);
     424                 :            :       return false;
     425                 :            :     }
     426 [ +  + ][ -  - ]:        762 :     cdp->addStep(eqii, ProofRule::TRANS, {peq, teq}, {});
     427                 :            :   }
     428         [ +  - ]:        315 :   Trace("brc-macro") << "...success" << std::endl;
     429                 :        315 :   return true;
     430                 :            : }
     431                 :            : 
     432                 :         10 : bool BasicRewriteRCons::ensureProofMacroSubstrStripSymLength(CDProof* cdp,
     433                 :            :                                                              const Node& eq)
     434                 :            : {
     435                 :         10 :   NodeManager* nm = NodeManager::currentNM();
     436         [ +  - ]:         10 :   Trace("brc-macro") << "Expand substring strip for " << eq << std::endl;
     437 [ -  + ][ -  + ]:         10 :   Assert(eq.getKind() == Kind::EQUAL);
                 [ -  - ]
     438                 :         20 :   Node lhs = eq[0];
     439 [ -  + ][ -  + ]:         10 :   Assert(lhs.getKind() == Kind::STRING_SUBSTR);
                 [ -  - ]
     440                 :            :   theory::strings::Rewrite rule;
     441                 :            :   // call the same utility that proved it
     442                 :         20 :   theory::strings::ArithEntail ae(nullptr);
     443                 :         10 :   theory::strings::StringsEntail sent(nullptr, ae, nullptr);
     444                 :         20 :   std::vector<Node> ch1;
     445                 :         20 :   std::vector<Node> ch2;
     446                 :         20 :   Node rhs = sent.rewriteViaMacroSubstrStripSymLength(lhs, rule, ch1, ch2);
     447         [ +  - ]:         10 :   Trace("brc-macro") << "...was via string rewrite rule " << rule << std::endl;
     448 [ -  + ][ -  + ]:         10 :   Assert(rhs == eq[1]);
                 [ -  - ]
     449                 :         20 :   TypeNode stype = lhs.getType();
     450                 :         20 :   Node cm1 = theory::strings::utils::mkConcat(ch1, stype);
     451                 :         20 :   Node cm2 = theory::strings::utils::mkConcat(ch2, stype);
     452                 :         20 :   Node cm;
     453                 :            :   // depending on the rule, are either stripping from front or back
     454         [ +  + ]:         10 :   if (rule == theory::strings::Rewrite::SS_STRIP_END_PT)
     455                 :            :   {
     456                 :          8 :     cm = nm->mkNode(Kind::STRING_CONCAT, cm1, cm2);
     457                 :            :   }
     458                 :            :   else
     459                 :            :   {
     460                 :          2 :     cm = nm->mkNode(Kind::STRING_CONCAT, cm2, cm1);
     461                 :            :   }
     462         [ -  + ]:         10 :   if (cm == lhs[0])
     463                 :            :   {
     464                 :          0 :     return false;
     465                 :            :   }
     466                 :         30 :   Node eq1 = nm->mkNode(Kind::EQUAL, lhs[0], cm);
     467                 :            :   // It is likely provable by ACI_NORM. However, if it involves splitting
     468                 :            :   // word constants, we require going through the rewrite term converter.
     469         [ +  - ]:         10 :   if (expr::isACINorm(lhs[0], cm))
     470                 :            :   {
     471                 :         20 :     cdp->addStep(eq1, ProofRule::ACI_NORM, {}, {eq1});
     472         [ +  - ]:         10 :     Trace("brc-macro") << "- via ACI_NORM " << eq1 << std::endl;
     473                 :            :   }
     474                 :            :   else
     475                 :            :   {
     476                 :            :     //             ----------------- via encode transform
     477                 :            :     //             (t = s) = (r = r)
     478                 :            :     // ----- REFL  ------------------ SYMM
     479                 :            :     // r = r       (r = r) = (t = s)
     480                 :            :     // ---------------------------------- EQ_RESOLVE
     481                 :            :     // t = s
     482                 :          0 :     RewriteDbNodeConverter rdnc(nodeManager());
     483                 :          0 :     Node eq1t = rdnc.convert(eq1);
     484                 :          0 :     Assert(eq1t.getKind() == Kind::EQUAL);
     485         [ -  - ]:          0 :     if (eq1t[0] != eq1t[1])
     486                 :            :     {
     487                 :          0 :       return false;
     488                 :            :     }
     489                 :          0 :     Node equiv = eq1.eqNode(eq1t);
     490                 :          0 :     ensureProofForEncodeTransform(cdp, eq1, eq1t);
     491                 :          0 :     Node equivs = eq1t.eqNode(eq1);
     492                 :          0 :     cdp->addStep(equivs, ProofRule::SYMM, {equiv}, {});
     493                 :          0 :     cdp->addStep(eq1t, ProofRule::REFL, {}, {eq1t[0]});
     494                 :          0 :     cdp->addStep(eq1, ProofRule::EQ_RESOLVE, {eq1t, equivs}, {});
     495                 :            :   }
     496                 :         20 :   std::vector<Node> cargs;
     497                 :         10 :   ProofRule cr = expr::getCongRule(lhs, cargs);
     498                 :         30 :   Node eq2 = lhs[1].eqNode(lhs[1]);
     499                 :         30 :   Node eq3 = lhs[2].eqNode(lhs[2]);
     500                 :         20 :   cdp->addStep(eq2, ProofRule::REFL, {}, {lhs[1]});
     501                 :         20 :   cdp->addStep(eq3, ProofRule::REFL, {}, {lhs[2]});
     502                 :         30 :   Node lhsm = nm->mkNode(Kind::STRING_SUBSTR, cm, lhs[1], lhs[2]);
     503                 :         20 :   Node eqLhs = lhs.eqNode(lhsm);
     504 [ +  + ][ -  - ]:         40 :   cdp->addStep(eqLhs, cr, {eq1, eq2, eq3}, cargs);
     505                 :         10 :   Node eqm = lhsm.eqNode(rhs);
     506                 :            :   // Note that this is not marked simple, since it may require length
     507                 :            :   // entailment to prove.
     508                 :            :   // Note that there are three cases of string rewrites handled by this macro,
     509                 :            :   // where we expect this trusted step to be filled by one of 3 RARE rewrites,
     510                 :            :   // namely:
     511                 :            :   // str-substr-len-include, str-substr-len-include-pre, str-substr-len-skip.
     512                 :         10 :   cdp->addTrustedStep(eqm, TrustId::MACRO_THEORY_REWRITE_RCONS, {}, {});
     513         [ +  - ]:         10 :   Trace("brc-macro") << "- rely on rewrite " << eqm << std::endl;
     514 [ +  + ][ -  - ]:         30 :   cdp->addStep(eq, ProofRule::TRANS, {eqLhs, eqm}, {});
     515                 :         10 :   return true;
     516                 :            : }
     517                 :            : 
     518                 :        419 : bool BasicRewriteRCons::ensureProofArithPolyNormRel(CDProof* cdp,
     519                 :            :                                                     const Node& eq)
     520                 :            : {
     521         [ +  - ]:        419 :   Trace("brc-macro") << "Ensure arith poly norm rel: " << eq << std::endl;
     522                 :        838 :   Rational rx, ry;
     523         [ -  + ]:        419 :   if (!theory::arith::PolyNorm::isArithPolyNormRel(eq[0], eq[1], rx, ry))
     524                 :            :   {
     525         [ -  - ]:          0 :     Trace("brc-macro") << "...fail rule" << std::endl;
     526                 :          0 :     return false;
     527                 :            :   }
     528                 :            :   Node premise =
     529                 :       1257 :       theory::arith::PolyNorm::getArithPolyNormRelPremise(eq[0], eq[1], rx, ry);
     530         [ +  - ]:        838 :   Trace("brc-macro") << "Show " << premise << " by arith poly norm"
     531                 :        419 :                      << std::endl;
     532 [ +  + ][ -  + ]:        838 :   if (!cdp->addStep(premise, ProofRule::ARITH_POLY_NORM, {}, {premise}))
                 [ -  - ]
     533                 :            :   {
     534         [ -  - ]:          0 :     Trace("brc-macro") << "...fail premise" << std::endl;
     535                 :          0 :     return false;
     536                 :            :   }
     537                 :        838 :   Node kn = ProofRuleChecker::mkKindNode(eq[0].getKind());
     538                 :       1257 :   if (!cdp->addStep(eq, ProofRule::ARITH_POLY_NORM_REL, {premise}, {kn}))
     539                 :            :   {
     540         [ -  - ]:          0 :     Trace("brc-macro") << "...fail application" << std::endl;
     541                 :          0 :     return false;
     542                 :            :   }
     543                 :        419 :   return true;
     544                 :            : }
     545                 :            : 
     546                 :     296947 : bool BasicRewriteRCons::tryTheoryRewrite(
     547                 :            :     CDProof* cdp,
     548                 :            :     const Node& eq,
     549                 :            :     theory::TheoryRewriteCtx ctx,
     550                 :            :     std::vector<std::shared_ptr<ProofNode>>& subgoals)
     551                 :            : {
     552 [ -  + ][ -  + ]:     296947 :   Assert(eq.getKind() == Kind::EQUAL);
                 [ -  - ]
     553                 :     296947 :   ProofRewriteRule prid = d_env.getRewriter()->findRule(eq[0], eq[1], ctx);
     554         [ +  + ]:     296947 :   if (prid != ProofRewriteRule::NONE)
     555                 :            :   {
     556                 :            :     // Do not add the step in the call to tryStep, instead we add it via
     557                 :            :     // ensureProofForTheoryRewrite.
     558 [ +  + ][ +  - ]:      15876 :     if (tryRule(cdp,
                 [ -  - ]
     559                 :            :                 eq,
     560                 :            :                 ProofRule::THEORY_REWRITE,
     561                 :            :                 {mkRewriteRuleNode(prid), eq},
     562                 :      10584 :                 false))
     563                 :            :     {
     564                 :            :       // Theory rewrites may require macro expansion
     565                 :       5292 :       ensureProofForTheoryRewrite(cdp, prid, eq, subgoals);
     566                 :       5292 :       return true;
     567                 :            :     }
     568                 :            :   }
     569                 :     291655 :   return false;
     570                 :            : }
     571                 :            : 
     572                 :            : }  // namespace rewriter
     573                 :            : }  // namespace cvc5::internal

Generated by: LCOV version 1.14