LCOV - code coverage report
Current view: top level - buildbot/coverage/build/src/theory/arith/linear - congruence_manager.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 417 446 93.5 %
Date: 2026-03-23 10:24:23 Functions: 27 29 93.1 %
Branches: 218 434 50.2 %

           Branch data     Line data    Source code
       1                 :            : /******************************************************************************
       2                 :            :  * This file is part of the cvc5 project.
       3                 :            :  *
       4                 :            :  * Copyright (c) 2009-2026 by the authors listed in the file AUTHORS
       5                 :            :  * in the top-level source directory and their institutional affiliations.
       6                 :            :  * All rights reserved.  See the file COPYING in the top-level source
       7                 :            :  * directory for licensing information.
       8                 :            :  * ****************************************************************************
       9                 :            :  *
      10                 :            :  * Congruence manager, the interface to the equality engine from the
      11                 :            :  * linear arithmetic solver
      12                 :            :  */
      13                 :            : 
      14                 :            : #include "theory/arith/linear/congruence_manager.h"
      15                 :            : 
      16                 :            : #include "base/output.h"
      17                 :            : #include "options/arith_options.h"
      18                 :            : #include "proof/conv_proof_generator.h"
      19                 :            : #include "proof/proof_checker.h"
      20                 :            : #include "proof/proof_node.h"
      21                 :            : #include "proof/proof_node_manager.h"
      22                 :            : #include "smt/env.h"
      23                 :            : #include "theory/arith/arith_poly_norm.h"
      24                 :            : #include "theory/arith/arith_proof_utilities.h"
      25                 :            : #include "theory/arith/arith_subs.h"
      26                 :            : #include "theory/arith/arith_utilities.h"
      27                 :            : #include "theory/arith/linear/constraint.h"
      28                 :            : #include "theory/arith/linear/partial_model.h"
      29                 :            : #include "theory/ee_setup_info.h"
      30                 :            : #include "theory/rewriter.h"
      31                 :            : #include "theory/uf/equality_engine.h"
      32                 :            : #include "theory/uf/proof_equality_engine.h"
      33                 :            : 
      34                 :            : using namespace cvc5::internal::kind;
      35                 :            : 
      36                 :            : namespace cvc5::internal {
      37                 :            : namespace theory {
      38                 :            : namespace arith::linear {
      39                 :            : 
      40                 :        429 : std::vector<Node> andComponents(NodeManager* nm, TNode an)
      41                 :            : {
      42         [ -  + ]:        429 :   if (an == nm->mkConst(true))
      43                 :            :   {
      44                 :          0 :     return {};
      45                 :            :   }
      46         [ -  + ]:        429 :   else if (an.getKind() != Kind::AND)
      47                 :            :   {
      48                 :          0 :     return {an};
      49                 :            :   }
      50                 :        429 :   std::vector<Node> a{};
      51                 :        429 :   a.reserve(an.getNumChildren());
      52                 :        429 :   a.insert(a.end(), an.begin(), an.end());
      53                 :        429 :   return a;
      54                 :        429 : }
      55                 :            : 
      56                 :      50263 : ArithCongruenceManager::ArithCongruenceManager(
      57                 :            :     Env& env,
      58                 :            :     ConstraintDatabase& cd,
      59                 :            :     SetupLiteralCallBack setup,
      60                 :            :     const ArithVariables& avars,
      61                 :      50263 :     RaiseEqualityEngineConflict raiseConflict)
      62                 :            :     : EnvObj(env),
      63                 :      50263 :       d_inConflict(context()),
      64                 :      50263 :       d_raiseConflict(raiseConflict),
      65                 :      50263 :       d_keepAlive(context()),
      66                 :      50263 :       d_propagatations(context()),
      67                 :      50263 :       d_explanationMap(context()),
      68                 :      50263 :       d_constraintDatabase(cd),
      69                 :      50263 :       d_setupLiteral(setup),
      70                 :      50263 :       d_avariables(avars),
      71                 :      50263 :       d_ee(nullptr),
      72         [ +  + ]:      50263 :       d_pnm(d_env.isTheoryProofProducing() ? d_env.getProofNodeManager()
      73                 :            :                                            : nullptr),
      74                 :            :       // Construct d_pfGenEe with the SAT context, since its proof include
      75                 :            :       // unclosed assumptions of theory literals.
      76                 :     100526 :       d_pfGenEe(new EagerProofGenerator(
      77                 :     100526 :           d_env, context(), "ArithCongruenceManager::pfGenEe")),
      78                 :            :       // Construct d_pfGenEe with the USER context, since its proofs are closed.
      79                 :     100526 :       d_pfGenExplain(new EagerProofGenerator(
      80                 :     100526 :           d_env, userContext(), "ArithCongruenceManager::pfGenExplain")),
      81                 :      50263 :       d_pfee(nullptr),
      82                 :     150789 :       d_statistics(statisticsRegistry())
      83                 :            : {
      84                 :      50263 : }
      85                 :            : 
      86                 :      49918 : ArithCongruenceManager::~ArithCongruenceManager() {}
      87                 :            : 
      88                 :      50191 : void ArithCongruenceManager::finishInit(eq::EqualityEngine* ee)
      89                 :            : {
      90 [ -  + ][ -  + ]:      50191 :   Assert(ee != nullptr);
                 [ -  - ]
      91                 :            :   // otherwise, we use the official one
      92                 :      50191 :   d_ee = ee;
      93                 :            :   // the congruence kinds are already set up
      94                 :            :   // the proof equality engine is the one from the equality engine
      95                 :      50191 :   d_pfee = d_ee->getProofEqualityEngine();
      96                 :            :   // have proof equality engine only if proofs are enabled
      97 [ -  + ][ -  + ]:      50191 :   Assert(isProofEnabled() == (d_pfee != nullptr));
                 [ -  - ]
      98                 :      50191 : }
      99                 :            : 
     100                 :      50263 : ArithCongruenceManager::Statistics::Statistics(StatisticsRegistry& sr)
     101                 :            :     : d_watchedVariables(
     102                 :      50263 :         sr.registerInt("theory::arith::congruence::watchedVariables")),
     103                 :            :       d_watchedVariableIsZero(
     104                 :      50263 :           sr.registerInt("theory::arith::congruence::watchedVariableIsZero")),
     105                 :      50263 :       d_watchedVariableIsNotZero(sr.registerInt(
     106                 :            :           "theory::arith::congruence::watchedVariableIsNotZero")),
     107                 :            :       d_equalsConstantCalls(
     108                 :      50263 :           sr.registerInt("theory::arith::congruence::equalsConstantCalls")),
     109                 :      50263 :       d_propagations(sr.registerInt("theory::arith::congruence::propagations")),
     110                 :            :       d_propagateConstraints(
     111                 :      50263 :           sr.registerInt("theory::arith::congruence::propagateConstraints")),
     112                 :      50263 :       d_conflicts(sr.registerInt("theory::arith::congruence::conflicts"))
     113                 :            : {
     114                 :      50263 : }
     115                 :            : 
     116                 :       4200 : void ArithCongruenceManager::raiseConflict(Node conflict,
     117                 :            :                                            std::shared_ptr<ProofNode> pf)
     118                 :            : {
     119 [ -  + ][ -  + ]:       4200 :   Assert(!inConflict());
                 [ -  - ]
     120         [ +  - ]:       4200 :   Trace("arith::conflict") << "difference manager conflict   " << conflict << std::endl;
     121                 :       4200 :   d_inConflict.raise();
     122                 :       4200 :   d_raiseConflict.raiseEEConflict(conflict, pf);
     123                 :       4200 : }
     124                 :    1708261 : bool ArithCongruenceManager::inConflict() const{
     125                 :    1708261 :   return d_inConflict.isRaised();
     126                 :            : }
     127                 :            : 
     128                 :    8078477 : bool ArithCongruenceManager::hasMorePropagations() const {
     129                 :    8078477 :   return !d_propagatations.empty();
     130                 :            : }
     131                 :    1235771 : const Node ArithCongruenceManager::getNextPropagation() {
     132 [ -  + ][ -  + ]:    1235771 :   Assert(hasMorePropagations());
                 [ -  - ]
     133                 :    1235771 :   Node prop = d_propagatations.front();
     134                 :    1235771 :   d_propagatations.dequeue();
     135                 :    1235771 :   return prop;
     136                 :          0 : }
     137                 :            : 
     138                 :     107436 : bool ArithCongruenceManager::canExplain(TNode n) const {
     139                 :     107436 :   return d_explanationMap.find(n) != d_explanationMap.end();
     140                 :            : }
     141                 :            : 
     142                 :      37222 : Node ArithCongruenceManager::externalToInternal(TNode n) const{
     143 [ -  + ][ -  + ]:      37222 :   Assert(canExplain(n));
                 [ -  - ]
     144                 :      37222 :   ExplainMap::const_iterator iter = d_explanationMap.find(n);
     145                 :      37222 :   size_t pos = (*iter).second;
     146                 :      74444 :   return d_propagatations[pos];
     147                 :            : }
     148                 :            : 
     149                 :    1082583 : void ArithCongruenceManager::pushBack(TNode n){
     150                 :    1082583 :   d_explanationMap.insert(n, d_propagatations.size());
     151                 :    1082583 :   d_propagatations.enqueue(n);
     152                 :            : 
     153                 :    1082583 :   ++(d_statistics.d_propagations);
     154                 :    1082583 : }
     155                 :     211890 : void ArithCongruenceManager::pushBack(TNode n, TNode r){
     156                 :     211890 :   d_explanationMap.insert(r, d_propagatations.size());
     157                 :     211890 :   d_explanationMap.insert(n, d_propagatations.size());
     158                 :     211890 :   d_propagatations.enqueue(n);
     159                 :            : 
     160                 :     211890 :   ++(d_statistics.d_propagations);
     161                 :     211890 : }
     162                 :          0 : void ArithCongruenceManager::pushBack(TNode n, TNode r, TNode w){
     163                 :          0 :   d_explanationMap.insert(w, d_propagatations.size());
     164                 :          0 :   d_explanationMap.insert(r, d_propagatations.size());
     165                 :          0 :   d_explanationMap.insert(n, d_propagatations.size());
     166                 :          0 :   d_propagatations.enqueue(n);
     167                 :            : 
     168                 :          0 :   ++(d_statistics.d_propagations);
     169                 :          0 : }
     170                 :            : 
     171                 :     701028 : void ArithCongruenceManager::watchedVariableIsZero(ConstraintCP lb, ConstraintCP ub){
     172 [ -  + ][ -  + ]:     701028 :   Assert(lb->isLowerBound());
                 [ -  - ]
     173 [ -  + ][ -  + ]:     701028 :   Assert(ub->isUpperBound());
                 [ -  - ]
     174 [ -  + ][ -  + ]:     701028 :   Assert(lb->getVariable() == ub->getVariable());
                 [ -  - ]
     175 [ -  + ][ -  + ]:     701028 :   Assert(lb->getValue().sgn() == 0);
                 [ -  - ]
     176 [ -  + ][ -  + ]:     701028 :   Assert(ub->getValue().sgn() == 0);
                 [ -  - ]
     177                 :            : 
     178                 :     701028 :   ++(d_statistics.d_watchedVariableIsZero);
     179                 :            : 
     180                 :     701028 :   ArithVar s = lb->getVariable();
     181                 :     701028 :   TNode eq = d_watchedEqualities[s];
     182                 :     701028 :   ConstraintCP eqC = d_constraintDatabase.getConstraint(
     183                 :            :       s, ConstraintType::Equality, lb->getValue());
     184                 :     701028 :   NodeBuilder reasonBuilder(nodeManager(), Kind::AND);
     185                 :     701028 :   auto pfLb = lb->externalExplainByAssertions(reasonBuilder);
     186                 :     701028 :   auto pfUb = ub->externalExplainByAssertions(reasonBuilder);
     187                 :     701028 :   Node reason = mkAndFromBuilder(nodeManager(), reasonBuilder);
     188                 :     701028 :   std::shared_ptr<ProofNode> pf{};
     189         [ +  + ]:     701028 :   if (isProofEnabled())
     190                 :            :   {
     191 [ +  + ][ -  - ]:    1392324 :     pf = d_pnm->mkNode(
     192                 :    1044243 :         ProofRule::ARITH_TRICHOTOMY, {pfLb, pfUb}, {}, eqC->getProofLiteral());
     193                 :     348081 :     pf = ensurePredTransform(d_pnm, pf, eq);
     194                 :            :   }
     195                 :            : 
     196                 :     701028 :   d_keepAlive.push_back(reason);
     197         [ +  - ]:    1402056 :   Trace("arith-ee") << "Asserting an equality on " << s << ", on trichotomy"
     198                 :     701028 :                     << std::endl;
     199         [ +  - ]:     701028 :   Trace("arith-ee") << "  based on " << lb << std::endl;
     200         [ +  - ]:     701028 :   Trace("arith-ee") << "  based on " << ub << std::endl;
     201                 :     701028 :   assertionToEqualityEngine(true, s, reason, pf);
     202                 :     701028 : }
     203                 :            : 
     204                 :     519910 : void ArithCongruenceManager::watchedVariableIsZero(ConstraintCP eq){
     205         [ +  - ]:     519910 :   Trace("arith::cong") << "Cong::watchedVariableIsZero: " << *eq << std::endl;
     206                 :            : 
     207 [ -  + ][ -  + ]:     519910 :   Assert(eq->isEquality());
                 [ -  - ]
     208 [ -  + ][ -  + ]:     519910 :   Assert(eq->getValue().sgn() == 0);
                 [ -  - ]
     209                 :            : 
     210                 :     519910 :   ++(d_statistics.d_watchedVariableIsZero);
     211                 :            : 
     212                 :     519910 :   ArithVar s = eq->getVariable();
     213                 :            : 
     214                 :            :   //Explain for conflict is correct as these proofs are generated
     215                 :            :   //and stored eagerly
     216                 :            :   //These will be safe for propagation later as well
     217                 :     519910 :   NodeBuilder nb(nodeManager(), Kind::AND);
     218                 :            :   // An open proof of eq from literals now in reason.
     219         [ -  + ]:     519910 :   if (TraceIsOn("arith::cong"))
     220                 :            :   {
     221         [ -  - ]:          0 :     eq->printProofTree(Trace("arith::cong"));
     222                 :            :   }
     223                 :     519910 :   auto pf = eq->externalExplainByAssertions(nb);
     224         [ +  + ]:     519910 :   if (isProofEnabled())
     225                 :            :   {
     226                 :     187109 :     pf = ensurePredTransform(d_pnm, pf, d_watchedEqualities[s]);
     227                 :            :   }
     228                 :     519910 :   Node reason = mkAndFromBuilder(nodeManager(), nb);
     229                 :            : 
     230                 :     519910 :   d_keepAlive.push_back(reason);
     231                 :     519910 :   assertionToEqualityEngine(true, s, reason, pf);
     232                 :     519910 : }
     233                 :            : 
     234                 :    1494178 : void ArithCongruenceManager::watchedVariableCannotBeZero(ConstraintCP c){
     235         [ +  - ]:    2988356 :   Trace("arith::cong::notzero")
     236                 :    1494178 :       << "Cong::watchedVariableCannotBeZero " << *c << std::endl;
     237                 :    1494178 :   ++(d_statistics.d_watchedVariableIsNotZero);
     238                 :            : 
     239                 :    1494178 :   ArithVar s = c->getVariable();
     240                 :    1494178 :   Node disEq = d_watchedEqualities[s].negate();
     241                 :            : 
     242                 :            :   //Explain for conflict is correct as these proofs are generated and stored eagerly
     243                 :            :   //These will be safe for propagation later as well
     244                 :    1494178 :   NodeBuilder nb(nodeManager(), Kind::AND);
     245                 :            :   // An open proof of eq from literals now in reason.
     246                 :    1494178 :   auto pf = c->externalExplainByAssertions(nb);
     247         [ -  + ]:    1494178 :   if (TraceIsOn("arith::cong::notzero"))
     248                 :            :   {
     249         [ -  - ]:          0 :     Trace("arith::cong::notzero") << "  original proof ";
     250         [ -  - ]:          0 :     pf->printDebug(Trace("arith::cong::notzero"));
     251         [ -  - ]:          0 :     Trace("arith::cong::notzero") << std::endl;
     252                 :            :   }
     253                 :    1494178 :   Node reason = mkAndFromBuilder(nodeManager(), nb);
     254         [ +  + ]:    1494178 :   if (isProofEnabled())
     255                 :            :   {
     256         [ +  + ]:     673265 :     if (c->getType() == ConstraintType::Disequality)
     257                 :            :     {
     258 [ -  + ][ -  + ]:     156402 :       Assert(c->getLiteral() == d_watchedEqualities[s].negate());
                 [ -  - ]
     259                 :            :       // We have to prove equivalence to the watched disequality.
     260                 :     156402 :       pf = ensurePredTransform(d_pnm, pf, disEq);
     261                 :            :     }
     262                 :            :     else
     263                 :            :     {
     264         [ +  - ]:    1033726 :       Trace("arith::cong::notzero")
     265                 :     516863 :           << "  proof modification needed" << std::endl;
     266                 :            : 
     267                 :            :       // Four cases:
     268                 :            :       //   c has form x_i = d, d > 0     => multiply c by -1 in Farkas proof
     269                 :            :       //   c has form x_i = d, d > 0     => multiply c by 1 in Farkas proof
     270                 :            :       //   c has form x_i <= d, d < 0     => multiply c by 1 in Farkas proof
     271                 :            :       //   c has form x_i >= d, d > 0     => multiply c by -1 in Farkas proof
     272                 :     516863 :       const bool scaleCNegatively = c->getType() == ConstraintType::LowerBound
     273 [ +  + ][ +  + ]:     535035 :                                     || (c->getType() == ConstraintType::Equality
     274         [ +  + ]:      18172 :                                         && c->getValue().sgn() > 0);
     275         [ +  + ]:     516863 :       const int cSign = scaleCNegatively ? -1 : 1;
     276                 :     516863 :       TNode isZero = d_watchedEqualities[s];
     277                 :     516863 :       TypeNode type = isZero[0].getType();
     278                 :     516863 :       const auto isZeroPf = d_pnm->mkAssume(isZero);
     279                 :     516863 :       const auto nm = nodeManager();
     280                 :    2067452 :       std::vector<std::shared_ptr<ProofNode>> pfs{isZeroPf, pf};
     281                 :            :       // Trick for getting correct, opposing signs.
     282                 :          0 :       std::vector<Node> coeff{nm->mkConstInt(Rational(-1 * cSign)),
     283                 :    2584315 :                               nm->mkConstInt(Rational(cSign))};
     284                 :     516863 :       std::vector<Node> coeffUse = getMacroSumUbCoeff(nm, pfs, coeff);
     285                 :            :       auto sumPf =
     286                 :     516863 :           d_pnm->mkNode(ProofRule::MACRO_ARITH_SCALE_SUM_UB, pfs, coeffUse);
     287                 :     516863 :       Node fn = nm->mkConst(false);
     288                 :     516863 :       const auto botPf = ensurePredTransform(d_pnm, sumPf, fn);
     289                 :    1550589 :       std::vector<Node> assumption = {isZero};
     290                 :     516863 :       pf = d_pnm->mkScope(botPf, assumption, false);
     291         [ -  + ]:     516863 :       if (TraceIsOn("arith::cong::notzero"))
     292                 :            :       {
     293         [ -  - ]:          0 :         Trace("arith::cong::notzero") << "  new proof ";
     294         [ -  - ]:          0 :         pf->printDebug(Trace("arith::cong::notzero"));
     295         [ -  - ]:          0 :         Trace("arith::cong::notzero") << std::endl;
     296                 :            :       }
     297                 :     516863 :     }
     298 [ -  + ][ -  + ]:     673265 :     Assert(pf->getResult() == disEq);
                 [ -  - ]
     299                 :            :   }
     300                 :    1494178 :   d_keepAlive.push_back(reason);
     301                 :    1494178 :   assertionToEqualityEngine(false, s, reason, pf);
     302                 :    1494178 : }
     303                 :            : 
     304                 :            : 
     305                 :    1704061 : bool ArithCongruenceManager::propagate(TNode x){
     306         [ +  - ]:    1704061 :   Trace("arith::congruenceManager")<< "ArithCongruenceManager::propagate("<<x<<")"<<std::endl;
     307         [ -  + ]:    1704061 :   if(inConflict()){
     308                 :          0 :     return true;
     309                 :            :   }
     310                 :            : 
     311                 :    1704061 :   Node rewritten = rewrite(x);
     312                 :            : 
     313                 :            :   //Need to still propagate this!
     314         [ +  + ]:    1704061 :   if (rewritten.getKind() == Kind::CONST_BOOLEAN)
     315                 :            :   {
     316                 :       3758 :     pushBack(x);
     317                 :            : 
     318         [ -  + ]:       3758 :     if(rewritten.getConst<bool>()){
     319                 :          0 :       return true;
     320                 :            :     }else{
     321                 :            :       // x rewrites to false.
     322                 :       3758 :       ++(d_statistics.d_conflicts);
     323                 :       3758 :       TrustNode trn = explainInternal(x);
     324                 :       3758 :       Node conf = flattenAnd(trn.getNode());
     325         [ +  - ]:       3758 :       Trace("arith::congruenceManager") << "rewritten to false "<<x<<" with explanation "<< conf << std::endl;
     326         [ +  + ]:       3758 :       if (isProofEnabled())
     327                 :            :       {
     328                 :       1956 :         auto pf = trn.getGenerator()->getProofFor(trn.getProven());
     329                 :       1956 :         auto confPf = ensurePredTransform(d_pnm, pf, conf.negate());
     330                 :       1956 :         raiseConflict(conf, confPf);
     331                 :       1956 :       }
     332                 :            :       else
     333                 :            :       {
     334                 :       1802 :         raiseConflict(conf);
     335                 :            :       }
     336                 :       3758 :       return false;
     337                 :       3758 :     }
     338                 :            :   }
     339                 :            : 
     340 [ -  + ][ -  + ]:    1700303 :   Assert(rewritten.getKind() != Kind::CONST_BOOLEAN);
                 [ -  - ]
     341                 :            : 
     342                 :    1700303 :   ConstraintP c = d_constraintDatabase.lookup(rewritten);
     343         [ +  + ]:    1700303 :   if(c == NullConstraint){
     344                 :            :     //using setup as there may not be a corresponding congruence literal yet
     345                 :      41746 :     d_setupLiteral(rewritten);
     346                 :      41746 :     c = d_constraintDatabase.lookup(rewritten);
     347 [ -  + ][ -  + ]:      41746 :     Assert(c != NullConstraint);
                 [ -  - ]
     348                 :            :   }
     349                 :            : 
     350         [ +  - ]:    3400606 :   Trace("arith::congruenceManager")<< "x is "
     351                 :          0 :                                    <<  c->hasProof() << " "
     352                 :          0 :                                    << (x == rewritten) << " "
     353                 :          0 :                                    << c->canBePropagated() << " "
     354                 :    1700303 :                                    << c->negationHasProof() << std::endl;
     355                 :            : 
     356         [ +  + ]:    1700303 :   if(c->negationHasProof()){
     357                 :        442 :     TrustNode texpC = explainInternal(x);
     358                 :        442 :     Node expC = texpC.getNode();
     359                 :        442 :     ConstraintCP negC = c->getNegation();
     360                 :        884 :     Node neg = Constraint::externalExplainByAssertions(nodeManager(), {negC});
     361                 :        442 :     Node conf = expC.andNode(neg);
     362                 :        442 :     Node finalPf = flattenAnd(conf);
     363                 :            : 
     364                 :        442 :     ++(d_statistics.d_conflicts);
     365         [ +  + ]:        442 :     if (isProofEnabled())
     366                 :            :     {
     367         [ +  - ]:        220 :       Trace("arith-cm-proof") << "Handle conflict " << finalPf << std::endl;
     368                 :            :       // we have a proof of (=> C L1) and need a proof of
     369                 :            :       // (not (and C L2)), where L1 and L2 are contradictory literals,
     370                 :            :       // stored in proven[1] and neg respectively below.
     371                 :        220 :       NodeManager* nm = nodeManager();
     372                 :        220 :       std::vector<Node> conj(finalPf.begin(), finalPf.end());
     373                 :        440 :       CDProof cdp(d_env);
     374                 :        220 :       Node falsen = nm->mkConst(false);
     375                 :        220 :       Node finalPfNeg = finalPf.notNode();
     376                 :        220 :       cdp.addProof(texpC.toProofNode());
     377                 :        220 :       Node proven = texpC.getProven();
     378         [ +  - ]:        220 :       Trace("arith-cm-proof") << "Proven was " << proven << std::endl;
     379                 :        220 :       Node antec = proven[0];
     380                 :        220 :       std::vector<Node> antecc;
     381         [ +  - ]:        220 :       if (antec.getKind() == Kind::AND)
     382                 :            :       {
     383                 :        220 :         antecc.insert(antecc.end(), antec.begin(), antec.end());
     384                 :        220 :         cdp.addStep(antec, ProofRule::AND_INTRO, antecc, {});
     385                 :            :       }
     386                 :            :       else
     387                 :            :       {
     388                 :          0 :         antecc.push_back(antec);
     389                 :            :       }
     390 [ +  + ][ -  - ]:        660 :       cdp.addStep(proven[1], ProofRule::MODUS_PONENS, {antec, proven}, {});
     391                 :        220 :       std::shared_ptr<ProofNode> pf;
     392                 :        220 :       bool success = false;
     393         [ +  + ]:        296 :       for (size_t i = 0; i < 2; i++)
     394                 :            :       {
     395         [ +  + ]:        259 :         Node lit1 = i == 0 ? neg : proven[1];
     396         [ +  + ]:        259 :         Node lit2 = i == 0 ? proven[1] : neg;
     397         [ +  - ]:        259 :         Trace("arith-cm-proof") << "same " << lit1 << " " << lit2 << std::endl;
     398                 :        259 :         Rational rx, ry;
     399                 :            :         // We are robust to cases where proven[1] and neg[0] are equivalent via
     400                 :            :         // arith poly norm here, where in most cases neg[0] is proven[1]
     401                 :        777 :         if (lit1.getKind() == Kind::NOT
     402                 :        259 :             && PolyNorm::isArithPolyNormRel(lit2, lit1[0], rx, ry))
     403                 :            :         {
     404         [ +  + ]:        183 :           if (lit1[0] != lit2)
     405                 :            :           {
     406                 :         38 :             Node eqa = lit2.eqNode(lit1[0]);
     407                 :            :             Node premise =
     408                 :         76 :                 PolyNorm::getArithPolyNormRelPremise(lit2, lit1[0], rx, ry);
     409                 :         76 :             cdp.addStep(premise, ProofRule::ARITH_POLY_NORM, {}, {premise});
     410                 :        114 :             cdp.addStep(eqa, ProofRule::ARITH_POLY_NORM_REL, {premise}, {eqa});
     411 [ +  + ][ -  - ]:        114 :             cdp.addStep(lit1[0], ProofRule::EQ_RESOLVE, {lit2, eqa}, {});
     412                 :         38 :           }
     413                 :            :           // L1 and L2 are negation of one another, just use CONTRA
     414 [ +  + ][ -  - ]:        549 :           cdp.addStep(falsen, ProofRule::CONTRA, {lit1[0], lit1}, {});
     415                 :        183 :           success = true;
     416                 :        183 :           break;
     417                 :            :         }
     418 [ +  + ][ +  + ]:        808 :       }
         [ +  + ][ +  + ]
     419 [ +  + ][ +  - ]:        220 :       if (!success && proven[1].getKind() == Kind::EQUAL)
         [ +  + ][ +  + ]
                 [ -  - ]
     420                 :            :       {
     421                 :            :         // otherwise typically proven[1] is of the form (= t c) or (= c t) where
     422                 :            :         // neg is the (negation of) a relation involving t.
     423                 :         74 :         Node peq = proven[1][0].isConst() ? proven[1][1].eqNode(proven[1][0])
     424                 :         89 :                                           : proven[1];
     425 [ -  + ][ -  + ]:         37 :         Assert (peq.getKind()==Kind::EQUAL);
                 [ -  - ]
     426         [ +  + ]:         37 :         if (peq[0].getKind()==Kind::TO_REAL)
     427                 :            :         {
     428                 :            :           // if we have (= (to_real t) c) where c is a rational, we do:
     429                 :            :           //                     -------------------------- ARITH_POLY_NORM_REL
     430                 :            :           // (= (to_real t) c)   (= (= (to_real t) c) (= t c'))
     431                 :            :           // ------------------------------------------------- EQ_RESOLVE
     432                 :            :           // (= t c')
     433                 :            :           // where c' is integer equivalent of c.
     434                 :          4 :           Assert (peq[1].isConst() && peq[1].getConst<Rational>().isIntegral());
     435                 :          4 :           Node ic = nm->mkConstInt(peq[1].getConst<Rational>());
     436                 :          8 :           Node peqi = peq[0][0].eqNode(ic);
     437                 :          4 :           Node equiv = peq.eqNode(peqi);
     438                 :          4 :           Rational cx, cy;
     439                 :          8 :           Node premise = PolyNorm::getArithPolyNormRelPremise(peq, peqi, cx, cy);
     440                 :          8 :           cdp.addStep(premise, ProofRule::ARITH_POLY_NORM, {}, {premise});
     441                 :         12 :           cdp.addStep(equiv, ProofRule::ARITH_POLY_NORM_REL, {premise}, {equiv});
     442 [ +  + ][ -  - ]:         12 :           cdp.addStep(peqi, ProofRule::EQ_RESOLVE, {peq, equiv}, {});
     443                 :          4 :           peq = peqi;
     444                 :          4 :         }
     445                 :         37 :         ProofChecker* pc = d_env.getProofNodeManager()->getChecker();
     446                 :            :         // We substitute t -> c within the arithmetic context of neg.
     447                 :            :         // In particular using an arithmetic context ensures that this rewrite
     448                 :            :         // should be locally handled as an ARITH_POLY_NORM step.
     449                 :            :         // Otherwise, we may require the full rewriter. For example:
     450                 :            :         // (= x f(x)) => (not (>= (+ x (* -1 f(x))) 0)) would otherwise fail if
     451                 :            :         // we applied at general substitution
     452                 :            :         // (not (>= (+ f(x) (* -1 f(f(x)))) 0)),
     453                 :            :         // whereas since x in f(x) is not in an arithmetic context, we want
     454                 :            :         // (not (>= (+ f(x) (* -1 f(x))) 0)).
     455                 :            :         // Furthermore note that we should not traverse non-linear
     456                 :            :         // multiplication here, as this inference was inferred via linear
     457                 :            :         // arithmetic which treats non-linear arithmetic as an abstraction.
     458                 :         37 :         ArithSubsTermContext astc(false);
     459                 :            :         TConvProofGenerator tcnv(d_env,
     460                 :            :                                  nullptr,
     461                 :            :                                  TConvPolicy::FIXPOINT,
     462                 :            :                                  TConvCachePolicy::NEVER,
     463                 :            :                                  "ArithRConsTConv",
     464                 :         74 :                                  &astc);
     465                 :         74 :         Trace("arith-cm-proof") << "add step " << peq[0] << " -> " << peq[1]
     466                 :         37 :                                 << ", rewrite " << neg << std::endl;
     467                 :         37 :         tcnv.addRewriteStep(peq[0], peq[1], &cdp);
     468                 :         37 :         std::shared_ptr<ProofNode> pfna = tcnv.getProofForRewriting(neg);
     469                 :         37 :         Node negr = pfna->getResult()[1];
     470                 :         74 :         Node res = pc->checkDebug(
     471                 :        148 :             ProofRule::MACRO_SR_PRED_TRANSFORM, {negr}, {falsen}, falsen);
     472 [ -  + ][ -  + ]:         37 :         Assert(!res.isNull());
                 [ -  - ]
     473         [ +  - ]:         37 :         if (!res.isNull())
     474                 :            :         {
     475                 :        111 :           cdp.addStep(
     476                 :            :               falsen, ProofRule::MACRO_SR_PRED_TRANSFORM, {negr}, {falsen});
     477                 :         37 :           success = true;
     478         [ +  - ]:         37 :           if (negr != neg)
     479                 :            :           {
     480                 :         37 :             cdp.addProof(pfna);
     481 [ +  + ][ -  - ]:        111 :             cdp.addStep(
     482                 :            :                 negr, ProofRule::EQ_RESOLVE, {neg, pfna->getResult()}, {});
     483                 :            :           }
     484                 :            :         }
     485                 :         37 :       }
     486         [ +  - ]:        220 :       if (success)
     487                 :            :       {
     488                 :        440 :         cdp.addStep(finalPfNeg, ProofRule::SCOPE, {falsen}, conj);
     489                 :        220 :         pf = cdp.getProofFor(finalPfNeg);
     490                 :            :       }
     491                 :        220 :       Assert(pf != nullptr) << "Failed from " << neg << " " << proven[1];
     492                 :        220 :       raiseConflict(finalPf, pf);
     493                 :        220 :     }
     494                 :            :     else
     495                 :            :     {
     496                 :        222 :       raiseConflict(finalPf);
     497                 :            :     }
     498         [ +  - ]:        884 :     Trace("arith::congruenceManager")
     499                 :        442 :         << "congruenceManager found a conflict " << finalPf << std::endl;
     500                 :        442 :     return false;
     501                 :        442 :   }
     502                 :            : 
     503                 :            :   // Cases for propagation
     504                 :            :   // C : c has a proof
     505                 :            :   // S : x == rewritten
     506                 :            :   // P : c can be propagated
     507                 :            :   //
     508                 :            :   // CSP
     509                 :            :   // 000 : propagate x, and mark C it as being explained
     510                 :            :   // 001 : propagate x, and propagate c after marking it as being explained
     511                 :            :   // 01* : propagate x, mark c but do not propagate c
     512                 :            :   // 10* : propagate x, do not mark c and do not propagate c
     513                 :            :   // 11* : drop the constraint, do not propagate x or c
     514                 :            : 
     515 [ +  + ][ +  + ]:    1699861 :   if(!c->hasProof() && x != rewritten){
                 [ +  + ]
     516         [ -  + ]:     211890 :     if(c->assertedToTheTheory()){
     517                 :          0 :       pushBack(x, rewritten, c->getWitness());
     518                 :            :     }else{
     519                 :     211890 :       pushBack(x, rewritten);
     520                 :            :     }
     521                 :            : 
     522                 :     211890 :     c->setEqualityEngineProof();
     523 [ +  + ][ +  - ]:     211890 :     if(c->canBePropagated() && !c->assertedToTheTheory()){
                 [ +  + ]
     524                 :            : 
     525                 :      33343 :       ++(d_statistics.d_propagateConstraints);
     526                 :      33343 :       c->propagate();
     527                 :            :     }
     528 [ +  + ][ +  - ]:    1487971 :   }else if(!c->hasProof() && x == rewritten){
                 [ +  + ]
     529         [ -  + ]:     165674 :     if(c->assertedToTheTheory()){
     530                 :          0 :       pushBack(x, c->getWitness());
     531                 :            :     }else{
     532                 :     165674 :       pushBack(x);
     533                 :            :     }
     534                 :     165674 :     c->setEqualityEngineProof();
     535 [ +  - ][ +  + ]:    1322297 :   }else if(c->hasProof() && x != rewritten){
                 [ +  + ]
     536         [ +  + ]:     913151 :     if(c->assertedToTheTheory()){
     537                 :     911483 :       pushBack(x);
     538                 :            :     }else{
     539                 :       1668 :       pushBack(x);
     540                 :            :     }
     541                 :            :   }else{
     542 [ +  - ][ +  - ]:     409146 :     Assert(c->hasProof() && x == rewritten);
         [ -  + ][ -  + ]
                 [ -  - ]
     543                 :            :   }
     544                 :    1699861 :   return true;
     545                 :    1704061 : }
     546                 :            : 
     547                 :      41422 : TrustNode ArithCongruenceManager::explainInternal(TNode internal)
     548                 :            : {
     549         [ +  + ]:      41422 :   if (isProofEnabled())
     550                 :            :   {
     551                 :      20471 :     return d_pfee->explain(internal);
     552                 :            :   }
     553                 :            :   // otherwise, explain without proof generator
     554                 :      20951 :   Node exp = d_ee->mkExplainLit(internal);
     555                 :      20951 :   return TrustNode::mkTrustPropExp(internal, exp, nullptr);
     556                 :      20951 : }
     557                 :            : 
     558                 :      37222 : TrustNode ArithCongruenceManager::explain(TNode external)
     559                 :            : {
     560         [ +  - ]:      37222 :   Trace("arith-ee") << "Ask for explanation of " << external << std::endl;
     561                 :      37222 :   Node internal = externalToInternal(external);
     562         [ +  - ]:      37222 :   Trace("arith-ee") << "...internal = " << internal << std::endl;
     563                 :      37222 :   TrustNode trn = explainInternal(internal);
     564                 :      37222 :   if (isProofEnabled() && trn.getProven()[1] != external)
     565                 :            :   {
     566 [ -  + ][ -  + ]:        429 :     Assert(trn.getKind() == TrustNodeKind::PROP_EXP);
                 [ -  - ]
     567 [ -  + ][ -  + ]:        429 :     Assert(trn.getProven().getKind() == Kind::IMPLIES);
                 [ -  - ]
     568 [ -  + ][ -  + ]:        429 :     Assert(trn.getGenerator() != nullptr);
                 [ -  - ]
     569         [ +  - ]:        858 :     Trace("arith-ee") << "tweaking proof to prove " << external << " not "
     570                 :        429 :                       << trn.getProven()[1] << std::endl;
     571                 :        429 :     std::vector<std::shared_ptr<ProofNode>> assumptionPfs;
     572                 :        858 :     std::vector<Node> assumptions = andComponents(nodeManager(), trn.getNode());
     573                 :        429 :     assumptionPfs.push_back(trn.toProofNode());
     574         [ +  + ]:       1504 :     for (const auto& a : assumptions)
     575                 :            :     {
     576                 :       1075 :       assumptionPfs.push_back(
     577                 :       3225 :           d_pnm->mkNode(ProofRule::TRUE_INTRO, {d_pnm->mkAssume(a)}, {}));
     578                 :            :     }
     579                 :            :     // uses substitution to true
     580                 :        429 :     auto litPf = d_pnm->mkNode(ProofRule::MACRO_SR_PRED_TRANSFORM,
     581                 :            :                                {assumptionPfs},
     582                 :            :                                {external},
     583                 :       1287 :                                external);
     584                 :        858 :     auto extPf = d_pnm->mkScope(litPf, assumptions);
     585                 :        429 :     return d_pfGenExplain->mkTrustedPropagation(external, trn.getNode(), extPf);
     586                 :        429 :   }
     587                 :      36793 :   return trn;
     588                 :      37222 : }
     589                 :            : 
     590                 :     136734 : void ArithCongruenceManager::addWatchedPair(ArithVar s, TNode x, TNode y){
     591 [ -  + ][ -  + ]:     136734 :   Assert(!isWatchedVariable(s));
                 [ -  - ]
     592                 :            : 
     593         [ +  - ]:     273468 :   Trace("arith::congruenceManager")
     594                 :     136734 :     << "addWatchedPair(" << s << ", " << x << ", " << y << ")" << std::endl;
     595                 :            : 
     596                 :            : 
     597                 :     136734 :   ++(d_statistics.d_watchedVariables);
     598                 :            : 
     599                 :     136734 :   d_watchedVariables.add(s);
     600                 :            :   // must ensure types are correct, thus, add TO_REAL if necessary here
     601                 :     273468 :   std::pair<Node, Node> p = mkSameType(x, y);
     602                 :     136734 :   Node eq = p.first.eqNode(p.second);
     603                 :     136734 :   d_watchedEqualities.set(s, eq);
     604                 :     136734 : }
     605                 :            : 
     606                 :    4365734 : void ArithCongruenceManager::assertLitToEqualityEngine(
     607                 :            :     Node lit, TNode reason, std::shared_ptr<ProofNode> pf)
     608                 :            : {
     609                 :    4365734 :   bool isEquality = lit.getKind() != Kind::NOT;
     610         [ +  + ]:    4365734 :   Node eq = isEquality ? lit : lit[0];
     611 [ -  + ][ -  + ]:    4365734 :   Assert(eq.getKind() == Kind::EQUAL);
                 [ -  - ]
     612                 :            : 
     613         [ +  - ]:    8731468 :   Trace("arith-ee") << "Assert to Eq " << lit << ", reason " << reason
     614                 :    4365734 :                     << std::endl;
     615         [ +  + ]:    4365734 :   if (isProofEnabled())
     616                 :            :   {
     617         [ +  + ]:    1816351 :     if (CDProof::isSame(lit, reason))
     618                 :            :     {
     619         [ +  - ]:     729478 :       Trace("arith-pfee") << "Asserting only, b/c implied by symm" << std::endl;
     620                 :            :       // The equality engine doesn't ref-count for us...
     621                 :     729478 :       d_keepAlive.push_back(eq);
     622                 :     729478 :       d_keepAlive.push_back(reason);
     623                 :     729478 :       d_ee->assertEquality(eq, isEquality, reason);
     624                 :            :     }
     625         [ +  + ]:    1086873 :     else if (hasProofFor(lit))
     626                 :            :     {
     627         [ +  - ]:      30356 :       Trace("arith-pfee") << "Skipping b/c already done" << std::endl;
     628                 :            :     }
     629                 :            :     else
     630                 :            :     {
     631                 :    1056517 :       setProofFor(lit, pf);
     632         [ +  - ]:    1056517 :       Trace("arith-pfee") << "Actually asserting" << std::endl;
     633         [ -  + ]:    1056517 :       if (TraceIsOn("arith-pfee"))
     634                 :            :       {
     635         [ -  - ]:          0 :         Trace("arith-pfee") << "Proof: ";
     636         [ -  - ]:          0 :         pf->printDebug(Trace("arith-pfee"));
     637         [ -  - ]:          0 :         Trace("arith-pfee") << std::endl;
     638                 :            :       }
     639                 :            :       // The proof equality engine *does* ref-count for us...
     640         [ +  - ]:    1056517 :       d_pfee->assertFact(lit, reason, d_pfGenEe.get());
     641                 :            :     }
     642                 :            :   }
     643                 :            :   else
     644                 :            :   {
     645                 :            :     // The equality engine doesn't ref-count for us...
     646                 :    2549383 :     d_keepAlive.push_back(eq);
     647                 :    2549383 :     d_keepAlive.push_back(reason);
     648                 :    2549383 :     d_ee->assertEquality(eq, isEquality, reason);
     649                 :            :   }
     650                 :    4365734 : }
     651                 :            : 
     652                 :    2715116 : void ArithCongruenceManager::assertionToEqualityEngine(
     653                 :            :     bool isEquality, ArithVar s, TNode reason, std::shared_ptr<ProofNode> pf)
     654                 :            : {
     655 [ -  + ][ -  + ]:    2715116 :   Assert(isWatchedVariable(s));
                 [ -  - ]
     656                 :            : 
     657                 :    2715116 :   TNode eq = d_watchedEqualities[s];
     658 [ -  + ][ -  + ]:    2715116 :   Assert(eq.getKind() == Kind::EQUAL);
                 [ -  - ]
     659                 :            : 
     660         [ +  + ]:    2715116 :   Node lit = isEquality ? Node(eq) : eq.notNode();
     661         [ +  - ]:    5430232 :   Trace("arith-ee") << "Assert to Eq " << eq << ", pol " << isEquality
     662                 :    2715116 :                     << ", reason " << reason << std::endl;
     663                 :    2715116 :   assertLitToEqualityEngine(lit, reason, pf);
     664                 :    2715116 : }
     665                 :            : 
     666                 :    2143390 : bool ArithCongruenceManager::hasProofFor(TNode f) const
     667                 :            : {
     668 [ -  + ][ -  + ]:    2143390 :   Assert(isProofEnabled());
                 [ -  - ]
     669         [ +  + ]:    2143390 :   if (d_pfGenEe->hasProofFor(f))
     670                 :            :   {
     671                 :      30356 :     return true;
     672                 :            :   }
     673                 :    2113034 :   Node sym = CDProof::getSymmFact(f);
     674 [ -  + ][ -  + ]:    2113034 :   Assert(!sym.isNull());
                 [ -  - ]
     675                 :    2113034 :   return d_pfGenEe->hasProofFor(sym);
     676                 :    2113034 : }
     677                 :            : 
     678                 :    1056517 : void ArithCongruenceManager::setProofFor(TNode f,
     679                 :            :                                          std::shared_ptr<ProofNode> pf) const
     680                 :            : {
     681 [ -  + ][ -  + ]:    1056517 :   Assert(!hasProofFor(f));
                 [ -  - ]
     682                 :    1056517 :   d_pfGenEe->mkTrustNode(f, pf);
     683                 :    1056517 :   Node symF = CDProof::getSymmFact(f);
     684                 :    4226068 :   auto symPf = d_pnm->mkNode(ProofRule::SYMM, {pf}, {});
     685                 :    1056517 :   d_pfGenEe->mkTrustNode(symF, symPf);
     686                 :    1056517 : }
     687                 :            : 
     688                 :    1316479 : void ArithCongruenceManager::equalsConstant(ConstraintCP c){
     689 [ -  + ][ -  + ]:    1316479 :   Assert(c->isEquality());
                 [ -  - ]
     690                 :            : 
     691                 :    1316479 :   ++(d_statistics.d_equalsConstantCalls);
     692         [ +  - ]:    1316479 :   Trace("equalsConstant") << "equals constant " << c << std::endl;
     693                 :            : 
     694                 :    1316479 :   ArithVar x = c->getVariable();
     695                 :    1316479 :   Node xAsNode = d_avariables.asNode(x);
     696                 :    1316479 :   NodeManager* nm = nodeManager();
     697                 :            :   Node asRational = nm->mkConstRealOrInt(
     698                 :    1316479 :       xAsNode.getType(), c->getValue().getNoninfinitesimalPart());
     699                 :            : 
     700                 :            :   // No guarentee this is in normal form!
     701                 :            :   // Note though, that it happens to be in proof normal form!
     702                 :    1316479 :   Node eq = xAsNode.eqNode(asRational);
     703                 :    1316479 :   d_keepAlive.push_back(eq);
     704                 :            : 
     705                 :    1316479 :   NodeBuilder nb(nodeManager(), Kind::AND);
     706                 :    1316479 :   auto pf = c->externalExplainByAssertions(nb);
     707                 :    1316479 :   Node reason = mkAndFromBuilder(nodeManager(), nb);
     708                 :    1316479 :   d_keepAlive.push_back(reason);
     709                 :            : 
     710         [ +  - ]:    1316479 :   Trace("arith-ee") << "Assert equalsConstant " << eq << ", reason " << reason << std::endl;
     711                 :    1316479 :   assertLitToEqualityEngine(eq, reason, pf);
     712                 :    1316479 : }
     713                 :            : 
     714                 :     334139 : void ArithCongruenceManager::equalsConstant(ConstraintCP lb, ConstraintCP ub){
     715 [ -  + ][ -  + ]:     334139 :   Assert(lb->isLowerBound());
                 [ -  - ]
     716 [ -  + ][ -  + ]:     334139 :   Assert(ub->isUpperBound());
                 [ -  - ]
     717 [ -  + ][ -  + ]:     334139 :   Assert(lb->getVariable() == ub->getVariable());
                 [ -  - ]
     718                 :            : 
     719                 :     334139 :   ++(d_statistics.d_equalsConstantCalls);
     720         [ +  - ]:     668278 :   Trace("equalsConstant") << "equals constant " << lb << std::endl
     721                 :     334139 :                           << ub << std::endl;
     722                 :            : 
     723                 :     334139 :   ArithVar x = lb->getVariable();
     724                 :     334139 :   NodeManager* nm = nodeManager();
     725                 :     334139 :   NodeBuilder nb(nm, Kind::AND);
     726                 :     334139 :   auto pfLb = lb->externalExplainByAssertions(nb);
     727                 :     334139 :   auto pfUb = ub->externalExplainByAssertions(nb);
     728                 :     334139 :   Node reason = mkAndFromBuilder(nodeManager(), nb);
     729                 :            : 
     730                 :     334139 :   Node xAsNode = d_avariables.asNode(x);
     731                 :            :   Node asRational = nm->mkConstRealOrInt(
     732                 :     334139 :       xAsNode.getType(), lb->getValue().getNoninfinitesimalPart());
     733                 :            : 
     734                 :            :   // No guarentee this is in normal form!
     735                 :            :   // Note though, that it happens to be in proof normal form!
     736                 :     334139 :   Node eq = xAsNode.eqNode(asRational);
     737                 :     334139 :   std::shared_ptr<ProofNode> pf;
     738         [ +  + ]:     334139 :   if (isProofEnabled())
     739                 :            :   {
     740 [ +  + ][ -  - ]:     441435 :     pf = d_pnm->mkNode(ProofRule::ARITH_TRICHOTOMY, {pfLb, pfUb}, {}, eq);
     741                 :            :   }
     742                 :     334139 :   d_keepAlive.push_back(eq);
     743                 :     334139 :   d_keepAlive.push_back(reason);
     744                 :            : 
     745         [ +  - ]:     334139 :   Trace("arith-ee") << "Assert equalsConstant2 " << eq << ", reason " << reason << std::endl;
     746                 :            : 
     747                 :     334139 :   assertLitToEqualityEngine(eq, reason, pf);
     748                 :     334139 : }
     749                 :            : 
     750                 :    9691414 : bool ArithCongruenceManager::isProofEnabled() const { return d_pnm != nullptr; }
     751                 :            : 
     752                 :            : }  // namespace arith
     753                 :            : }  // namespace theory
     754                 :            : }  // namespace cvc5::internal

Generated by: LCOV version 1.14