LCOV - code coverage report
Current view: top level - buildbot/coverage/build/src/theory/arith - proof_checker.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 180 238 75.6 %
Date: 2026-02-09 12:26:33 Functions: 3 3 100.0 %
Branches: 132 271 48.7 %

           Branch data     Line data    Source code
       1                 :            : /******************************************************************************
       2                 :            :  * Top contributors (to current version):
       3                 :            :  *   Alex Ozdemir, Andrew Reynolds, Gereon Kremer
       4                 :            :  *
       5                 :            :  * This file is part of the cvc5 project.
       6                 :            :  *
       7                 :            :  * Copyright (c) 2009-2025 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                 :            :  * Implementation of arithmetic proof checker.
      14                 :            :  */
      15                 :            : 
      16                 :            : #include "theory/arith/proof_checker.h"
      17                 :            : 
      18                 :            : #include <iostream>
      19                 :            : #include <set>
      20                 :            : 
      21                 :            : #include "expr/skolem_manager.h"
      22                 :            : #include "theory/arith/arith_poly_norm.h"
      23                 :            : #include "theory/arith/arith_utilities.h"
      24                 :            : #include "theory/arith/linear/constraint.h"
      25                 :            : #include "theory/arith/operator_elim.h"
      26                 :            : 
      27                 :            : using namespace cvc5::internal::kind;
      28                 :            : 
      29                 :            : namespace cvc5::internal {
      30                 :            : namespace theory {
      31                 :            : namespace arith {
      32                 :            : 
      33                 :      50340 : ArithProofRuleChecker::ArithProofRuleChecker(NodeManager* nm)
      34                 :            :     : ProofRuleChecker(nm),
      35                 :            :       d_extChecker(nm),
      36                 :            :       d_trChecker(nm)
      37                 :            : #ifdef CVC5_POLY_IMP
      38                 :            :       ,
      39                 :      50340 :       d_covChecker(nm)
      40                 :            : #endif
      41                 :            : {
      42                 :      50340 : }
      43                 :            : 
      44                 :      18858 : void ArithProofRuleChecker::registerTo(ProofChecker* pc)
      45                 :            : {
      46                 :      18858 :   pc->registerChecker(ProofRule::MACRO_ARITH_SCALE_SUM_UB, this);
      47                 :      18858 :   pc->registerChecker(ProofRule::ARITH_SUM_UB, this);
      48                 :      18858 :   pc->registerChecker(ProofRule::ARITH_TRICHOTOMY, this);
      49                 :      18858 :   pc->registerChecker(ProofRule::INT_TIGHT_UB, this);
      50                 :      18858 :   pc->registerChecker(ProofRule::INT_TIGHT_LB, this);
      51                 :      18858 :   pc->registerChecker(ProofRule::ARITH_REDUCTION, this);
      52                 :      18858 :   pc->registerChecker(ProofRule::ARITH_MULT_POS, this);
      53                 :      18858 :   pc->registerChecker(ProofRule::ARITH_MULT_NEG, this);
      54                 :      18858 :   pc->registerChecker(ProofRule::ARITH_POLY_NORM, this);
      55                 :      18858 :   pc->registerChecker(ProofRule::ARITH_POLY_NORM_REL, this);
      56                 :            :   // register the extended proof checkers
      57                 :      18858 :   d_extChecker.registerTo(pc);
      58                 :      18858 :   d_trChecker.registerTo(pc);
      59                 :            : #ifdef CVC5_POLY_IMP
      60                 :      18858 :   d_covChecker.registerTo(pc);
      61                 :            : #endif
      62                 :      18858 : }
      63                 :            : 
      64                 :    1022500 : Node ArithProofRuleChecker::checkInternal(ProofRule id,
      65                 :            :                                           const std::vector<Node>& children,
      66                 :            :                                           const std::vector<Node>& args)
      67                 :            : {
      68                 :    1022500 :   NodeManager* nm = nodeManager();
      69         [ -  + ]:    1022500 :   if (TraceIsOn("arith::pf::check"))
      70                 :            :   {
      71         [ -  - ]:          0 :     Trace("arith::pf::check") << "Arith ProofRule:" << id << std::endl;
      72         [ -  - ]:          0 :     Trace("arith::pf::check") << "  children: " << std::endl;
      73         [ -  - ]:          0 :     for (const auto& c : children)
      74                 :            :     {
      75         [ -  - ]:          0 :       Trace("arith::pf::check") << "  * " << c << std::endl;
      76                 :            :     }
      77         [ -  - ]:          0 :     Trace("arith::pf::check") << "  args:" << std::endl;
      78         [ -  - ]:          0 :     for (const auto& c : args)
      79                 :            :     {
      80         [ -  - ]:          0 :       Trace("arith::pf::check") << "  * " << c << std::endl;
      81                 :            :     }
      82                 :            :   }
      83 [ +  + ][ +  + ]:    1022500 :   switch (id)
         [ +  + ][ +  + ]
            [ +  + ][ - ]
      84                 :            :   {
      85                 :      16029 :     case ProofRule::ARITH_MULT_POS:
      86                 :            :     {
      87 [ -  + ][ -  + ]:      16029 :       Assert(children.empty());
                 [ -  - ]
      88 [ -  + ][ -  + ]:      16029 :       Assert(args.size() == 2);
                 [ -  - ]
      89                 :      32058 :       Node mult = args[0];
      90                 :      16029 :       Kind rel = args[1].getKind();
      91 [ +  + ][ +  - ]:      16029 :       Assert(rel == Kind::EQUAL || rel == Kind::DISTINCT || rel == Kind::LT
         [ +  + ][ +  + ]
         [ +  + ][ -  + ]
         [ -  + ][ -  - ]
      92                 :            :              || rel == Kind::LEQ || rel == Kind::GT || rel == Kind::GEQ);
      93                 :      32058 :       Node lhs = args[1][0];
      94                 :      32058 :       Node rhs = args[1][1];
      95                 :      32058 :       Node zero = nm->mkConstRealOrInt(mult.getType(), Rational(0));
      96                 :            :       return nm->mkNode(Kind::IMPLIES,
      97 [ +  + ][ -  - ]:      80145 :                         nm->mkAnd(std::vector<Node>{
      98                 :      48087 :                             nm->mkNode(Kind::GT, mult, zero), args[1]}),
      99                 :      48087 :                         nm->mkNode(rel,
     100                 :      32058 :                                    nm->mkNode(Kind::MULT, mult, lhs),
     101                 :      80145 :                                    nm->mkNode(Kind::MULT, mult, rhs)));
     102                 :            :     }
     103                 :     116137 :     case ProofRule::ARITH_MULT_NEG:
     104                 :            :     {
     105 [ -  + ][ -  + ]:     116137 :       Assert(children.empty());
                 [ -  - ]
     106 [ -  + ][ -  + ]:     116137 :       Assert(args.size() == 2);
                 [ -  - ]
     107                 :     232274 :       Node mult = args[0];
     108                 :     116137 :       Kind rel = args[1].getKind();
     109 [ +  + ][ +  - ]:     116137 :       Assert(rel == Kind::EQUAL || rel == Kind::DISTINCT || rel == Kind::LT
         [ +  + ][ +  + ]
         [ +  + ][ -  + ]
         [ -  + ][ -  - ]
     110                 :            :              || rel == Kind::LEQ || rel == Kind::GT || rel == Kind::GEQ);
     111         [ +  - ]:     116137 :       Kind rel_inv = (rel == Kind::DISTINCT ? rel : reverseRelationKind(rel));
     112                 :     232274 :       Node lhs = args[1][0];
     113                 :     232274 :       Node rhs = args[1][1];
     114                 :     232274 :       Node zero = nm->mkConstRealOrInt(mult.getType(), Rational(0));
     115                 :            :       return nm->mkNode(Kind::IMPLIES,
     116 [ +  + ][ -  - ]:     580685 :                         nm->mkAnd(std::vector<Node>{
     117                 :     348411 :                             nm->mkNode(Kind::LT, mult, zero), args[1]}),
     118                 :     348411 :                         nm->mkNode(rel_inv,
     119                 :     232274 :                                    nm->mkNode(Kind::MULT, mult, lhs),
     120                 :     580685 :                                    nm->mkNode(Kind::MULT, mult, rhs)));
     121                 :            :     }
     122                 :      89189 :     case ProofRule::ARITH_SUM_UB:
     123                 :            :     {
     124         [ -  + ]:      89189 :       if (children.size() < 2)
     125                 :            :       {
     126                 :          0 :         return Node::null();
     127                 :            :       }
     128                 :            : 
     129                 :            :       // Whether a strict inequality is in the sum.
     130                 :      89189 :       bool strict = false;
     131                 :     178378 :       NodeBuilder leftSum(nm, Kind::ADD);
     132                 :     178378 :       NodeBuilder rightSum(nm, Kind::ADD);
     133         [ +  + ]:     477015 :       for (size_t i = 0; i < children.size(); ++i)
     134                 :            :       {
     135                 :            :         // Adjust strictness
     136    [ +  + ][ - ]:     387826 :         switch (children[i].getKind())
     137                 :            :         {
     138                 :      74397 :           case Kind::LT:
     139                 :            :           {
     140                 :      74397 :             strict = true;
     141                 :      74397 :             break;
     142                 :            :           }
     143                 :     313429 :           case Kind::LEQ:
     144                 :            :           case Kind::EQUAL:
     145                 :            :           {
     146                 :     313429 :             break;
     147                 :            :           }
     148                 :          0 :           default:
     149                 :            :           {
     150         [ -  - ]:          0 :             Trace("arith::pf::check")
     151                 :          0 :                 << "Bad kind: " << children[i].getKind() << std::endl;
     152                 :          0 :             return Node::null();
     153                 :            :           }
     154                 :            :         }
     155                 :     387826 :         leftSum << children[i][0];
     156                 :     387826 :         rightSum << children[i][1];
     157                 :            :       }
     158                 :            :       Node r = nm->mkNode(strict ? Kind::LT : Kind::LEQ,
     159                 :     178378 :                           leftSum.constructNode(),
     160         [ +  + ]:     445945 :                           rightSum.constructNode());
     161                 :      89189 :       return r;
     162                 :            :     }
     163                 :     703099 :     case ProofRule::MACRO_ARITH_SCALE_SUM_UB:
     164                 :            :     {
     165                 :            :       //================================================= Arithmetic rules
     166                 :            :       // ======== Adding Inequalities
     167                 :            :       // Note: an ArithLiteral is a term of the form (>< poly const)
     168                 :            :       // where
     169                 :            :       //   >< is >=, >, ==, <, <=, or not(== ...).
     170                 :            :       //   poly is a polynomial
     171                 :            :       //   const is a rational constant
     172                 :            : 
     173                 :            :       // Children: (P1:l1, ..., Pn:ln)
     174                 :            :       //           where each li is an ArithLiteral
     175                 :            :       //           not(= ...) is dis-allowed!
     176                 :            :       //
     177                 :            :       // Arguments: (k1, ..., kn), non-zero reals
     178                 :            :       // ---------------------
     179                 :            :       // Conclusion: (>< t1 t2)
     180                 :            :       //    where >< is the fusion of the combination of the ><i, (flipping each
     181                 :            :       //    it its ki is negative). >< is always one of <, <= NB: this implies
     182                 :            :       //    that lower bounds must have negative ki,
     183                 :            :       //                      and upper bounds must have positive ki.
     184                 :            :       //    t1 is the sum of the scaled polynomials (k_1 * poly_1 + ... + k_n *
     185                 :            :       //    poly_n) t2 is the sum of the scaled constants (k_1 * const_1 + ... +
     186                 :            :       //    k_n * const_n)
     187 [ -  + ][ -  + ]:     703099 :       Assert(children.size() == args.size());
                 [ -  - ]
     188         [ -  + ]:     703099 :       if (children.size() < 2)
     189                 :            :       {
     190                 :          0 :         return Node::null();
     191                 :            :       }
     192                 :            : 
     193                 :            :       // Whether a strict inequality is in the sum.
     194                 :     703099 :       bool strict = false;
     195                 :    1406200 :       NodeBuilder leftSum(nm, Kind::ADD);
     196                 :    1406200 :       NodeBuilder rightSum(nm, Kind::ADD);
     197         [ +  + ]:    2616100 :       for (size_t i = 0; i < children.size(); ++i)
     198                 :            :       {
     199                 :    1913000 :         Rational scalar = args[i].getConst<Rational>();
     200         [ -  + ]:    1913000 :         if (scalar == 0)
     201                 :            :         {
     202         [ -  - ]:          0 :           Trace("arith::pf::check") << "Error: zero scalar" << std::endl;
     203                 :          0 :           return Node::null();
     204                 :            :         }
     205                 :            : 
     206                 :            :         // Adjust strictness
     207    [ +  + ][ - ]:    1913000 :         switch (children[i].getKind())
     208                 :            :         {
     209                 :     362533 :           case Kind::GT:
     210                 :            :           case Kind::LT:
     211                 :            :           {
     212                 :     362533 :             strict = true;
     213                 :     362533 :             break;
     214                 :            :           }
     215                 :    1550470 :           case Kind::GEQ:
     216                 :            :           case Kind::LEQ:
     217                 :            :           case Kind::EQUAL:
     218                 :            :           {
     219                 :    1550470 :             break;
     220                 :            :           }
     221                 :          0 :           default:
     222                 :            :           {
     223         [ -  - ]:          0 :             Trace("arith::pf::check")
     224                 :          0 :                 << "Bad kind: " << children[i].getKind() << std::endl;
     225                 :            :           }
     226                 :            :         }
     227                 :            :         // check for spurious mixed arithmetic
     228                 :    3826000 :         if (children[i][0].getType().isReal()
     229                 :    3826000 :             || children[i][1].getType().isReal())
     230                 :            :         {
     231         [ -  + ]:     694383 :           if (args[i].getType().isInteger())
     232                 :            :           {
     233                 :            :             // Should use real for predicates over reals. This is only
     234                 :            :             // necessary for avoiding spurious usage of mixed arithmetic, but we
     235                 :            :             // check here to be pedantic.
     236                 :          0 :             return Node::null();
     237                 :            :           }
     238                 :            :         }
     239 [ +  + ][ -  + ]:    1218620 :         else if (args[i].getType().isReal() && scalar.isIntegral())
         [ +  - ][ -  + ]
                 [ -  - ]
     240                 :            :         {
     241                 :            :           // conversely, don't use (integral) real for integer relation.
     242                 :          0 :           return Node::null();
     243                 :            :         }
     244                 :            :         // Check sign
     245 [ +  + ][ +  - ]:    1913000 :         switch (children[i].getKind())
     246                 :            :         {
     247                 :     462259 :           case Kind::GT:
     248                 :            :           case Kind::GEQ:
     249                 :            :           {
     250         [ -  + ]:     462259 :             if (scalar > 0)
     251                 :            :             {
     252         [ -  - ]:          0 :               Trace("arith::pf::check")
     253                 :          0 :                   << "Positive scalar for lower bound: " << scalar << " for "
     254                 :          0 :                   << children[i] << std::endl;
     255                 :          0 :               return Node::null();
     256                 :            :             }
     257                 :     462259 :             break;
     258                 :            :           }
     259                 :     585235 :           case Kind::LEQ:
     260                 :            :           case Kind::LT:
     261                 :            :           {
     262         [ -  + ]:     585235 :             if (scalar < 0)
     263                 :            :             {
     264         [ -  - ]:          0 :               Trace("arith::pf::check")
     265                 :          0 :                   << "Negative scalar for upper bound: " << scalar << " for "
     266                 :          0 :                   << children[i] << std::endl;
     267                 :          0 :               return Node::null();
     268                 :            :             }
     269                 :     585235 :             break;
     270                 :            :           }
     271                 :     865508 :           case Kind::EQUAL:
     272                 :            :           {
     273                 :     865508 :             break;
     274                 :            :           }
     275                 :          0 :           default:
     276                 :            :           {
     277         [ -  - ]:          0 :             Trace("arith::pf::check")
     278                 :          0 :                 << "Bad kind: " << children[i].getKind() << std::endl;
     279                 :            :           }
     280                 :            :         }
     281                 :            :         // if multiplying by one, don't introduce MULT
     282         [ +  + ]:    1913000 :         if (scalar == 1)
     283                 :            :         {
     284                 :     886947 :           leftSum << children[i][0];
     285                 :     886947 :           rightSum << children[i][1];
     286                 :            :         }
     287                 :            :         else
     288                 :            :         {
     289                 :    1026060 :           leftSum << nm->mkNode(Kind::MULT, args[i], children[i][0]);
     290                 :    1026060 :           rightSum << nm->mkNode(Kind::MULT, args[i], children[i][1]);
     291                 :            :         }
     292                 :            :       }
     293                 :            :       Node r = nm->mkNode(strict ? Kind::LT : Kind::LEQ,
     294                 :    1406200 :                           leftSum.constructNode(),
     295         [ +  + ]:    3515500 :                           rightSum.constructNode());
     296                 :     703099 :       return r;
     297                 :            :     }
     298                 :        742 :     case ProofRule::INT_TIGHT_LB:
     299                 :            :     {
     300                 :            :       // Children: (P:(> i c))
     301                 :            :       //         where i has integer type.
     302                 :            :       // Arguments: none
     303                 :            :       // ---------------------
     304                 :            :       // Conclusion: (>= i leastIntGreaterThan(c)})
     305                 :       1484 :       if (children.size() != 1
     306         [ -  + ]:        742 :           || (children[0].getKind() != Kind::GT
     307         [ -  - ]:          0 :               && children[0].getKind() != Kind::GEQ)
     308                 :       1484 :           || !children[0][0].getType().isInteger() || !children[0][1].isConst())
     309                 :            :       {
     310         [ -  - ]:          0 :         Trace("arith::pf::check") << "Illformed input: " << children;
     311                 :          0 :         return Node::null();
     312                 :            :       }
     313                 :            :       else
     314                 :            :       {
     315                 :       1484 :         Rational originalBound = children[0][1].getConst<Rational>();
     316                 :       1484 :         Rational newBound = leastIntGreaterThan(originalBound);
     317                 :        742 :         Node rational = nm->mkConstInt(newBound);
     318                 :        742 :         return nm->mkNode(Kind::GEQ, children[0][0], rational);
     319                 :            :       }
     320                 :            :     }
     321                 :       9245 :     case ProofRule::INT_TIGHT_UB:
     322                 :            :     {
     323                 :            :       // ======== Tightening Strict Integer Upper Bounds
     324                 :            :       // Children: (P:(< i c))
     325                 :            :       //         where i has integer type.
     326                 :            :       // Arguments: none
     327                 :            :       // ---------------------
     328                 :            :       // Conclusion: (<= i greatestIntLessThan(c)})
     329                 :      18490 :       if (children.size() != 1
     330         [ -  + ]:       9245 :           || (children[0].getKind() != Kind::LT
     331         [ -  - ]:          0 :               && children[0].getKind() != Kind::LEQ)
     332                 :      18490 :           || !children[0][0].getType().isInteger() || !children[0][1].isConst())
     333                 :            :       {
     334         [ -  - ]:          0 :         Trace("arith::pf::check") << "Illformed input: " << children;
     335                 :          0 :         return Node::null();
     336                 :            :       }
     337                 :            :       else
     338                 :            :       {
     339                 :      18490 :         Rational originalBound = children[0][1].getConst<Rational>();
     340                 :      18490 :         Rational newBound = greatestIntLessThan(originalBound);
     341                 :       9245 :         Node rational = nm->mkConstInt(newBound);
     342                 :       9245 :         return nm->mkNode(Kind::LEQ, children[0][0], rational);
     343                 :            :       }
     344                 :            :     }
     345                 :       5951 :     case ProofRule::ARITH_TRICHOTOMY:
     346                 :            :     {
     347                 :      11902 :       Node a = negateProofLiteral(children[0]);
     348                 :      11902 :       Node b = negateProofLiteral(children[1]);
     349                 :       5951 :       if (a[0] == b[0] && a[1] == b[1])
     350                 :            :       {
     351                 :      11902 :         std::set<Kind> cmps;
     352                 :       5951 :         cmps.insert(a.getKind());
     353                 :       5951 :         cmps.insert(b.getKind());
     354                 :       5951 :         Kind retk = Kind::UNDEFINED_KIND;
     355         [ +  + ]:       5951 :         if (cmps.count(Kind::EQUAL) == 0)
     356                 :            :         {
     357                 :       3560 :           retk = Kind::EQUAL;
     358                 :            :         }
     359         [ +  + ]:       5951 :         if (cmps.count(Kind::GT) == 0)
     360                 :            :         {
     361         [ -  + ]:       1340 :           if (retk != Kind::UNDEFINED_KIND)
     362                 :            :           {
     363         [ -  - ]:          0 :             Trace("arith::pf::check")
     364                 :          0 :                 << "Error: No GT and " << retk << std::endl;
     365                 :          0 :             return Node::null();
     366                 :            :           }
     367                 :       1340 :           retk = Kind::GT;
     368                 :            :         }
     369         [ +  + ]:       5951 :         if (cmps.count(Kind::LT) == 0)
     370                 :            :         {
     371         [ -  + ]:       1051 :           if (retk != Kind::UNDEFINED_KIND)
     372                 :            :           {
     373         [ -  - ]:          0 :             Trace("arith::pf::check")
     374                 :          0 :                 << "Error: No LT and " << retk << std::endl;
     375                 :          0 :             return Node::null();
     376                 :            :           }
     377                 :       1051 :           retk = Kind::LT;
     378                 :            :         }
     379                 :       5951 :         return nm->mkNode(retk, a[0], a[1]);
     380                 :            :       }
     381                 :            :       else
     382                 :            :       {
     383         [ -  - ]:          0 :         Trace("arith::pf::check")
     384                 :          0 :             << "Error: Different polynomials / values" << std::endl;
     385         [ -  - ]:          0 :         Trace("arith::pf::check") << "  a: " << a << std::endl;
     386         [ -  - ]:          0 :         Trace("arith::pf::check") << "  b: " << b << std::endl;
     387                 :          0 :         return Node::null();
     388                 :            :       }
     389                 :            :       // Check that all have the same constant:
     390                 :            :     }
     391                 :       1404 :     case ProofRule::ARITH_REDUCTION:
     392                 :            :     {
     393 [ -  + ][ -  + ]:       1404 :       Assert(children.empty());
                 [ -  - ]
     394 [ -  + ][ -  + ]:       1404 :       Assert(args.size() == 1);
                 [ -  - ]
     395                 :       1404 :       return OperatorElim::getAxiomFor(nm, args[0]);
     396                 :            :     }
     397                 :      52284 :     case ProofRule::ARITH_POLY_NORM:
     398                 :            :     {
     399 [ -  + ][ -  + ]:      52284 :       Assert(children.empty());
                 [ -  - ]
     400 [ -  + ][ -  + ]:      52284 :       Assert(args.size() == 1);
                 [ -  - ]
     401                 :      52284 :       if (args[0].getKind() != Kind::EQUAL
     402                 :     104568 :           || !args[0][0].getType().isRealOrInt())
     403                 :            :       {
     404                 :          0 :         return Node::null();
     405                 :            :       }
     406         [ -  + ]:      52284 :       if (!PolyNorm::isArithPolyNorm(args[0][0], args[0][1]))
     407                 :            :       {
     408                 :          0 :         return Node::null();
     409                 :            :       }
     410                 :      52284 :       return args[0];
     411                 :            :     }
     412                 :      28424 :     case ProofRule::ARITH_POLY_NORM_REL:
     413                 :            :     {
     414 [ -  + ][ -  + ]:      28424 :       Assert(children.size() == 1);
                 [ -  - ]
     415 [ -  + ][ -  + ]:      28424 :       Assert(args.size() == 1);
                 [ -  - ]
     416         [ -  + ]:      28424 :       if (args[0].getKind() != Kind::EQUAL)
     417                 :            :       {
     418                 :          0 :         return Node::null();
     419                 :            :       }
     420                 :      28424 :       Kind k = args[0][0].getKind();
     421 [ +  + ][ +  + ]:      28424 :       if (k != Kind::LT && k != Kind::LEQ && k != Kind::EQUAL && k != Kind::GT
         [ +  + ][ +  + ]
     422         [ -  + ]:      11733 :           && k != Kind::GEQ)
     423                 :            :       {
     424                 :          0 :         return Node::null();
     425                 :            :       }
     426         [ -  + ]:      28424 :       if (children[0].getKind() != Kind::EQUAL)
     427                 :            :       {
     428                 :          0 :         return Node::null();
     429                 :            :       }
     430                 :      56848 :       Node l = children[0][0];
     431                 :      56848 :       Node r = children[0][1];
     432 [ +  - ][ -  + ]:      28424 :       if (l.getKind() != Kind::MULT || r.getKind() != Kind::MULT)
                 [ -  + ]
     433                 :            :       {
     434                 :          0 :         return Node::null();
     435                 :            :       }
     436                 :      56848 :       Node lr = l[1];
     437         [ +  + ]:      28424 :       lr = lr.getKind() == Kind::TO_REAL ? lr[0] : lr;
     438                 :      56848 :       Node rr = r[1];
     439         [ +  + ]:      28424 :       rr = rr.getKind() == Kind::TO_REAL ? rr[0] : rr;
     440 [ +  - ][ -  + ]:      28424 :       if (lr.getKind() != Kind::SUB || rr.getKind() != Kind::SUB)
                 [ -  + ]
     441                 :            :       {
     442                 :          0 :         return Node::null();
     443                 :            :       }
     444                 :      56848 :       Node cx = l[0];
     445                 :      56848 :       Node x1 = lr[0];
     446                 :      56848 :       Node x2 = lr[1];
     447                 :      56848 :       Node cy = r[0];
     448                 :      56848 :       Node y1 = rr[0];
     449                 :      56848 :       Node y2 = rr[1];
     450                 :      28424 :       if ((cx.getKind() == Kind::CONST_INTEGER
     451         [ +  - ]:      11567 :            || cx.getKind() == Kind::CONST_RATIONAL)
     452 [ +  + ][ +  + ]:      51558 :           && (cy.getKind() == Kind::CONST_INTEGER
                 [ +  - ]
     453         [ +  - ]:      11567 :               || cy.getKind() == Kind::CONST_RATIONAL))
     454                 :            :       {
     455                 :      28424 :         Rational c1 = cx.getConst<Rational>();
     456                 :      28424 :         Rational c2 = cy.getConst<Rational>();
     457 [ +  + ][ -  + ]:      28424 :         if (k != Kind::EQUAL && c1.sgn() != c2.sgn())
                 [ -  + ]
     458                 :            :         {
     459                 :          0 :           return Node::null();
     460                 :            :         }
     461                 :            :       }
     462                 :      85272 :       Node ret = nm->mkNode(k, x1, x2).eqNode(nm->mkNode(k, y1, y2));
     463         [ -  + ]:      28424 :       if (ret != args[0])
     464                 :            :       {
     465                 :          0 :         return Node::null();
     466                 :            :       }
     467                 :      28424 :       return ret;
     468                 :            :     }
     469                 :          0 :     default: return Node::null();
     470                 :            :   }
     471                 :            : }
     472                 :            : }  // namespace arith
     473                 :            : }  // namespace theory
     474                 :            : }  // namespace cvc5::internal

Generated by: LCOV version 1.14