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

Generated by: LCOV version 1.14