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: 198 257 77.0 %
Date: 2026-07-28 10:35:35 Functions: 3 3 100.0 %
Branches: 157 309 50.8 %

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

Generated by: LCOV version 1.14