LCOV - code coverage report
Current view: top level - buildbot/coverage/build/src/theory/uf - equality_engine.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1231 1388 88.7 %
Date: 2025-02-18 13:42:10 Functions: 59 63 93.7 %
Branches: 842 1330 63.3 %

           Branch data     Line data    Source code
       1                 :            : /******************************************************************************
       2                 :            :  * Top contributors (to current version):
       3                 :            :  *   Dejan Jovanovic, Andrew Reynolds, Haniel Barbosa
       4                 :            :  *
       5                 :            :  * This file is part of the cvc5 project.
       6                 :            :  *
       7                 :            :  * Copyright (c) 2009-2025 by the authors listed in the file AUTHORS
       8                 :            :  * in the top-level source directory and their institutional affiliations.
       9                 :            :  * All rights reserved.  See the file COPYING in the top-level source
      10                 :            :  * directory for licensing information.
      11                 :            :  * ****************************************************************************
      12                 :            :  * [[ Add one-line brief description here ]]
      13                 :            :  *
      14                 :            :  *
      15                 :            :  * [[ Add lengthier description here ]]
      16                 :            :  * \todo document this file
      17                 :            :  */
      18                 :            : 
      19                 :            : #include "theory/uf/equality_engine.h"
      20                 :            : 
      21                 :            : #include "base/output.h"
      22                 :            : #include "options/smt_options.h"
      23                 :            : #include "smt/env.h"
      24                 :            : #include "theory/rewriter.h"
      25                 :            : #include "theory/uf/eq_proof.h"
      26                 :            : 
      27                 :            : namespace cvc5::internal {
      28                 :            : namespace theory {
      29                 :            : namespace eq {
      30                 :            : 
      31                 :     808266 : EqualityEngine::Statistics::Statistics(StatisticsRegistry& sr,
      32                 :     808266 :                                        const std::string& name)
      33                 :     808266 :     : d_mergesCount(sr.registerInt(name + "mergesCount")),
      34                 :     808266 :       d_termsCount(sr.registerInt(name + "termsCount")),
      35                 :     808266 :       d_functionTermsCount(sr.registerInt(name + "functionTermsCount")),
      36                 :     808266 :       d_constantTermsCount(sr.registerInt(name + "constantTermsCount"))
      37                 :            : {
      38                 :     808266 : }
      39                 :            : 
      40                 :            : /**
      41                 :            :  * Data used in the BFS search through the equality graph.
      42                 :            :  */
      43                 :            : struct BfsData {
      44                 :            :   // The current node
      45                 :            :   EqualityNodeId d_nodeId;
      46                 :            :   // The index of the edge we traversed
      47                 :            :   EqualityEdgeId d_edgeId;
      48                 :            :   // Index in the queue of the previous node. Shouldn't be too much of them, at most the size
      49                 :            :   // of the biggest equivalence class
      50                 :            :   size_t d_previousIndex;
      51                 :            : 
      52                 :   36832500 :   BfsData(EqualityNodeId nodeId = null_id,
      53                 :            :           EqualityEdgeId edgeId = null_edge,
      54                 :            :           size_t prev = 0)
      55                 :   36832500 :       : d_nodeId(nodeId), d_edgeId(edgeId), d_previousIndex(prev)
      56                 :            :   {
      57                 :   36832500 :   }
      58                 :            : };
      59                 :            : 
      60                 :            : class ScopedBool {
      61                 :            :   bool& d_watch;
      62                 :            :   bool d_oldValue;
      63                 :            : 
      64                 :            :  public:
      65                 :   85152900 :   ScopedBool(bool& watch, bool newValue) : d_watch(watch), d_oldValue(watch)
      66                 :            :   {
      67                 :   85152900 :     d_watch = newValue;
      68                 :   85152900 :   }
      69                 :   85152900 :   ~ScopedBool() { d_watch = d_oldValue; }
      70                 :            : };
      71                 :            : 
      72                 :            : EqualityEngineNotifyNone EqualityEngine::s_notifyNone;
      73                 :            : 
      74                 :     808266 : void EqualityEngine::init() {
      75         [ +  - ]:     808266 :   Trace("equality") << "EqualityEdge::EqualityEngine(): id_null = " << +null_id << std::endl;
      76         [ +  - ]:     808266 :   Trace("equality") << "EqualityEdge::EqualityEngine(): edge_null = " << +null_edge << std::endl;
      77         [ +  - ]:     808266 :   Trace("equality") << "EqualityEdge::EqualityEngine(): trigger_null = " << +null_trigger << std::endl;
      78                 :            : 
      79                 :            :   // Note that we previously checked whether the context level was zero here,
      80                 :            :   // to ensure that true/false could never be removed. However, this assertion
      81                 :            :   // restricts our ability to construct equality engines in nested contexts.
      82                 :            : 
      83                 :     808266 :   d_true = nodeManager()->mkConst<bool>(true);
      84                 :     808266 :   d_false = nodeManager()->mkConst<bool>(false);
      85                 :            : 
      86                 :     808266 :   d_triggerDatabaseAllocatedSize = 100000;
      87                 :     808266 :   d_triggerDatabase = (char*) malloc(d_triggerDatabaseAllocatedSize);
      88                 :            : 
      89                 :     808266 :   addTermInternal(d_true);
      90                 :     808266 :   addTermInternal(d_false);
      91                 :            : 
      92                 :     808266 :   d_trueId = getNodeId(d_true);
      93                 :     808266 :   d_falseId = getNodeId(d_false);
      94                 :     808266 : }
      95                 :            : 
      96                 :    1506703 : EqualityEngine::~EqualityEngine() {
      97                 :     804180 :   free(d_triggerDatabase);
      98                 :    1506703 : }
      99                 :            : 
     100                 :     153027 : EqualityEngine::EqualityEngine(Env& env,
     101                 :            :                                context::Context* c,
     102                 :            :                                std::string name,
     103                 :            :                                bool constantsAreTriggers,
     104                 :     153027 :                                bool anyTermTriggers)
     105                 :            :     : ContextNotifyObj(c),
     106                 :            :       EnvObj(env),
     107                 :            :       d_masterEqualityEngine(0),
     108                 :            :       d_context(c),
     109                 :          0 :       d_done(c, false),
     110                 :            :       d_notify(&s_notifyNone),
     111                 :          0 :       d_applicationLookupsCount(c, 0),
     112                 :          0 :       d_nodesCount(c, 0),
     113                 :          0 :       d_assertedEqualitiesCount(c, 0),
     114                 :          0 :       d_equalityTriggersCount(c, 0),
     115                 :          0 :       d_subtermEvaluatesSize(c, 0),
     116                 :     153027 :       d_stats(statisticsRegistry(), name + "::"),
     117                 :            :       d_inPropagate(false),
     118                 :            :       d_constantsAreTriggers(constantsAreTriggers),
     119                 :            :       d_anyTermsAreTriggers(anyTermTriggers),
     120                 :          0 :       d_triggerDatabaseSize(c, 0),
     121                 :          0 :       d_triggerTermSetUpdatesSize(c, 0),
     122                 :          0 :       d_deducedDisequalitiesSize(c, 0),
     123                 :          0 :       d_deducedDisequalityReasonsSize(c, 0),
     124                 :            :       d_propagatedDisequalities(c),
     125                 :     306054 :       d_name(name)
     126                 :            : {
     127                 :     153027 :   init();
     128                 :     153027 : }
     129                 :            : 
     130                 :     655239 : EqualityEngine::EqualityEngine(Env& env,
     131                 :            :                                context::Context* c,
     132                 :            :                                EqualityEngineNotify& notify,
     133                 :            :                                std::string name,
     134                 :            :                                bool constantsAreTriggers,
     135                 :     655239 :                                bool anyTermTriggers)
     136                 :            :     : ContextNotifyObj(c),
     137                 :            :       EnvObj(env),
     138                 :            :       d_masterEqualityEngine(nullptr),
     139                 :            :       d_proofEqualityEngine(nullptr),
     140                 :            :       d_context(c),
     141                 :          0 :       d_done(c, false),
     142                 :            :       d_notify(&s_notifyNone),
     143                 :          0 :       d_applicationLookupsCount(c, 0),
     144                 :          0 :       d_nodesCount(c, 0),
     145                 :          0 :       d_assertedEqualitiesCount(c, 0),
     146                 :          0 :       d_equalityTriggersCount(c, 0),
     147                 :          0 :       d_subtermEvaluatesSize(c, 0),
     148                 :     655239 :       d_stats(statisticsRegistry(), name + "::"),
     149                 :            :       d_inPropagate(false),
     150                 :            :       d_constantsAreTriggers(constantsAreTriggers),
     151                 :            :       d_anyTermsAreTriggers(anyTermTriggers),
     152                 :          0 :       d_triggerDatabaseSize(c, 0),
     153                 :          0 :       d_triggerTermSetUpdatesSize(c, 0),
     154                 :          0 :       d_deducedDisequalitiesSize(c, 0),
     155                 :          0 :       d_deducedDisequalityReasonsSize(c, 0),
     156                 :            :       d_propagatedDisequalities(c),
     157                 :    1310480 :       d_name(name)
     158                 :            : {
     159                 :     655239 :   init();
     160                 :            :   // since init makes notifications (e.g. new eq class for true/false), and
     161                 :            :   // since the notify class may not be fully constructed yet, we
     162                 :            :   // don't set up the provided notification class until after initialization.
     163                 :     655239 :   d_notify = &notify;
     164                 :     655239 : }
     165                 :            : 
     166                 :     481599 : void EqualityEngine::setMasterEqualityEngine(EqualityEngine* master) {
     167 [ -  + ][ -  + ]:     481599 :   Assert(d_masterEqualityEngine == nullptr);
                 [ -  - ]
     168                 :     481599 :   d_masterEqualityEngine = master;
     169                 :     481599 : }
     170                 :            : 
     171                 :     140060 : void EqualityEngine::setProofEqualityEngine(ProofEqEngine* pfee)
     172                 :            : {
     173 [ -  + ][ -  + ]:     140060 :   Assert(d_proofEqualityEngine == nullptr);
                 [ -  - ]
     174                 :     140060 :   d_proofEqualityEngine = pfee;
     175                 :     140060 : }
     176                 :     191299 : ProofEqEngine* EqualityEngine::getProofEqualityEngine()
     177                 :            : {
     178                 :     191299 :   return d_proofEqualityEngine;
     179                 :            : }
     180                 :            : 
     181                 :  107660000 : void EqualityEngine::enqueue(const MergeCandidate& candidate, bool back) {
     182         [ +  - ]:  215320000 :   Trace("equality") << d_name << "::eq::enqueue({" << candidate.d_t1Id << "} "
     183                 :          0 :                     << d_nodes[candidate.d_t1Id] << ", {" << candidate.d_t2Id
     184                 :          0 :                     << "} " << d_nodes[candidate.d_t2Id] << ", "
     185                 :  107660000 :                     << static_cast<MergeReasonType>(candidate.d_type)
     186                 :  107660000 :                     << "). reason: " << candidate.d_reason << std::endl;
     187         [ +  - ]:  107660000 :   if (back) {
     188                 :  107660000 :     d_propagationQueue.push_back(candidate);
     189                 :            :   } else {
     190                 :          0 :     d_propagationQueue.push_front(candidate);
     191                 :            :   }
     192                 :  107660000 : }
     193                 :            : 
     194                 :    7120420 : EqualityNodeId EqualityEngine::newApplicationNode(TNode original, EqualityNodeId t1, EqualityNodeId t2, FunctionApplicationType type) {
     195         [ +  - ]:   14240800 :   Trace("equality") << d_name << "::eq::newApplicationNode(" << original
     196                 :          0 :                     << ", {" << t1 << "} " << d_nodes[t1] << ", {" << t2 << "} "
     197                 :    7120420 :                     << d_nodes[t2] << ")" << std::endl;
     198                 :            : 
     199                 :    7120420 :   ++d_stats.d_functionTermsCount;
     200                 :            : 
     201                 :            :   // Get another id for this
     202                 :    7120420 :   EqualityNodeId funId = newNode(original);
     203                 :    7120420 :   FunctionApplication funOriginal(type, t1, t2);
     204                 :            :   // The function application we're creating
     205                 :    7120420 :   EqualityNodeId t1ClassId = getEqualityNode(t1).getFind();
     206                 :    7120420 :   EqualityNodeId t2ClassId = getEqualityNode(t2).getFind();
     207                 :    7120420 :   FunctionApplication funNormalized(type, t1ClassId, t2ClassId);
     208                 :            : 
     209         [ +  - ]:   14240800 :   Trace("equality") << d_name << "::eq::newApplicationNode: funOriginal: ("
     210                 :          0 :                     << type << " " << d_nodes[t1] << " " << d_nodes[t2]
     211                 :          0 :                     << "), funNorm: (" << type << " " << d_nodes[t1ClassId]
     212                 :    7120420 :                     << " " << d_nodes[t2ClassId] << ")\n";
     213                 :            : 
     214                 :            :   // We add the original version
     215                 :    7120420 :   d_applications[funId] = FunctionApplicationPair(funOriginal, funNormalized);
     216                 :            : 
     217                 :            :   // Add the lookup data, if it's not already there
     218                 :    7120420 :   ApplicationIdsMap::iterator find = d_applicationLookup.find(funNormalized);
     219         [ +  + ]:    7120420 :   if (find == d_applicationLookup.end()) {
     220         [ +  - ]:   12740800 :     Trace("equality") << d_name << "::eq::newApplicationNode(" << original
     221                 :          0 :                       << ", " << t1 << ", " << t2
     222                 :          0 :                       << "): no lookup, setting up funNorm: (" << type << " "
     223                 :          0 :                       << d_nodes[t1ClassId] << " " << d_nodes[t2ClassId]
     224                 :    6370390 :                       << ") => " << funId << std::endl;
     225                 :            :     // Mark the normalization to the lookup
     226                 :    6370390 :     storeApplicationLookup(funNormalized, funId);
     227                 :            :   } else {
     228                 :            :     // If it's there, we need to merge these two
     229         [ +  - ]:     750028 :     Trace("equality") << d_name << "::eq::newApplicationNode(" << original << ", " << t1 << ", " << t2 << "): lookup exists, adding to queue" << std::endl;
     230         [ +  - ]:     750028 :     Trace("equality") << d_name << "::eq::newApplicationNode(" << original << ", " << t1 << ", " << t2 << "): lookup = " << d_nodes[find->second] << std::endl;
     231                 :     750028 :     enqueue(MergeCandidate(funId, find->second, MERGED_THROUGH_CONGRUENCE, TNode::null()));
     232                 :            :   }
     233                 :            : 
     234                 :            :   // Add to the use lists
     235         [ +  - ]:    7120420 :   Trace("equality") << d_name << "::eq::newApplicationNode(" << original << ", " << t1 << ", " << t2 << "): adding " << original << " to the uselist of " << d_nodes[t1] << std::endl;
     236                 :    7120420 :   d_equalityNodes[t1].usedIn(funId, d_useListNodes);
     237         [ +  - ]:    7120420 :   Trace("equality") << d_name << "::eq::newApplicationNode(" << original << ", " << t1 << ", " << t2 << "): adding " << original << " to the uselist of " << d_nodes[t2] << std::endl;
     238                 :    7120420 :   d_equalityNodes[t2].usedIn(funId, d_useListNodes);
     239                 :            : 
     240                 :            :   // Return the new id
     241         [ +  - ]:    7120420 :   Trace("equality") << d_name << "::eq::newApplicationNode(" << original << ", " << t1 << ", " << t2 << ") => " << funId << std::endl;
     242                 :            : 
     243                 :    7120420 :   return funId;
     244                 :            : }
     245                 :            : 
     246                 :   18034200 : EqualityNodeId EqualityEngine::newNode(TNode node) {
     247                 :            : 
     248         [ +  - ]:   18034200 :   Trace("equality") << d_name << "::eq::newNode(" << node << ")" << std::endl;
     249                 :            : 
     250                 :   18034200 :   ++d_stats.d_termsCount;
     251                 :            : 
     252                 :            :   // Register the new id of the term
     253                 :   18034200 :   EqualityNodeId newId = d_nodes.size();
     254                 :   18034200 :   d_nodeIds[node] = newId;
     255                 :            :   // Add the node to it's position
     256                 :   18034200 :   d_nodes.push_back(node);
     257                 :            :   // Note if this is an application or not
     258                 :   18034200 :   d_applications.push_back(FunctionApplicationPair());
     259                 :            :   // Add the trigger list for this node
     260                 :   18034200 :   d_nodeTriggers.push_back(+null_trigger);
     261                 :            :   // Add it to the equality graph
     262                 :   18034200 :   d_equalityGraph.push_back(+null_edge);
     263                 :            :   // Mark the no-individual trigger
     264                 :   18034200 :   d_nodeIndividualTrigger.push_back(+null_set_id);
     265                 :            :   // Mark non-constant by default
     266                 :   18034200 :   d_isConstant.push_back(false);
     267                 :            :   // No terms to evaluate by defaul
     268                 :   18034200 :   d_subtermsToEvaluate.push_back(0);
     269                 :            :   // Mark equality nodes
     270                 :   18034200 :   d_isEquality.push_back(false);
     271                 :            :   // Mark the node as internal by default
     272                 :   18034200 :   d_isInternal.push_back(true);
     273                 :            :   // Add the equality node to the nodes
     274                 :   18034200 :   d_equalityNodes.push_back(EqualityNode(newId));
     275                 :            : 
     276                 :            :   // Increase the counters
     277                 :   18034200 :   d_nodesCount = d_nodesCount + 1;
     278                 :            : 
     279         [ +  - ]:   18034200 :   Trace("equality") << d_name << "::eq::newNode(" << node << ") => " << newId << std::endl;
     280                 :            : 
     281                 :   18034200 :   return newId;
     282                 :            : }
     283                 :            : 
     284                 :    5975180 : void EqualityEngine::addFunctionKind(Kind fun,
     285                 :            :                                      bool interpreted,
     286                 :            :                                      bool extOperator)
     287                 :            : {
     288                 :    5975180 :   d_congruenceKinds.set(fun);
     289         [ +  - ]:    5975180 :   if (fun != Kind::EQUAL)
     290                 :            :   {
     291         [ +  + ]:    5975180 :     if (interpreted)
     292                 :            :     {
     293         [ +  - ]:    2345820 :       Trace("equality::evaluation")
     294                 :          0 :           << d_name << "::eq::addFunctionKind(): " << fun << " is interpreted "
     295                 :    1172910 :           << std::endl;
     296                 :    1172910 :       d_congruenceKindsInterpreted.set(fun);
     297                 :            :     }
     298         [ +  + ]:    5975180 :     if (extOperator)
     299                 :            :     {
     300         [ +  - ]:       4640 :       Trace("equality::extoperator")
     301                 :          0 :           << d_name << "::eq::addFunctionKind(): " << fun
     302                 :       2320 :           << " is an external operator kind " << std::endl;
     303                 :       2320 :       d_congruenceKindsExtOperators.set(fun);
     304                 :            :     }
     305                 :            :   }
     306                 :    5975180 : }
     307                 :            : 
     308                 :    1191050 : void EqualityEngine::subtermEvaluates(EqualityNodeId id)  {
     309         [ +  - ]:    1191050 :   Trace("equality::evaluation") << d_name << "::eq::subtermEvaluates(" << d_nodes[id] << "): " << d_subtermsToEvaluate[id] << std::endl;
     310 [ -  + ][ -  + ]:    1191050 :   Assert(!d_isInternal[id]);
                 [ -  - ]
     311 [ -  + ][ -  + ]:    1191050 :   Assert(d_subtermsToEvaluate[id] > 0);
                 [ -  - ]
     312         [ +  + ]:    1191050 :   if ((-- d_subtermsToEvaluate[id]) == 0) {
     313                 :     858544 :     d_evaluationQueue.push(id);
     314                 :            :   }
     315                 :    1191050 :   d_subtermEvaluates.push_back(id);
     316                 :    1191050 :   d_subtermEvaluatesSize = d_subtermEvaluates.size();
     317         [ +  - ]:    1191050 :   Trace("equality::evaluation") << d_name << "::eq::subtermEvaluates(" << d_nodes[id] << "): new " << d_subtermsToEvaluate[id] << std::endl;
     318                 :    1191050 : }
     319                 :            : 
     320                 :  174703000 : void EqualityEngine::addTermInternal(TNode t, bool isOperator) {
     321                 :            : 
     322         [ +  - ]:  174703000 :   Trace("equality") << d_name << "::eq::addTermInternal(" << t << ")" << std::endl;
     323                 :            : 
     324                 :            :   // If there already, we're done
     325         [ +  + ]:  174703000 :   if (hasTerm(t)) {
     326         [ +  - ]:  157744000 :     Trace("equality") << d_name << "::eq::addTermInternal(" << t << "): already there" << std::endl;
     327                 :  157744000 :     return;
     328                 :            :   }
     329                 :            : 
     330         [ +  + ]:   16958300 :   if (d_done) {
     331                 :         26 :     return;
     332                 :            :   }
     333                 :            : 
     334                 :            :   EqualityNodeId result;
     335                 :            : 
     336                 :   16958300 :   Kind tk = t.getKind();
     337         [ +  + ]:   16958300 :   if (tk == Kind::EQUAL)
     338                 :            :   {
     339                 :    4385330 :     addTermInternal(t[0]);
     340                 :    4385330 :     addTermInternal(t[1]);
     341                 :    4385330 :     EqualityNodeId t0id = getNodeId(t[0]);
     342                 :    4385330 :     EqualityNodeId t1id = getNodeId(t[1]);
     343                 :    4385330 :     result = newApplicationNode(t, t0id, t1id, APP_EQUALITY);
     344                 :    4385330 :     d_isInternal[result] = false;
     345                 :    4385330 :     d_isConstant[result] = false;
     346                 :            :   }
     347 [ +  + ][ +  + ]:   12572900 :   else if (t.getNumChildren() > 0 && d_congruenceKinds[tk])
                 [ +  + ]
     348                 :            :   {
     349                 :    3318370 :     TNode tOp = t.getOperator();
     350                 :            :     // Add the operator
     351                 :    1659180 :     addTermInternal(tOp, !isExternalOperatorKind(tk));
     352                 :    1659180 :     result = getNodeId(tOp);
     353                 :            :     // Add all the children and Curryfy
     354                 :    1659180 :     bool isInterpreted = isInterpretedFunctionKind(tk);
     355         [ +  + ]:    4394270 :     for (unsigned i = 0; i < t.getNumChildren(); ++ i) {
     356                 :            :       // Add the child
     357                 :    2735080 :       addTermInternal(t[i]);
     358                 :    2735080 :       EqualityNodeId tiId = getNodeId(t[i]);
     359                 :            :       // Add the application
     360         [ +  + ]:    2735080 :       result = newApplicationNode(t, result, tiId, isInterpreted ? APP_INTERPRETED : APP_UNINTERPRETED);
     361                 :            :     }
     362                 :    1659180 :     d_isInternal[result] = false;
     363                 :    1659180 :     d_isConstant[result] = t.isConst();
     364                 :            :     // If interpreted, set the number of non-interpreted children
     365         [ +  + ]:    1659180 :     if (isInterpreted) {
     366                 :            :       // How many children are not constants yet
     367                 :     132832 :       d_subtermsToEvaluate[result] = t.getNumChildren();
     368         [ +  + ]:     335043 :       for (unsigned i = 0; i < t.getNumChildren(); ++ i) {
     369         [ +  + ]:     202211 :         if (isConstant(getNodeId(t[i]))) {
     370 [ +  - ][ -  + ]:      33150 :           Trace("equality::evaluation") << d_name << "::eq::addTermInternal(" << t << "): evaluates " << t[i] << std::endl;
                 [ -  - ]
     371                 :      33150 :           subtermEvaluates(result);
     372                 :            :         }
     373                 :            :       }
     374                 :            :     }
     375                 :            :   }
     376                 :            :   else
     377                 :            :   {
     378                 :            :     // Otherwise we just create the new id
     379                 :   10913800 :     result = newNode(t);
     380                 :            :     // Is this an operator
     381                 :   10913800 :     d_isInternal[result] = isOperator;
     382 [ +  + ][ +  + ]:   10913800 :     d_isConstant[result] = !isOperator && t.isConst();
     383                 :            :   }
     384                 :            : 
     385         [ +  + ]:   16958300 :   if (tk == Kind::EQUAL)
     386                 :            :   {
     387                 :            :     // We set this here as this only applies to actual terms, not the
     388                 :            :     // intermediate application terms
     389                 :    4385330 :     d_isEquality[result] = true;
     390                 :            :   }
     391                 :            :   else
     392                 :            :   {
     393                 :            :     // Notify e.g. the theory that owns this equality engine that there is a
     394                 :            :     // new equivalence class.
     395                 :   12572900 :     d_notify->eqNotifyNewClass(t);
     396 [ +  + ][ +  + ]:   12572900 :     if (d_constantsAreTriggers && d_isConstant[result])
                 [ +  + ]
     397                 :            :     {
     398                 :            :       // Non-Boolean constants are trigger terms for all tags
     399                 :    2033140 :       EqualityNodeId tId = getNodeId(t);
     400                 :            :       // Setup the new set
     401                 :    2033140 :       TheoryIdSet newSetTags = 0;
     402                 :            :       EqualityNodeId newSetTriggers[THEORY_LAST];
     403                 :    2033140 :       unsigned newSetTriggersSize = THEORY_LAST;
     404         [ +  + ]:   30497000 :       for (TheoryId currentTheory = THEORY_FIRST; currentTheory != THEORY_LAST;
     405                 :   28463900 :            ++currentTheory)
     406                 :            :       {
     407                 :   28463900 :         newSetTags = TheoryIdSetUtil::setInsert(currentTheory, newSetTags);
     408                 :   28463900 :         newSetTriggers[currentTheory] = tId;
     409                 :            :       }
     410                 :            :       // Add it to the list for backtracking
     411                 :    2033140 :       d_triggerTermSetUpdates.push_back(TriggerSetUpdate(tId, null_set_id));
     412                 :    2033140 :       d_triggerTermSetUpdatesSize = d_triggerTermSetUpdatesSize + 1;
     413                 :            :       // Mark the the new set as a trigger
     414                 :    2033140 :       d_nodeIndividualTrigger[tId] =
     415                 :    2033140 :           newTriggerTermSet(newSetTags, newSetTriggers, newSetTriggersSize);
     416                 :            :     }
     417                 :            :   }
     418                 :            : 
     419                 :            :   // If this is not an internal node, add it to the master
     420 [ +  + ][ +  + ]:   16958300 :   if (d_masterEqualityEngine && !d_isInternal[result]) {
                 [ +  + ]
     421                 :    4228290 :     d_masterEqualityEngine->addTermInternal(t);
     422                 :            :   }
     423                 :            : 
     424                 :            :   // Empty the queue
     425                 :   16958300 :   propagate();
     426                 :            : 
     427 [ -  + ][ -  + ]:   16958300 :   Assert(hasTerm(t));
                 [ -  - ]
     428                 :            : 
     429         [ +  - ]:   16958300 :   Trace("equality") << d_name << "::eq::addTermInternal(" << t << ") => " << result << std::endl;
     430                 :            : }
     431                 :            : 
     432                 : 3176730000 : bool EqualityEngine::hasTerm(TNode t) const {
     433                 : 3176730000 :   return d_nodeIds.find(t) != d_nodeIds.end();
     434                 :            : }
     435                 :            : 
     436                 : 1082620000 : EqualityNodeId EqualityEngine::getNodeId(TNode node) const {
     437                 : 1082620000 :   Assert(hasTerm(node)) << node;
     438                 : 1082620000 :   return (*d_nodeIds.find(node)).second;
     439                 :            : }
     440                 :            : 
     441                 :  206343000 : EqualityNode& EqualityEngine::getEqualityNode(TNode t) {
     442                 :  206343000 :   return getEqualityNode(getNodeId(t));
     443                 :            : }
     444                 :            : 
     445                 : 1334430000 : EqualityNode& EqualityEngine::getEqualityNode(EqualityNodeId nodeId) {
     446 [ -  + ][ -  + ]: 1334430000 :   Assert(nodeId < d_equalityNodes.size());
                 [ -  - ]
     447                 : 1334430000 :   return d_equalityNodes[nodeId];
     448                 :            : }
     449                 :            : 
     450                 :  589922000 : const EqualityNode& EqualityEngine::getEqualityNode(TNode t) const {
     451                 :  589922000 :   return getEqualityNode(getNodeId(t));
     452                 :            : }
     453                 :            : 
     454                 :  983848000 : const EqualityNode& EqualityEngine::getEqualityNode(EqualityNodeId nodeId) const {
     455 [ -  + ][ -  + ]:  983848000 :   Assert(nodeId < d_equalityNodes.size());
                 [ -  - ]
     456                 :  983848000 :   return d_equalityNodes[nodeId];
     457                 :            : }
     458                 :            : 
     459                 :   68240800 : void EqualityEngine::assertEqualityInternal(TNode t1, TNode t2, TNode reason, unsigned pid) {
     460         [ +  - ]:  136482000 :   Trace("equality") << d_name << "::eq::addEqualityInternal(" << t1 << "," << t2
     461                 :          0 :                     << "), reason = " << reason
     462                 :   68240800 :                     << ", pid = " << static_cast<MergeReasonType>(pid)
     463                 :   68240800 :                     << std::endl;
     464                 :            : 
     465         [ +  + ]:   68240800 :   if (d_done) {
     466                 :        243 :     return;
     467                 :            :   }
     468                 :            : 
     469                 :            :   // Add the terms if they are not already in the database
     470                 :   68240600 :   addTermInternal(t1);
     471                 :   68240600 :   addTermInternal(t2);
     472                 :            : 
     473                 :            :   // Add to the queue and propagate
     474                 :   68240600 :   EqualityNodeId t1Id = getNodeId(t1);
     475                 :   68240600 :   EqualityNodeId t2Id = getNodeId(t2);
     476                 :   68240600 :   enqueue(MergeCandidate(t1Id, t2Id, pid, reason));
     477                 :            : }
     478                 :            : 
     479                 :   36665600 : bool EqualityEngine::assertPredicate(TNode t,
     480                 :            :                                      bool polarity,
     481                 :            :                                      TNode reason,
     482                 :            :                                      unsigned pid)
     483                 :            : {
     484 [ +  - ][ -  - ]:   36665600 :   Trace("equality") << d_name << "::eq::addPredicate(" << t << "," << (polarity ? "true" : "false") << ")" << std::endl;
     485 [ -  + ][ -  + ]:   36665600 :   Assert(t.getKind() != Kind::EQUAL) << "Use assertEquality instead";
                 [ -  - ]
     486         [ +  + ]:   73331100 :   TNode b = polarity ? d_true : d_false;
     487                 :   36665600 :   if (hasTerm(t) && areEqual(t, b))
     488                 :            :   {
     489                 :    2173850 :     return false;
     490                 :            :   }
     491                 :   34491700 :   assertEqualityInternal(t, b, reason, pid);
     492                 :   34491700 :   propagate();
     493                 :   34491700 :   return true;
     494                 :            : }
     495                 :            : 
     496                 :   31465300 : bool EqualityEngine::assertEquality(TNode eq,
     497                 :            :                                     bool polarity,
     498                 :            :                                     TNode reason,
     499                 :            :                                     unsigned pid)
     500                 :            : {
     501 [ +  - ][ -  - ]:   31465300 :   Trace("equality") << d_name << "::eq::addEquality(" << eq << "," << (polarity ? "true" : "false") << ")" << std::endl;
     502         [ +  + ]:   31465300 :   if (polarity) {
     503                 :            :     // If two terms are already equal, don't assert anything
     504                 :   17711500 :     if (hasTerm(eq[0]) && hasTerm(eq[1]) && areEqual(eq[0], eq[1])) {
     505                 :    4743050 :       return false;
     506                 :            :     }
     507                 :            :     // Add equality between terms
     508                 :   12968500 :     assertEqualityInternal(eq[0], eq[1], reason, pid);
     509                 :   12968500 :     propagate();
     510                 :            :   } else {
     511                 :            :     // If two terms are already dis-equal, don't assert anything
     512                 :   13753800 :     if (hasTerm(eq[0]) && hasTerm(eq[1]) && areDisequal(eq[0], eq[1], false)) {
     513                 :    7509510 :       return false;
     514                 :            :     }
     515                 :            : 
     516                 :            :     // notify the theory
     517                 :    6247040 :     d_notify->eqNotifyDisequal(eq[0], eq[1], reason);
     518                 :            : 
     519 [ +  - ][ -  - ]:    6247040 :     Trace("equality::trigger") << d_name << "::eq::addEquality(" << eq << "," << (polarity ? "true" : "false") << ")" << std::endl;
     520                 :            : 
     521                 :    6247040 :     assertEqualityInternal(eq, d_false, reason, pid);
     522                 :    6247040 :     propagate();
     523                 :            : 
     524         [ +  + ]:    6247040 :     if (d_done) {
     525                 :       1871 :       return true;
     526                 :            :     }
     527                 :            : 
     528                 :            :     // If both have constant representatives, we don't notify anyone
     529                 :    6245170 :     EqualityNodeId a = getNodeId(eq[0]);
     530                 :    6245170 :     EqualityNodeId b = getNodeId(eq[1]);
     531                 :    6245170 :     EqualityNodeId aClassId = getEqualityNode(a).getFind();
     532                 :    6245170 :     EqualityNodeId bClassId = getEqualityNode(b).getFind();
     533 [ +  + ][ +  + ]:    6245170 :     if (d_isConstant[aClassId] && d_isConstant[bClassId]) {
                 [ +  + ]
     534                 :        884 :       return true;
     535                 :            :     }
     536                 :            : 
     537                 :            :     // If we are adding a disequality, notify of the shared term representatives
     538                 :    6244280 :     EqualityNodeId eqId = getNodeId(eq);
     539                 :    6244280 :     TriggerTermSetRef aTriggerRef = d_nodeIndividualTrigger[aClassId];
     540                 :    6244280 :     TriggerTermSetRef bTriggerRef = d_nodeIndividualTrigger[bClassId];
     541 [ +  + ][ +  + ]:    6244280 :     if (aTriggerRef != +null_set_id && bTriggerRef != +null_set_id) {
     542 [ +  - ][ -  - ]:    2771460 :       Trace("equality::trigger") << d_name << "::eq::addEquality(" << eq << "," << (polarity ? "true" : "false") << ": have triggers" << std::endl;
     543                 :            :       // The sets of trigger terms
     544                 :    2771460 :       TriggerTermSet& aTriggerTerms = getTriggerTermSet(aTriggerRef);
     545                 :    2771460 :       TriggerTermSet& bTriggerTerms = getTriggerTermSet(bTriggerRef);
     546                 :            :       // Go through and notify the shared dis-equalities
     547                 :    2771460 :       TheoryIdSet aTags = aTriggerTerms.d_tags;
     548                 :    2771460 :       TheoryIdSet bTags = bTriggerTerms.d_tags;
     549                 :    2771460 :       TheoryId aTag = TheoryIdSetUtil::setPop(aTags);
     550                 :    2771460 :       TheoryId bTag = TheoryIdSetUtil::setPop(bTags);
     551                 :    2771460 :       int a_i = 0, b_i = 0;
     552 [ +  + ][ +  + ]:   16953800 :       while (aTag != THEORY_LAST && bTag != THEORY_LAST) {
     553         [ +  + ]:   14182500 :         if (aTag < bTag) {
     554                 :    5764160 :           aTag = TheoryIdSetUtil::setPop(aTags);
     555                 :    5764160 :           ++ a_i;
     556         [ +  + ]:    8418310 :         } else if (aTag > bTag) {
     557                 :    4485180 :           bTag = TheoryIdSetUtil::setPop(bTags);
     558                 :    4485180 :           ++ b_i;
     559                 :            :         } else {
     560                 :            :           // Same tags, notify
     561                 :    3933130 :           EqualityNodeId aSharedId = aTriggerTerms.d_triggers[a_i++];
     562                 :    3933130 :           EqualityNodeId bSharedId = bTriggerTerms.d_triggers[b_i++];
     563                 :            :           // Propagate
     564         [ +  - ]:    3933130 :           if (!hasPropagatedDisequality(aTag, aSharedId, bSharedId)) {
     565                 :            :             // Store a proof if not there already
     566         [ +  + ]:    3933130 :             if (!hasPropagatedDisequality(aSharedId, bSharedId)) {
     567                 :    1848900 :               d_deducedDisequalityReasons.push_back(EqualityPair(aSharedId, a));
     568                 :    1848900 :               d_deducedDisequalityReasons.push_back(EqualityPair(bSharedId, b));
     569                 :    1848900 :               d_deducedDisequalityReasons.push_back(EqualityPair(eqId, d_falseId));
     570                 :            :             }
     571                 :            :             // Store the propagation
     572                 :    3933130 :             storePropagatedDisequality(aTag, aSharedId, bSharedId);
     573                 :            :             // Notify
     574 [ +  - ][ -  - ]:    3933130 :             Trace("equality::trigger") << d_name << "::eq::addEquality(" << eq << "," << (polarity ? "true" : "false") << ": notifying " << aTag << " for " << d_nodes[aSharedId] << " != " << d_nodes[bSharedId] << std::endl;
     575         [ +  + ]:    7866260 :             if (!notifyTriggerTermEquality(
     576                 :    7866260 :                     aTag, d_nodes[aSharedId], d_nodes[bSharedId], false))
     577                 :            :             {
     578                 :        110 :               break;
     579                 :            :             }
     580                 :            :           }
     581                 :            :           // Pop the next tags
     582                 :    3933020 :           aTag = TheoryIdSetUtil::setPop(aTags);
     583                 :    3933020 :           bTag = TheoryIdSetUtil::setPop(bTags);
     584                 :            :         }
     585                 :            :       }
     586                 :            :     }
     587                 :            :   }
     588                 :   19212800 :   return true;
     589                 :            : }
     590                 :            : 
     591                 :  413575000 : TNode EqualityEngine::getRepresentative(TNode t) const {
     592         [ +  - ]:  413575000 :   Trace("equality::internal") << d_name << "::eq::getRepresentative(" << t << ")" << std::endl;
     593 [ -  + ][ -  + ]:  413575000 :   Assert(hasTerm(t));
                 [ -  - ]
     594                 :  413575000 :   EqualityNodeId representativeId = getEqualityNode(t).getFind();
     595 [ -  + ][ -  + ]:  413575000 :   Assert(!d_isInternal[representativeId]);
                 [ -  - ]
     596         [ +  - ]:  413575000 :   Trace("equality::internal") << d_name << "::eq::getRepresentative(" << t << ") => " << d_nodes[representativeId] << std::endl;
     597                 :  413575000 :   return d_nodes[representativeId];
     598                 :            : }
     599                 :            : 
     600                 :   88535300 : bool EqualityEngine::merge(EqualityNode& class1, EqualityNode& class2, std::vector<TriggerId>& triggersFired) {
     601                 :            : 
     602         [ +  - ]:   88535300 :   Trace("equality") << d_name << "::eq::merge(" << class1.getFind() << "," << class2.getFind() << ")" << std::endl;
     603                 :            : 
     604 [ -  + ][ -  + ]:   88535300 :   Assert(triggersFired.empty());
                 [ -  - ]
     605                 :            : 
     606                 :   88535300 :   ++d_stats.d_mergesCount;
     607                 :            : 
     608                 :   88535300 :   EqualityNodeId class1Id = class1.getFind();
     609                 :   88535300 :   EqualityNodeId class2Id = class2.getFind();
     610                 :            : 
     611                 :  177071000 :   Node n1 = d_nodes[class1Id];
     612                 :  177071000 :   Node n2 = d_nodes[class2Id];
     613                 :   88535300 :   EqualityNode cc1 = getEqualityNode(n1);
     614                 :   88535300 :   EqualityNode cc2 = getEqualityNode(n2);
     615                 :   88535300 :   bool doNotify = false;
     616                 :            :   // Determine if we should notify the owner of this class of this merge.
     617                 :            :   // The second part of this check is needed due to the internal implementation
     618                 :            :   // of this class. It ensures that we are merging terms and not operators.
     619 [ +  + ][ +  + ]:   88535300 :   if (class1Id == cc1.getFind() && class2Id == cc2.getFind())
                 [ +  + ]
     620                 :            :   {
     621                 :   85423100 :     doNotify = true;
     622                 :            :   }
     623                 :            : 
     624                 :            :   // Check for constant merges
     625                 :   88535300 :   bool class1isConstant = d_isConstant[class1Id];
     626                 :   88535300 :   bool class2isConstant = d_isConstant[class2Id];
     627 [ +  + ][ -  + ]:   88535300 :   Assert(class1isConstant || !class2isConstant)
         [ -  + ][ -  - ]
     628                 :          0 :       << "Should always merge into constants";
     629 [ +  + ][ -  + ]:   88535300 :   Assert(!class1isConstant || !class2isConstant) << "Don't merge constants";
         [ -  + ][ -  - ]
     630                 :            : 
     631                 :            :   // Trigger set of class 1
     632                 :   88535300 :   TriggerTermSetRef class1triggerRef = d_nodeIndividualTrigger[class1Id];
     633                 :            :   TheoryIdSet class1Tags = class1triggerRef == null_set_id
     634         [ +  + ]:   88535300 :                                ? 0
     635                 :   64773800 :                                : getTriggerTermSet(class1triggerRef).d_tags;
     636                 :            :   // Trigger set of class 2
     637                 :   88535300 :   TriggerTermSetRef class2triggerRef = d_nodeIndividualTrigger[class2Id];
     638                 :            :   TheoryIdSet class2Tags = class2triggerRef == null_set_id
     639         [ +  + ]:   88535300 :                                ? 0
     640                 :    6444250 :                                : getTriggerTermSet(class2triggerRef).d_tags;
     641                 :            : 
     642                 :            :   // Disequalities coming from class2
     643                 :  177071000 :   TaggedEqualitiesSet class2disequalitiesToNotify;
     644                 :            :   // Disequalities coming from class1
     645                 :  177071000 :   TaggedEqualitiesSet class1disequalitiesToNotify;
     646                 :            : 
     647                 :            :   // Individual tags
     648                 :            :   TheoryIdSet class1OnlyTags =
     649                 :   88535300 :       TheoryIdSetUtil::setDifference(class1Tags, class2Tags);
     650                 :            :   TheoryIdSet class2OnlyTags =
     651                 :   88535300 :       TheoryIdSetUtil::setDifference(class2Tags, class1Tags);
     652                 :            : 
     653                 :            :   // Only get disequalities if they are not both constant
     654 [ +  + ][ +  - ]:   88535300 :   if (!class1isConstant || !class2isConstant) {
     655                 :   88535300 :     getDisequalities(!class1isConstant, class2Id, class1OnlyTags, class2disequalitiesToNotify);
     656                 :   88535300 :     getDisequalities(!class2isConstant, class1Id, class2OnlyTags, class1disequalitiesToNotify);
     657                 :            :   }
     658                 :            : 
     659                 :            :   // Update class2 representative information
     660         [ +  - ]:   88535300 :   Trace("equality") << d_name << "::eq::merge(" << class1.getFind() << "," << class2.getFind() << "): updating class " << class2Id << std::endl;
     661                 :   88535300 :   EqualityNodeId currentId = class2Id;
     662                 :   14034000 :   do {
     663                 :            :     // Get the current node
     664                 :  102569000 :     EqualityNode& currentNode = getEqualityNode(currentId);
     665                 :            : 
     666                 :            :     // Update it's find to class1 id
     667         [ +  - ]:  102569000 :     Trace("equality") << d_name << "::eq::merge(" << class1.getFind() << "," << class2.getFind() << "): " << currentId << "->" << class1Id << std::endl;
     668                 :  102569000 :     currentNode.setFind(class1Id);
     669                 :            : 
     670                 :            :     // Go through the triggers and inform if necessary
     671                 :  102569000 :     TriggerId currentTrigger = d_nodeTriggers[currentId];
     672         [ +  + ]:  175894000 :     while (currentTrigger != null_trigger) {
     673                 :   73324800 :       Trigger& trigger = d_equalityTriggers[currentTrigger];
     674                 :   73324800 :       Trigger& otherTrigger = d_equalityTriggers[currentTrigger ^ 1];
     675                 :            : 
     676                 :            :       // If the two are not already in the same class
     677         [ +  + ]:   73324800 :       if (otherTrigger.d_classId != trigger.d_classId)
     678                 :            :       {
     679                 :   64135600 :         trigger.d_classId = class1Id;
     680                 :            :         // If they became the same, call the trigger
     681         [ +  + ]:   64135600 :         if (otherTrigger.d_classId == class1Id)
     682                 :            :         {
     683                 :            :           // Id of the real trigger is half the internal one
     684                 :   23258100 :           triggersFired.push_back(currentTrigger);
     685                 :            :         }
     686                 :            :       }
     687                 :            : 
     688                 :            :       // Go to the next trigger
     689                 :   73324800 :       currentTrigger = trigger.d_nextTrigger;
     690                 :            :     }
     691                 :            : 
     692                 :            :     // Move to the next node
     693                 :  102569000 :     currentId = currentNode.getNext();
     694                 :            : 
     695         [ +  + ]:  102569000 :   } while (currentId != class2Id);
     696                 :            : 
     697                 :            :   // Update class2 table lookup and information if not a boolean
     698                 :            :   // since booleans can't be in an application
     699         [ +  + ]:   88535300 :   if (!d_isEquality[class2Id]) {
     700         [ +  - ]:   64072000 :     Trace("equality") << d_name << "::eq::merge(" << class1.getFind() << "," << class2.getFind() << "): updating lookups of " << class2Id << std::endl;
     701                 :   11204800 :     do {
     702                 :            :       // Get the current node
     703                 :   75276800 :       EqualityNode& currentNode = getEqualityNode(currentId);
     704         [ +  - ]:   75276800 :       Trace("equality") << d_name << "::eq::merge(" << class1.getFind() << "," << class2.getFind() << "): updating lookups of node " << currentId << std::endl;
     705                 :            : 
     706                 :            :       // Go through the uselist and check for congruences
     707                 :   75276800 :       UseListNodeId currentUseId = currentNode.getUseList();
     708         [ +  + ]:  153238000 :       while (currentUseId != null_uselist_id) {
     709                 :            :         // Get the node of the use list
     710                 :   77960900 :         UseListNode& useNode = d_useListNodes[currentUseId];
     711                 :            :         // Get the function application
     712                 :   77960900 :         EqualityNodeId funId = useNode.getApplicationId();
     713         [ +  - ]:   77960900 :         Trace("equality") << d_name << "::eq::merge(" << class1.getFind() << "," << class2.getFind() << "): " << d_nodes[currentId] << " in " << d_nodes[funId] << std::endl;
     714                 :            :         const FunctionApplication& fun =
     715                 :   77960900 :             d_applications[useNode.getApplicationId()].d_normalized;
     716                 :            :         // If it's interpreted and we can interpret
     717 [ +  + ][ +  + ]:   77960900 :         if (fun.isInterpreted() && class1isConstant && !d_isInternal[currentId])
         [ +  + ][ +  + ]
     718                 :            :         {
     719                 :            :           // Get the actual term id
     720                 :    1157900 :           TNode term = d_nodes[funId];
     721                 :    1157900 :           subtermEvaluates(getNodeId(term));
     722                 :            :         }
     723                 :            :         // Check if there is an application with find arguments
     724                 :   77960900 :         EqualityNodeId aNormalized = getEqualityNode(fun.d_a).getFind();
     725                 :   77960900 :         EqualityNodeId bNormalized = getEqualityNode(fun.d_b).getFind();
     726                 :   77960900 :         FunctionApplication funNormalized(fun.d_type, aNormalized, bNormalized);
     727                 :   77960900 :         ApplicationIdsMap::iterator find = d_applicationLookup.find(funNormalized);
     728         [ +  + ]:   77960900 :         if (find != d_applicationLookup.end()) {
     729                 :            :           // Applications fun and the funNormalized can be merged due to congruence
     730         [ +  + ]:   55453900 :           if (getEqualityNode(funId).getFind() != getEqualityNode(find->second).getFind()) {
     731                 :   33821200 :             enqueue(MergeCandidate(funId, find->second, MERGED_THROUGH_CONGRUENCE, TNode::null()));
     732                 :            :           }
     733                 :            :         } else {
     734                 :            :           // There is no representative, so we can add one, we remove this when backtracking
     735                 :   22507100 :           storeApplicationLookup(funNormalized, funId);
     736                 :            :         }
     737                 :            : 
     738                 :            :         // Go to the next one in the use list
     739                 :   77960900 :         currentUseId = useNode.getNext();
     740                 :            :       }
     741                 :            : 
     742                 :            :       // Move to the next node
     743                 :   75276800 :       currentId = currentNode.getNext();
     744         [ +  + ]:   75276800 :     } while (currentId != class2Id);
     745                 :            :   }
     746                 :            : 
     747                 :            :   // Now merge the lists
     748                 :   88535300 :   class1.merge<true>(class2);
     749                 :            : 
     750                 :            :   // notify the theory
     751         [ +  + ]:   88535300 :   if (doNotify) {
     752                 :   85423100 :     d_notify->eqNotifyMerge(n1, n2);
     753                 :            :   }
     754                 :            : 
     755                 :            :   // Go through the trigger term disequalities and propagate
     756         [ +  + ]:   88535300 :   if (!propagateTriggerTermDisequalities(class1OnlyTags, class1triggerRef, class2disequalitiesToNotify)) {
     757                 :         26 :     return false;
     758                 :            :   }
     759         [ +  + ]:   88535300 :   if (!propagateTriggerTermDisequalities(class2OnlyTags, class2triggerRef, class1disequalitiesToNotify)) {
     760                 :         22 :     return false;
     761                 :            :   }
     762                 :            : 
     763                 :            :   // Notify the trigger term merges
     764         [ +  + ]:   88535300 :   if (class2triggerRef != +null_set_id) {
     765         [ +  + ]:    6444220 :     if (class1triggerRef == +null_set_id) {
     766                 :            :       // If class1 doesn't have individual triggers, but class2 does, mark it
     767                 :     285638 :       d_nodeIndividualTrigger[class1Id] = class2triggerRef;
     768                 :            :       // Add it to the list for backtracking
     769                 :     285638 :       d_triggerTermSetUpdates.push_back(TriggerSetUpdate(class1Id, +null_set_id));
     770                 :     285638 :       d_triggerTermSetUpdatesSize = d_triggerTermSetUpdatesSize + 1;
     771                 :            :     } else {
     772                 :            :       // Get the triggers
     773                 :    6158590 :       TriggerTermSet& class1triggers = getTriggerTermSet(class1triggerRef);
     774                 :    6158590 :       TriggerTermSet& class2triggers = getTriggerTermSet(class2triggerRef);
     775                 :            : 
     776                 :            :       // Initialize the merged set
     777                 :    6158590 :       TheoryIdSet newSetTags = TheoryIdSetUtil::setUnion(class1triggers.d_tags,
     778                 :            :                                                          class2triggers.d_tags);
     779                 :            :       EqualityNodeId newSetTriggers[THEORY_LAST];
     780                 :    6158590 :       unsigned newSetTriggersSize = 0;
     781                 :            : 
     782                 :    6158590 :       int i1 = 0;
     783                 :    6158590 :       int i2 = 0;
     784                 :    6158590 :       TheoryIdSet tags1 = class1triggers.d_tags;
     785                 :    6158590 :       TheoryIdSet tags2 = class2triggers.d_tags;
     786                 :    6158590 :       TheoryId tag1 = TheoryIdSetUtil::setPop(tags1);
     787                 :    6158590 :       TheoryId tag2 = TheoryIdSetUtil::setPop(tags2);
     788                 :            : 
     789                 :            :       // Comparing the THEORY_LAST is OK because all other theories are
     790                 :            :       // smaller, and will therefore be preferred
     791 [ +  + ][ +  + ]:   60425800 :       while (tag1 != THEORY_LAST || tag2 != THEORY_LAST)
     792                 :            :       {
     793         [ +  + ]:   54296700 :         if (tag1 < tag2) {
     794                 :            :           // copy tag1
     795                 :   46161900 :           newSetTriggers[newSetTriggersSize++] =
     796                 :   46161900 :               class1triggers.d_triggers[i1++];
     797                 :   46161900 :           tag1 = TheoryIdSetUtil::setPop(tags1);
     798         [ +  + ]:    8134770 :         } else if (tag1 > tag2) {
     799                 :            :           // copy tag2
     800                 :       5743 :           newSetTriggers[newSetTriggersSize++] =
     801                 :       5743 :               class2triggers.d_triggers[i2++];
     802                 :       5743 :           tag2 = TheoryIdSetUtil::setPop(tags2);
     803                 :            :         } else {
     804                 :            :           // copy tag1
     805                 :    8129030 :           EqualityNodeId tag1id = newSetTriggers[newSetTriggersSize++] =
     806                 :    8129030 :               class1triggers.d_triggers[i1++];
     807                 :            :           // since they are both tagged notify of merge
     808                 :    8129030 :           EqualityNodeId tag2id = class2triggers.d_triggers[i2++];
     809         [ +  + ]:   16258100 :           if (!notifyTriggerTermEquality(
     810                 :   16258100 :                   tag1, d_nodes[tag1id], d_nodes[tag2id], true))
     811                 :            :           {
     812                 :      29485 :             return false;
     813                 :            :           }
     814                 :            :           // Next tags
     815                 :    8099540 :           tag1 = TheoryIdSetUtil::setPop(tags1);
     816                 :    8099540 :           tag2 = TheoryIdSetUtil::setPop(tags2);
     817                 :            :         }
     818                 :            :       }
     819                 :            : 
     820                 :            :       // Add the new trigger set, if different from previous one
     821         [ +  + ]:    6129100 :       if (class1triggers.d_tags != class2triggers.d_tags)
     822                 :            :       {
     823                 :            :         // Add it to the list for backtracking
     824                 :    3651800 :         d_triggerTermSetUpdates.push_back(TriggerSetUpdate(class1Id, class1triggerRef));
     825                 :    3651800 :         d_triggerTermSetUpdatesSize = d_triggerTermSetUpdatesSize + 1;
     826                 :            :         // Mark the the new set as a trigger
     827                 :    3651800 :         d_nodeIndividualTrigger[class1Id] = newTriggerTermSet(newSetTags, newSetTriggers, newSetTriggersSize);
     828                 :            :       }
     829                 :            :     }
     830                 :            :   }
     831                 :            : 
     832                 :            :   // Everything fine
     833                 :   88505800 :   return true;
     834                 :            : }
     835                 :            : 
     836                 :   88534100 : void EqualityEngine::undoMerge(EqualityNode& class1, EqualityNode& class2, EqualityNodeId class2Id) {
     837                 :            : 
     838         [ +  - ]:   88534100 :   Trace("equality") << d_name << "::eq::undoMerge(" << class1.getFind() << "," << class2Id << ")" << std::endl;
     839                 :            : 
     840                 :            :   // Now unmerge the lists (same as merge)
     841                 :   88534100 :   class1.merge<false>(class2);
     842                 :            : 
     843                 :            :   // Update class2 representative information
     844                 :   88534100 :   EqualityNodeId currentId = class2Id;
     845         [ +  - ]:   88534100 :   Trace("equality") << d_name << "::eq::undoMerge(" << class1.getFind() << "," << class2Id << "): undoing representative info" << std::endl;
     846                 :   14034000 :   do {
     847                 :            :     // Get the current node
     848                 :  102568000 :     EqualityNode& currentNode = getEqualityNode(currentId);
     849                 :            : 
     850                 :            :     // Update it's find to class1 id
     851                 :  102568000 :     currentNode.setFind(class2Id);
     852                 :            : 
     853                 :            :     // Go through the trigger list (if any) and undo the class
     854                 :  102568000 :     TriggerId currentTrigger = d_nodeTriggers[currentId];
     855         [ +  + ]:  175892000 :     while (currentTrigger != null_trigger) {
     856                 :   73324200 :       Trigger& trigger = d_equalityTriggers[currentTrigger];
     857                 :   73324200 :       trigger.d_classId = class2Id;
     858                 :   73324200 :       currentTrigger = trigger.d_nextTrigger;
     859                 :            :     }
     860                 :            : 
     861                 :            :     // Move to the next node
     862                 :  102568000 :     currentId = currentNode.getNext();
     863                 :            : 
     864         [ +  + ]:  102568000 :   } while (currentId != class2Id);
     865                 :            : 
     866                 :   88534100 : }
     867                 :            : 
     868                 :  186646000 : void EqualityEngine::backtrack() {
     869                 :            : 
     870         [ +  - ]:  186646000 :   Trace("equality::backtrack") << "backtracking" << std::endl;
     871                 :            : 
     872                 :            :   // If we need to backtrack then do it
     873         [ +  + ]:  186646000 :   if (d_assertedEqualitiesCount < d_assertedEqualities.size()) {
     874                 :            : 
     875                 :            :     // Clear the propagation queue
     876         [ +  + ]:   15760600 :     while (!d_propagationQueue.empty()) {
     877                 :          6 :       d_propagationQueue.pop_front();
     878                 :            :     }
     879                 :            : 
     880         [ +  - ]:   15760600 :     Trace("equality") << d_name << "::eq::backtrack(): nodes" << std::endl;
     881                 :            : 
     882         [ +  + ]:  104355000 :     for (int i = (int)d_assertedEqualities.size() - 1, i_end = (int)d_assertedEqualitiesCount; i >= i_end; --i) {
     883                 :            :       // Get the ids of the merged classes
     884                 :   88594000 :       Equality& eq = d_assertedEqualities[i];
     885                 :            :       // Undo the merge
     886         [ +  + ]:   88594000 :       if (eq.d_lhs != null_id)
     887                 :            :       {
     888                 :   88534100 :         undoMerge(
     889                 :   88534100 :             d_equalityNodes[eq.d_lhs], d_equalityNodes[eq.d_rhs], eq.d_rhs);
     890                 :            :       }
     891                 :            :     }
     892                 :            : 
     893                 :   15760600 :     d_assertedEqualities.resize(d_assertedEqualitiesCount);
     894                 :            : 
     895         [ +  - ]:   15760600 :     Trace("equality") << d_name << "::eq::backtrack(): edges" << std::endl;
     896                 :            : 
     897         [ +  + ]:  104355000 :     for (int i = (int)d_equalityEdges.size() - 2, i_end = (int)(2*d_assertedEqualitiesCount); i >= i_end; i -= 2) {
     898                 :   88594000 :       EqualityEdge& edge1 = d_equalityEdges[i];
     899                 :   88594000 :       EqualityEdge& edge2 = d_equalityEdges[i | 1];
     900                 :   88594000 :       d_equalityGraph[edge2.getNodeId()] = edge1.getNext();
     901                 :   88594000 :       d_equalityGraph[edge1.getNodeId()] = edge2.getNext();
     902                 :            :     }
     903                 :            : 
     904                 :   15760600 :     d_equalityEdges.resize(2 * d_assertedEqualitiesCount);
     905                 :            :   }
     906                 :            : 
     907         [ +  + ]:  186646000 :   if (d_triggerTermSetUpdates.size() > d_triggerTermSetUpdatesSize) {
     908                 :            :     // Unset the individual triggers
     909         [ +  + ]:   13727500 :     for (int i = d_triggerTermSetUpdates.size() - 1, i_end = d_triggerTermSetUpdatesSize; i >= i_end; -- i) {
     910                 :   10457400 :       const TriggerSetUpdate& update = d_triggerTermSetUpdates[i];
     911                 :   10457400 :       d_nodeIndividualTrigger[update.d_classId] = update.d_oldValue;
     912                 :            :     }
     913                 :    3270070 :     d_triggerTermSetUpdates.resize(d_triggerTermSetUpdatesSize);
     914                 :            :   }
     915                 :            : 
     916         [ +  + ]:  186646000 :   if (d_equalityTriggers.size() > d_equalityTriggersCount) {
     917                 :            :     // Unlink the triggers from the lists
     918         [ +  + ]:    7783700 :     for (int i = d_equalityTriggers.size() - 1, i_end = d_equalityTriggersCount; i >= i_end; -- i) {
     919                 :    7614790 :       const Trigger& trigger = d_equalityTriggers[i];
     920                 :    7614790 :       d_nodeTriggers[trigger.d_classId] = trigger.d_nextTrigger;
     921                 :            :     }
     922                 :            :     // Get rid of the triggers
     923                 :     168916 :     d_equalityTriggers.resize(d_equalityTriggersCount);
     924                 :     168916 :     d_equalityTriggersOriginal.resize(d_equalityTriggersCount);
     925                 :            :   }
     926                 :            : 
     927         [ +  + ]:  186646000 :   if (d_applicationLookups.size() > d_applicationLookupsCount) {
     928         [ +  + ]:   32815000 :     for (int i = d_applicationLookups.size() - 1, i_end = (int) d_applicationLookupsCount; i >= i_end; -- i) {
     929                 :   28876600 :       d_applicationLookup.erase(d_applicationLookups[i]);
     930                 :            :     }
     931                 :    3938390 :     d_applicationLookups.resize(d_applicationLookupsCount);
     932                 :            :   }
     933                 :            : 
     934         [ +  + ]:  186646000 :   if (d_subtermEvaluates.size() > d_subtermEvaluatesSize) {
     935         [ +  + ]:    1451580 :     for(int i = d_subtermEvaluates.size() - 1, i_end = (int)d_subtermEvaluatesSize; i >= i_end; --i) {
     936                 :    1191020 :       d_subtermsToEvaluate[d_subtermEvaluates[i]] ++;
     937                 :            :     }
     938                 :     260561 :     d_subtermEvaluates.resize(d_subtermEvaluatesSize);
     939                 :            :   }
     940                 :            : 
     941         [ +  + ]:  186646000 :   if (d_nodes.size() > d_nodesCount) {
     942                 :            :     // Go down the nodes, check the application nodes and remove them from use-lists
     943         [ +  + ]:   18885700 :     for(int i = d_nodes.size() - 1, i_end = (int)d_nodesCount; i >= i_end; -- i) {
     944                 :            :       // Remove from the node -> id map
     945         [ +  - ]:   16415600 :       Trace("equality") << d_name << "::eq::backtrack(): removing node " << d_nodes[i] << std::endl;
     946                 :   16415600 :       d_nodeIds.erase(d_nodes[i]);
     947                 :            : 
     948                 :   16415600 :       const FunctionApplication& app = d_applications[i].d_original;
     949         [ +  + ]:   16415600 :       if (!app.isNull()) {
     950                 :            :         // Remove b from use-list
     951                 :    7119830 :         getEqualityNode(app.d_b).removeTopFromUseList(d_useListNodes);
     952                 :            :         // Remove a from use-list
     953                 :    7119830 :         getEqualityNode(app.d_a).removeTopFromUseList(d_useListNodes);
     954                 :            :       }
     955                 :            :     }
     956                 :            : 
     957                 :            :     // Now get rid of the nodes and the rest
     958                 :    2470140 :     d_nodes.resize(d_nodesCount);
     959                 :    2470140 :     d_applications.resize(d_nodesCount);
     960                 :    2470140 :     d_nodeTriggers.resize(d_nodesCount);
     961                 :    2470140 :     d_nodeIndividualTrigger.resize(d_nodesCount);
     962                 :    2470140 :     d_isConstant.resize(d_nodesCount);
     963                 :    2470140 :     d_subtermsToEvaluate.resize(d_nodesCount);
     964                 :    2470140 :     d_isEquality.resize(d_nodesCount);
     965                 :    2470140 :     d_isInternal.resize(d_nodesCount);
     966                 :    2470140 :     d_equalityGraph.resize(d_nodesCount);
     967                 :    2470140 :     d_equalityNodes.resize(d_nodesCount);
     968                 :            :   }
     969                 :            : 
     970         [ +  + ]:  186646000 :   if (d_deducedDisequalities.size() > d_deducedDisequalitiesSize) {
     971         [ +  + ]:   17143100 :     for(int i = d_deducedDisequalities.size() - 1, i_end = (int)d_deducedDisequalitiesSize; i >= i_end; -- i) {
     972                 :   12776500 :       EqualityPair pair = d_deducedDisequalities[i];
     973 [ -  + ][ -  + ]:   12776500 :       Assert(d_disequalityReasonsMap.find(pair)
                 [ -  - ]
     974                 :            :              != d_disequalityReasonsMap.end());
     975                 :            :       // Remove from the map
     976                 :   12776500 :       d_disequalityReasonsMap.erase(pair);
     977                 :   12776500 :       std::swap(pair.first, pair.second);
     978                 :   12776500 :       d_disequalityReasonsMap.erase(pair);
     979                 :            :     }
     980                 :    4366660 :     d_deducedDisequalityReasons.resize(d_deducedDisequalityReasonsSize);
     981                 :    4366660 :     d_deducedDisequalities.resize(d_deducedDisequalitiesSize);
     982                 :            :   }
     983                 :            : 
     984                 :  186646000 : }
     985                 :            : 
     986                 :   88595200 : void EqualityEngine::addGraphEdge(EqualityNodeId t1, EqualityNodeId t2, unsigned type, TNode reason) {
     987         [ +  - ]:  177190000 :   Trace("equality") << d_name << "::eq::addGraphEdge({" << t1 << "} "
     988                 :          0 :                     << d_nodes[t1] << ", {" << t2 << "} " << d_nodes[t2] << ","
     989                 :   88595200 :                     << reason << ")" << std::endl;
     990                 :   88595200 :   EqualityEdgeId edge = d_equalityEdges.size();
     991                 :   88595200 :   d_equalityEdges.push_back(EqualityEdge(t2, d_equalityGraph[t1], type, reason));
     992                 :   88595200 :   d_equalityEdges.push_back(EqualityEdge(t1, d_equalityGraph[t2], type, reason));
     993                 :   88595200 :   d_equalityGraph[t1] = edge;
     994                 :   88595200 :   d_equalityGraph[t2] = edge | 1;
     995                 :            : 
     996         [ -  + ]:   88595200 :   if (TraceIsOn("equality::internal")) {
     997                 :          0 :     debugPrintGraph();
     998                 :            :   }
     999                 :   88595200 : }
    1000                 :            : 
    1001                 :          0 : std::string EqualityEngine::edgesToString(EqualityEdgeId edgeId) const {
    1002                 :          0 :   std::stringstream out;
    1003                 :          0 :   bool first = true;
    1004         [ -  - ]:          0 :   if (edgeId == null_edge) {
    1005                 :          0 :     out << "null";
    1006                 :            :   } else {
    1007         [ -  - ]:          0 :     while (edgeId != null_edge) {
    1008                 :          0 :       const EqualityEdge& edge = d_equalityEdges[edgeId];
    1009         [ -  - ]:          0 :       if (!first) out << ",";
    1010                 :          0 :       out << "{" << edge.getNodeId() << "} " << d_nodes[edge.getNodeId()];
    1011                 :          0 :       edgeId = edge.getNext();
    1012                 :          0 :       first = false;
    1013                 :            :     }
    1014                 :            :   }
    1015                 :          0 :   return out.str();
    1016                 :            : }
    1017                 :            : 
    1018                 :    2769380 : void EqualityEngine::buildEqConclusion(EqualityNodeId id1,
    1019                 :            :                                        EqualityNodeId id2,
    1020                 :            :                                        EqProof* eqp) const
    1021                 :            : {
    1022                 :    2769380 :   Kind k1 = d_nodes[id1].getKind();
    1023                 :    2769380 :   Kind k2 = d_nodes[id2].getKind();
    1024                 :            :   // only try to build if ids do not correspond to internal nodes. If they do,
    1025                 :            :   // only try to build build if full applications corresponding to the given ids
    1026                 :            :   // have the same congruence n-ary non-APPLY_* kind, since the internal nodes
    1027                 :            :   // may be full nodes.
    1028         [ +  + ]:    4151860 :   if ((d_isInternal[id1] || d_isInternal[id2])
    1029 [ +  + ][ +  - ]:    4211570 :       && (k1 != k2 || k1 == Kind::APPLY_UF || k1 == Kind::APPLY_CONSTRUCTOR
         [ +  + ][ +  + ]
                 [ +  + ]
    1030 [ +  - ][ +  - ]:      59701 :           || k1 == Kind::APPLY_SELECTOR || k1 == Kind::APPLY_TESTER
    1031         [ +  + ]:      59701 :           || !NodeManager::isNAryKind(k1)))
    1032                 :            :   {
    1033                 :    2764820 :     return;
    1034                 :            :   }
    1035         [ +  - ]:    2776490 :   Trace("equality") << "buildEqConclusion: {" << id1 << "} " << d_nodes[id1]
    1036                 :    1388250 :                     << "\n";
    1037         [ +  - ]:    2776490 :   Trace("equality") << "buildEqConclusion: {" << id2 << "} " << d_nodes[id2]
    1038                 :    1388250 :                     << "\n";
    1039 [ +  + ][ -  - ]:    6941230 :   Node eq[2];
    1040                 :    1388250 :   NodeManager* nm = nodeManager();
    1041         [ +  + ]:    4164740 :   for (unsigned i = 0; i < 2; ++i)
    1042                 :            :   {
    1043         [ +  + ]:    2776490 :     EqualityNodeId equalityNodeId = i == 0 ? id1 : id2;
    1044                 :    2776490 :     Node equalityNode = d_nodes[equalityNodeId];
    1045                 :            :     // if not an internal node, just retrieve it
    1046         [ +  + ]:    2776490 :     if (!d_isInternal[equalityNodeId])
    1047                 :            :     {
    1048                 :    2764970 :       eq[i] = equalityNode;
    1049                 :    2764970 :       continue;
    1050                 :            :     }
    1051                 :            :     // build node relative to partial application of this
    1052                 :            :     // n-ary kind. We get the full application, then we get
    1053                 :            :     // the arguments relative to how partial the internal
    1054                 :            :     // node is, and build the application
    1055                 :            : 
    1056                 :            :     // get number of children of partial app:
    1057                 :            :     // #children of full app - (id of full app - id of
    1058                 :            :     // partial app)
    1059                 :      11518 :     EqualityNodeId fullAppId = getNodeId(equalityNode);
    1060                 :      11518 :     EqualityNodeId curr = fullAppId;
    1061                 :      11518 :     unsigned separation = 0;
    1062 [ -  + ][ -  + ]:      11518 :     Assert(fullAppId >= equalityNodeId);
                 [ -  - ]
    1063         [ +  + ]:      28607 :     while (curr != equalityNodeId)
    1064                 :            :     {
    1065         [ +  - ]:      17089 :       separation = separation + (d_nodes[curr--] == equalityNode ? 1 : 0);
    1066                 :            :     }
    1067                 :            :     // compute separation, which is how many ids with the
    1068                 :            :     // same fullappnode exist between equalityNodeId and
    1069                 :            :     // fullAppId
    1070                 :      11518 :     unsigned numChildren = equalityNode.getNumChildren() - separation;
    1071 [ -  + ][ -  - ]:      11518 :     Assert(numChildren < equalityNode.getNumChildren())
    1072                 :          0 :         << "broke for numChildren " << numChildren << ", fullAppId "
    1073                 :          0 :         << fullAppId << ", equalityNodeId " << equalityNodeId << ", node "
    1074                 :      11518 :         << equalityNode << ", cong: {" << id1 << "} " << d_nodes[id1] << " = {"
    1075 [ -  + ][ -  + ]:      11518 :         << id2 << "} " << d_nodes[id2] << "\n";
                 [ -  - ]
    1076                 :            :     // if has at least as many children as the minimal
    1077                 :            :     // number of children of the n-ary kind, build the node
    1078         [ +  + ]:      11518 :     if (numChildren >= kind::metakind::getMinArityForKind(k1))
    1079                 :            :     {
    1080                 :       2392 :       std::vector<Node> children;
    1081         [ +  + ]:       7606 :       for (unsigned j = 0; j < numChildren; ++j)
    1082                 :            :       {
    1083                 :       5214 :         children.push_back(equalityNode[j]);
    1084                 :            :       }
    1085                 :       2392 :       eq[i] = nm->mkNode(k1, children);
    1086                 :            :     }
    1087                 :            :   }
    1088                 :            :   // if built equality, add it as eqp's conclusion
    1089 [ +  + ][ +  - ]:    1388250 :   if (!eq[0].isNull() && !eq[1].isNull())
                 [ +  + ]
    1090                 :            :   {
    1091                 :    1383680 :     eqp->d_node = eq[0].eqNode(eq[1]);
    1092         [ +  - ]:    1383680 :     Trace("equality") << "buildEqConclusion: Built equality " << eqp->d_node << "\n";
    1093                 :    1383680 :     return;
    1094                 :            :   }
    1095         [ +  - ]:       4563 :   Trace("equality") << "buildEqConclusion: Did not build equality\n";
    1096                 :            : }
    1097                 :            : 
    1098                 :     776073 : void EqualityEngine::explainEquality(TNode t1, TNode t2, bool polarity,
    1099                 :            :                                      std::vector<TNode>& equalities,
    1100                 :            :                                      EqProof* eqp) const {
    1101         [ +  - ]:    1552150 :   Trace("pf::ee") << d_name << "::eq::explainEquality(" << t1 << ", " << t2
    1102         [ -  - ]:          0 :                   << ", " << (polarity ? "true" : "false") << ")"
    1103         [ -  - ]:     776073 :                   << ", proof = " << (eqp ? "ON" : "OFF") << std::endl;
    1104                 :            : 
    1105                 :            :   // The terms must be there already
    1106                 :    1552150 :   Assert(hasTerm(t1) && hasTerm(t2));
    1107                 :            : 
    1108                 :            :   // Get the ids
    1109                 :     776073 :   EqualityNodeId t1Id = getNodeId(t1);
    1110                 :     776073 :   EqualityNodeId t2Id = getNodeId(t2);
    1111                 :            : 
    1112         [ +  - ]:     776073 :   Trace("pf::ee") << "Ids: " << t1Id << ", " << t2Id << "\n";
    1113                 :            : 
    1114         [ -  + ]:     776073 :   if (TraceIsOn("equality::internal"))
    1115                 :            :   {
    1116                 :          0 :     debugPrintGraph();
    1117                 :            :   }
    1118                 :            : 
    1119                 :    1552150 :   std::map<std::pair<EqualityNodeId, EqualityNodeId>, EqProof*> cache;
    1120         [ +  + ]:     776073 :   if (polarity) {
    1121                 :            :     // Get the explanation
    1122                 :     728217 :     getExplanation(t1Id, t2Id, equalities, cache, eqp);
    1123                 :            :   } else {
    1124         [ +  + ]:      47856 :     if (eqp) {
    1125                 :      20191 :       eqp->d_id = MERGED_THROUGH_TRANS;
    1126                 :      20191 :       eqp->d_node = d_nodes[t1Id].eqNode(d_nodes[t2Id]).notNode();
    1127                 :            :     }
    1128                 :            : 
    1129                 :            :     // Get the reason for this disequality
    1130                 :      47856 :     EqualityPair pair(t1Id, t2Id);
    1131 [ -  + ][ -  + ]:      47856 :     Assert(d_disequalityReasonsMap.find(pair) != d_disequalityReasonsMap.end())
                 [ -  - ]
    1132                 :          0 :         << "Don't ask for stuff I didn't notify you about";
    1133                 :      47856 :     DisequalityReasonRef reasonRef = d_disequalityReasonsMap.find(pair)->second;
    1134         [ +  + ]:      47856 :     if (eqp)
    1135                 :            :     {
    1136         [ +  - ]:      40382 :       Trace("pf::ee") << "Deq reason for " << eqp->d_node << " "
    1137                 :          0 :                       << reasonRef.d_mergesStart << "..."
    1138                 :      20191 :                       << reasonRef.d_mergesEnd << std::endl;
    1139                 :            :     }
    1140         [ +  + ]:     117569 :     for (unsigned i = reasonRef.d_mergesStart; i < reasonRef.d_mergesEnd; ++i)
    1141                 :            :     {
    1142                 :      69713 :       EqualityPair toExplain = d_deducedDisequalityReasons[i];
    1143                 :      69713 :       std::shared_ptr<EqProof> eqpc;
    1144                 :            : 
    1145                 :            :       // If we're constructing a (transitivity) proof, we don't need to include an explanation for x=x.
    1146 [ +  + ][ +  + ]:      69713 :       if (eqp && toExplain.first != toExplain.second) {
    1147                 :      24797 :         eqpc = std::make_shared<EqProof>();
    1148         [ +  - ]:      49594 :         Trace("pf::ee") << "Deq getExplanation #" << i << " for " << eqp->d_node
    1149                 :          0 :                         << " : " << toExplain.first << " " << toExplain.second
    1150                 :      24797 :                         << std::endl;
    1151                 :            :       }
    1152                 :            : 
    1153                 :      69713 :       getExplanation(
    1154                 :            :           toExplain.first, toExplain.second, equalities, cache, eqpc.get());
    1155                 :            : 
    1156         [ +  + ]:      69713 :       if (eqpc) {
    1157         [ -  + ]:      24797 :         if (TraceIsOn("pf::ee"))
    1158                 :            :         {
    1159         [ -  - ]:          0 :           Trace("pf::ee") << "Child proof is:" << std::endl;
    1160                 :          0 :           eqpc->debug_print("pf::ee", 1);
    1161                 :            :         }
    1162         [ +  + ]:      24797 :         if (eqpc->d_id == MERGED_THROUGH_TRANS)
    1163                 :            :         {
    1164                 :      26228 :           std::vector<std::shared_ptr<EqProof>> orderedChildren;
    1165                 :      13114 :           bool nullCongruenceFound = false;
    1166         [ +  + ]:      43313 :           for (const auto& child : eqpc->d_children)
    1167                 :            :           {
    1168                 :      30199 :             if (child->d_id == MERGED_THROUGH_CONGRUENCE
    1169 [ +  + ][ +  + ]:      30199 :                 && child->d_node.isNull())
                 [ +  + ]
    1170                 :            :             {
    1171                 :      14090 :               nullCongruenceFound = true;
    1172         [ +  - ]:      28180 :               Trace("pf::ee")
    1173                 :          0 :                   << "Have congruence with empty d_node. Splitting..."
    1174                 :      14090 :                   << std::endl;
    1175                 :      14090 :               orderedChildren.insert(orderedChildren.begin(),
    1176                 :      28180 :                                      child->d_children[0]);
    1177                 :      14090 :               orderedChildren.push_back(child->d_children[1]);
    1178                 :            :             }
    1179                 :            :             else
    1180                 :            :             {
    1181                 :      16109 :               orderedChildren.push_back(child);
    1182                 :            :             }
    1183                 :            :           }
    1184                 :            : 
    1185         [ +  + ]:      13114 :           if (nullCongruenceFound) {
    1186                 :      11349 :             eqpc->d_children = orderedChildren;
    1187         [ -  + ]:      11349 :             if (TraceIsOn("pf::ee"))
    1188                 :            :             {
    1189         [ -  - ]:          0 :               Trace("pf::ee")
    1190                 :          0 :                   << "Child proof's children have been reordered. It is now:"
    1191                 :          0 :                   << std::endl;
    1192                 :          0 :               eqpc->debug_print("pf::ee", 1);
    1193                 :            :             }
    1194                 :            :           }
    1195                 :            :         }
    1196                 :            : 
    1197                 :      24797 :         eqp->d_children.push_back(eqpc);
    1198                 :            :       }
    1199                 :            :     }
    1200                 :            : 
    1201         [ +  + ]:      47856 :     if (eqp) {
    1202         [ -  + ]:      20191 :       if (eqp->d_children.size() == 0) {
    1203                 :            :         // Corner case where this is actually a disequality between two constants
    1204         [ -  - ]:          0 :         Trace("pf::ee") << "Encountered a constant disequality (not a transitivity proof): "
    1205                 :          0 :                         << eqp->d_node << std::endl;
    1206                 :          0 :         Assert(eqp->d_node[0][0].isConst());
    1207                 :          0 :         Assert(eqp->d_node[0][1].isConst());
    1208                 :          0 :         eqp->d_id = MERGED_THROUGH_CONSTANTS;
    1209         [ +  + ]:      20191 :       } else if (eqp->d_children.size() == 1) {
    1210                 :      31848 :         Node cnode = eqp->d_children[0]->d_node;
    1211         [ +  - ]:      31848 :         Trace("pf::ee") << "Simplifying " << cnode << " from " << eqp->d_node
    1212                 :      15924 :                         << std::endl;
    1213                 :      15924 :         bool simpTrans = true;
    1214         [ +  - ]:      15924 :         if (cnode.getKind() == Kind::EQUAL)
    1215                 :            :         {
    1216                 :            :           // It may be the case that we have a proof of x = c2 and we want to
    1217                 :            :           // conclude x != c1. If this is the case, below we construct:
    1218                 :            :           //
    1219                 :            :           //          -------- MERGED_THROUGH_EQUALITY
    1220                 :            :           // x = c2   c1 != c2
    1221                 :            :           // ----------------- TRANS
    1222                 :            :           //     x != c1
    1223 [ +  + ][ +  + ]:      31848 :           TNode c1 = t1.isConst() ? t1 : (t2.isConst() ? t2 : TNode::null());
    1224 [ +  + ][ +  + ]:      31848 :           TNode nc = t1.isConst() ? t2 : (t2.isConst() ? t1 : TNode::null());
    1225                 :      31848 :           Node c2;
    1226                 :            :           // merge constants transitivity
    1227         [ +  + ]:      47170 :           for (unsigned i = 0; i < 2; i++)
    1228                 :            :           {
    1229                 :      31555 :             if (cnode[i].isConst() && cnode[1 - i] == nc)
    1230                 :            :             {
    1231                 :        309 :               c2 = cnode[i];
    1232                 :        309 :               break;
    1233                 :            :             }
    1234                 :            :           }
    1235 [ +  + ][ +  + ]:      15924 :           if (!c1.isNull() && !c2.isNull())
                 [ +  + ]
    1236                 :            :           {
    1237                 :        309 :             simpTrans = false;
    1238 [ -  + ][ -  + ]:        309 :             Assert(c1.getType() == c2.getType());
                 [ -  - ]
    1239                 :        618 :             std::shared_ptr<EqProof> eqpmc = std::make_shared<EqProof>();
    1240                 :        309 :             eqpmc->d_id = MERGED_THROUGH_CONSTANTS;
    1241                 :        309 :             eqpmc->d_node = c1.eqNode(c2).eqNode(d_false);
    1242                 :        309 :             eqp->d_children.push_back(eqpmc);
    1243                 :            :           }
    1244                 :            :         }
    1245         [ +  + ]:      15924 :         if (simpTrans)
    1246                 :            :         {
    1247                 :            :           // The transitivity proof has just one child. Simplify.
    1248                 :      31230 :           std::shared_ptr<EqProof> temp = eqp->d_children[0];
    1249                 :      15615 :           eqp->d_children.clear();
    1250                 :      15615 :           *eqp = *temp;
    1251                 :            :         }
    1252                 :            :       }
    1253                 :            : 
    1254         [ -  + ]:      20191 :       if (TraceIsOn("pf::ee"))
    1255                 :            :       {
    1256         [ -  - ]:          0 :         Trace("pf::ee") << "Disequality explanation final proof: " << std::endl;
    1257                 :          0 :         eqp->debug_print("pf::ee", 1);
    1258                 :            :       }
    1259                 :            :     }
    1260                 :            :   }
    1261                 :     776073 : }
    1262                 :            : 
    1263                 :      29368 : void EqualityEngine::explainPredicate(TNode p, bool polarity,
    1264                 :            :                                       std::vector<TNode>& assertions,
    1265                 :            :                                       EqProof* eqp) const {
    1266         [ +  - ]:      58736 :   Trace("equality") << d_name << "::eq::explainPredicate(" << p << ")"
    1267                 :      29368 :                     << std::endl;
    1268                 :            :   // Must have the term
    1269 [ -  + ][ -  + ]:      29368 :   Assert(hasTerm(p));
                 [ -  - ]
    1270                 :      29368 :   std::map<std::pair<EqualityNodeId, EqualityNodeId>, EqProof*> cache;
    1271         [ -  + ]:      29368 :   if (TraceIsOn("equality::internal"))
    1272                 :            :   {
    1273                 :          0 :     debugPrintGraph();
    1274                 :            :   }
    1275                 :            :   // Get the explanation
    1276         [ +  + ]:      29368 :   getExplanation(
    1277                 :            :       getNodeId(p), polarity ? d_trueId : d_falseId, assertions, cache, eqp);
    1278                 :      29368 : }
    1279                 :            : 
    1280                 :     435457 : void EqualityEngine::explainLit(TNode lit,
    1281                 :            :                                 std::vector<TNode>& assumptions) const
    1282                 :            : {
    1283         [ +  - ]:     435457 :   Trace("eq-exp") << "explainLit: " << lit << std::endl;
    1284 [ -  + ][ -  + ]:     435457 :   Assert(lit.getKind() != Kind::AND);
                 [ -  - ]
    1285                 :     435457 :   bool polarity = lit.getKind() != Kind::NOT;
    1286         [ +  + ]:     435457 :   TNode atom = polarity ? lit : lit[0];
    1287                 :     435457 :   std::vector<TNode> tassumptions;
    1288         [ +  + ]:     435457 :   if (atom.getKind() == Kind::EQUAL)
    1289                 :            :   {
    1290 [ -  + ][ -  + ]:     416848 :     Assert(hasTerm(atom[0]));
                 [ -  - ]
    1291 [ -  + ][ -  + ]:     416848 :     Assert(hasTerm(atom[1]));
                 [ -  - ]
    1292         [ +  + ]:     416848 :     if (!polarity)
    1293                 :            :     {
    1294                 :            :       // ensure that we are ready to explain the disequality
    1295 [ -  + ][ -  + ]:      27663 :       AlwaysAssert(areDisequal(atom[0], atom[1], true));
                 [ -  - ]
    1296                 :            :     }
    1297         [ -  + ]:     389185 :     else if (atom[0] == atom[1])
    1298                 :            :     {
    1299                 :            :       // no need to explain reflexivity
    1300                 :          0 :       return;
    1301                 :            :     }
    1302                 :     416848 :     explainEquality(atom[0], atom[1], polarity, tassumptions);
    1303                 :            :   }
    1304                 :            :   else
    1305                 :            :   {
    1306                 :      18609 :     explainPredicate(atom, polarity, tassumptions);
    1307                 :            :   }
    1308                 :            :   // ensure that duplicates are removed
    1309         [ +  + ]:    2233280 :   for (TNode a : tassumptions)
    1310                 :            :   {
    1311                 :    1797820 :     if (std::find(assumptions.begin(), assumptions.end(), a)
    1312         [ +  + ]:    3595640 :         == assumptions.end())
    1313                 :            :     {
    1314 [ -  + ][ -  + ]:    1606120 :       Assert(!a.isNull());
                 [ -  - ]
    1315                 :    1606120 :       assumptions.push_back(a);
    1316                 :            :     }
    1317                 :            :   }
    1318                 :            : }
    1319                 :            : 
    1320                 :     366245 : Node EqualityEngine::mkExplainLit(TNode lit) const
    1321                 :            : {
    1322 [ -  + ][ -  + ]:     366245 :   Assert(lit.getKind() != Kind::AND);
                 [ -  - ]
    1323                 :     732490 :   std::vector<TNode> assumptions;
    1324                 :     366245 :   explainLit(lit, assumptions);
    1325                 :     366245 :   Node ret;
    1326         [ -  + ]:     366245 :   if (assumptions.empty())
    1327                 :            :   {
    1328                 :          0 :     ret = nodeManager()->mkConst(true);
    1329                 :            :   }
    1330         [ +  + ]:     366245 :   else if (assumptions.size() == 1)
    1331                 :            :   {
    1332                 :      67711 :     ret = assumptions[0];
    1333                 :            :   }
    1334                 :            :   else
    1335                 :            :   {
    1336                 :     298534 :     ret = nodeManager()->mkNode(Kind::AND, assumptions);
    1337                 :            :   }
    1338                 :     732490 :   return ret;
    1339                 :            : }
    1340                 :            : 
    1341                 :    8608180 : void EqualityEngine::getExplanation(
    1342                 :            :     EqualityNodeId t1Id,
    1343                 :            :     EqualityNodeId t2Id,
    1344                 :            :     std::vector<TNode>& equalities,
    1345                 :            :     std::map<std::pair<EqualityNodeId, EqualityNodeId>, EqProof*>& cache,
    1346                 :            :     EqProof* eqp) const
    1347                 :            : {
    1348         [ +  - ]:   17216400 :   Trace("eq-exp") << d_name << "::eq::getExplanation({" << t1Id << "} "
    1349                 :          0 :                   << d_nodes[t1Id] << ", {" << t2Id << "} " << d_nodes[t2Id]
    1350                 :    8608180 :                   << ") size = " << cache.size() << std::endl;
    1351                 :            : 
    1352                 :            :   // determine if we have already computed the explanation.
    1353                 :    8608180 :   std::pair<EqualityNodeId, EqualityNodeId> cacheKey;
    1354                 :    8608180 :   std::map<std::pair<EqualityNodeId, EqualityNodeId>, EqProof*>::iterator it;
    1355         [ +  + ]:    8608180 :   if (!eqp)
    1356                 :            :   {
    1357                 :            :     // If proofs are disabled, we order the ids, since explaining t1 = t2 is the
    1358                 :            :     // same as explaining t2 = t1.
    1359                 :    4620430 :     cacheKey = std::minmax(t1Id, t2Id);
    1360                 :    4620430 :     it = cache.find(cacheKey);
    1361         [ +  + ]:    4620430 :     if (it != cache.end())
    1362                 :            :     {
    1363                 :    2246470 :       return;
    1364                 :            :     }
    1365                 :            :   }
    1366                 :            :   else
    1367                 :            :   {
    1368                 :            :     // If proofs are enabled, note that proofs are sensitive to the order of t1
    1369                 :            :     // and t2, so we don't sort the ids in this case. TODO: Depending on how
    1370                 :            :     // issue #2965 is resolved, we may be able to revisit this, if it is the
    1371                 :            :     // case that proof/uf_proof.h,cpp is robust to equality ordering.
    1372                 :    3987750 :     cacheKey = std::pair<EqualityNodeId, EqualityNodeId>(t1Id, t2Id);
    1373                 :    3987750 :     it = cache.find(cacheKey);
    1374         [ +  + ]:    3987750 :     if (it != cache.end())
    1375                 :            :     {
    1376         [ +  + ]:    1898590 :       if (it->second)
    1377                 :            :       {
    1378                 :    1898570 :         eqp->d_id = it->second->d_id;
    1379                 :    1898570 :         eqp->d_children.insert(eqp->d_children.end(),
    1380                 :    1898570 :                                it->second->d_children.begin(),
    1381                 :    5695710 :                                it->second->d_children.end());
    1382                 :    1898570 :         eqp->d_node = it->second->d_node;
    1383                 :            :       }
    1384                 :            :       else
    1385                 :            :       {
    1386                 :            :         // We may have cached null in its place, create the trivial proof now.
    1387 [ -  + ][ -  + ]:         23 :         Assert(d_nodes[t1Id] == d_nodes[t2Id]);
                 [ -  - ]
    1388 [ -  + ][ -  + ]:         23 :         Assert(eqp->d_id == MERGED_THROUGH_REFLEXIVITY);
                 [ -  - ]
    1389                 :         23 :         eqp->d_node = d_nodes[t1Id].eqNode(d_nodes[t1Id]);
    1390                 :            :       }
    1391                 :    1898590 :       return;
    1392                 :            :     }
    1393                 :            :   }
    1394                 :    4463110 :   cache[cacheKey] = eqp;
    1395                 :            : 
    1396                 :            :   // We can only explain the nodes that got merged
    1397                 :            : #ifdef CVC5_ASSERTIONS
    1398                 :    4463110 :   bool canExplain = getEqualityNode(t1Id).getFind() == getEqualityNode(t2Id).getFind()
    1399 [ +  + ][ +  - ]:    4463110 :                   || (d_done && isConstant(t1Id) && isConstant(t2Id));
         [ +  - ][ +  - ]
    1400                 :            : 
    1401         [ -  + ]:    4463110 :   if (!canExplain) {
    1402                 :          0 :     warning() << "Can't explain equality:" << std::endl;
    1403                 :          0 :     warning() << d_nodes[t1Id] << " with find " << d_nodes[getEqualityNode(t1Id).getFind()] << std::endl;
    1404                 :          0 :     warning() << d_nodes[t2Id] << " with find " << d_nodes[getEqualityNode(t2Id).getFind()] << std::endl;
    1405                 :            :   }
    1406 [ -  + ][ -  + ]:    4463110 :   Assert(canExplain);
                 [ -  - ]
    1407                 :            : #endif
    1408                 :            : 
    1409                 :            :   // If the nodes are the same, we're done
    1410         [ +  + ]:    4463110 :   if (t1Id == t2Id)
    1411                 :            :   {
    1412         [ +  + ]:    1116370 :     if (eqp)
    1413                 :            :     {
    1414                 :            :       // ignore equalities between function symbols, i.e. internal nullary
    1415                 :            :       // non-constant nodes.
    1416                 :            :       //
    1417                 :            :       // Note that this is robust for HOL because in that case function
    1418                 :            :       // symbols are not internal nodes
    1419         [ +  + ]:     715789 :       if (d_isInternal[t1Id] && d_nodes[t1Id].getNumChildren() == 0
    1420 [ +  + ][ +  - ]:     715789 :           && !d_isConstant[t1Id])
                 [ +  + ]
    1421                 :            :       {
    1422                 :     211272 :         eqp->d_node = Node::null();
    1423                 :            :       }
    1424                 :            :       else
    1425                 :            :       {
    1426 [ -  + ][ -  + ]:     292555 :         Assert(d_nodes[t1Id].getKind() != Kind::BUILTIN);
                 [ -  - ]
    1427                 :     292555 :         eqp->d_node = d_nodes[t1Id].eqNode(d_nodes[t1Id]);
    1428                 :            :       }
    1429                 :            :     }
    1430                 :    1116370 :     return;
    1431                 :            :   }
    1432                 :            : 
    1433                 :            :   // Queue for the BFS containing nodes
    1434                 :    6693480 :   std::vector<BfsData> bfsQueue;
    1435                 :            : 
    1436                 :            :   // Find a path from t1 to t2 in the graph (BFS)
    1437                 :    3346740 :   bfsQueue.push_back(BfsData(t1Id, null_id, 0));
    1438                 :    3346740 :   size_t currentIndex = 0;
    1439                 :            :   while (true) {
    1440                 :            :     // There should always be a path, and every node can be visited only once (tree)
    1441 [ -  + ][ -  + ]:   20571800 :     Assert(currentIndex < bfsQueue.size());
                 [ -  - ]
    1442                 :            : 
    1443                 :            :     // The next node to visit
    1444                 :   20571800 :     BfsData current = bfsQueue[currentIndex];
    1445                 :   20571800 :     EqualityNodeId currentNode = current.d_nodeId;
    1446                 :            : 
    1447         [ +  - ]:   41143600 :     Trace("equality") << d_name << "::eq::getExplanation(): currentNode = {"
    1448                 :          0 :                       << currentNode << "} " << d_nodes[currentNode]
    1449                 :   20571800 :                       << std::endl;
    1450                 :            : 
    1451                 :            :     // Go through the equality edges of this node
    1452                 :   20571800 :     EqualityEdgeId currentEdge = d_equalityGraph[currentNode];
    1453         [ -  + ]:   20571800 :     if (TraceIsOn("equality")) {
    1454         [ -  - ]:          0 :       Trace("equality") << d_name << "::eq::getExplanation(): edgesId =  " << currentEdge << std::endl;
    1455                 :          0 :       Trace("equality") << d_name << "::eq::getExplanation(): edges =  " << edgesToString(currentEdge) << std::endl;
    1456                 :            :     }
    1457                 :            : 
    1458         [ +  + ]:   70325900 :     while (currentEdge != null_edge) {
    1459                 :            :       // Get the edge
    1460                 :   53100900 :       const EqualityEdge& edge = d_equalityEdges[currentEdge];
    1461                 :            : 
    1462                 :            :       // If not just the backwards edge
    1463         [ +  + ]:   53100900 :       if ((currentEdge | 1u) != (current.d_edgeId | 1u))
    1464                 :            :       {
    1465         [ +  - ]:   73664900 :         Trace("equality") << d_name
    1466                 :          0 :                           << "::eq::getExplanation(): currentEdge = ({"
    1467                 :          0 :                           << currentNode << "} " << d_nodes[currentNode]
    1468                 :   36832500 :                           << ", {" << edge.getNodeId() << "} "
    1469                 :   36832500 :                           << d_nodes[edge.getNodeId()] << ")" << std::endl;
    1470                 :            : 
    1471                 :            :         // Did we find the path
    1472         [ +  + ]:   36832500 :         if (edge.getNodeId() == t2Id) {
    1473                 :            : 
    1474         [ +  - ]:    3346740 :           Trace("equality") << d_name << "::eq::getExplanation(): path found: " << std::endl;
    1475                 :            : 
    1476                 :    3346740 :           std::vector<std::shared_ptr<EqProof>> eqp_trans;
    1477                 :            : 
    1478                 :            :           // Reconstruct the path
    1479                 :    4091580 :           do {
    1480                 :            :             // The current node
    1481                 :    7438320 :             currentNode = bfsQueue[currentIndex].d_nodeId;
    1482                 :    7438320 :             EqualityNodeId edgeNode = d_equalityEdges[currentEdge].getNodeId();
    1483                 :            :             MergeReasonType reasonType = static_cast<MergeReasonType>(
    1484                 :    7438320 :                 d_equalityEdges[currentEdge].getReasonType());
    1485                 :   14876600 :             Node reason = d_equalityEdges[currentEdge].getReason();
    1486                 :            : 
    1487         [ +  - ]:   14876600 :             Trace("equality")
    1488                 :          0 :                 << d_name
    1489                 :          0 :                 << "::eq::getExplanation(): currentEdge = " << currentEdge
    1490                 :    7438320 :                 << ", currentNode = " << currentNode << std::endl;
    1491         [ +  - ]:   14876600 :             Trace("equality")
    1492                 :          0 :                 << d_name << "                       targetNode = {" << edgeNode
    1493                 :    7438320 :                 << "} " << d_nodes[edgeNode] << std::endl;
    1494         [ +  - ]:   14876600 :             Trace("equality")
    1495                 :          0 :                 << d_name << "                       in currentEdge = ({"
    1496                 :          0 :                 << currentNode << "} " << d_nodes[currentNode] << ", {"
    1497                 :    7438320 :                 << edge.getNodeId() << "} " << d_nodes[edge.getNodeId()] << ")"
    1498                 :    7438320 :                 << std::endl;
    1499         [ +  - ]:   14876600 :             Trace("equality")
    1500                 :          0 :                 << d_name
    1501                 :          0 :                 << "                       reason type = " << reasonType
    1502                 :    7438320 :                 << "\n";
    1503                 :            : 
    1504                 :    7438320 :             std::shared_ptr<EqProof> eqpc;;
    1505                 :            :             // Make child proof if a proof is being constructed
    1506         [ +  + ]:    7438320 :             if (eqp) {
    1507                 :    3448900 :               eqpc = std::make_shared<EqProof>();
    1508                 :    3448900 :               eqpc->d_id = reasonType;
    1509                 :            :             }
    1510                 :            : 
    1511                 :            :             // Add the actual equality to the vector
    1512 [ +  + ][ +  + ]:    7438320 :             switch (reasonType) {
    1513                 :    3836580 :             case MERGED_THROUGH_CONGRUENCE: {
    1514                 :            :               // f(x1, x2) == f(y1, y2) because x1 = y1 and x2 = y2
    1515         [ +  - ]:    7673160 :               Trace("equality")
    1516                 :          0 :                   << d_name
    1517                 :          0 :                   << "::eq::getExplanation(): due to congruence, going deeper"
    1518                 :    3836580 :                   << std::endl;
    1519                 :            :               const FunctionApplication& f1 =
    1520                 :    3836580 :                   d_applications[currentNode].d_original;
    1521                 :            :               const FunctionApplication& f2 =
    1522                 :    3836580 :                   d_applications[edgeNode].d_original;
    1523                 :            : 
    1524         [ +  - ]:    3836580 :               Trace("equality") << push;
    1525         [ +  - ]:    3836580 :               Trace("equality") << "Explaining left hand side equalities" << std::endl;
    1526                 :            :               std::shared_ptr<EqProof> eqpc1 =
    1527         [ +  + ]:    7673160 :                   eqpc ? std::make_shared<EqProof>() : nullptr;
    1528                 :    3836580 :               getExplanation(f1.d_a, f2.d_a, equalities, cache, eqpc1.get());
    1529         [ +  - ]:    3836580 :               Trace("equality") << "Explaining right hand side equalities" << std::endl;
    1530                 :            :               std::shared_ptr<EqProof> eqpc2 =
    1531         [ +  + ]:    7673160 :                   eqpc ? std::make_shared<EqProof>() : nullptr;
    1532                 :    3836580 :               getExplanation(f1.d_b, f2.d_b, equalities, cache, eqpc2.get());
    1533         [ +  + ]:    3836580 :               if (eqpc)
    1534                 :            :               {
    1535                 :    1792630 :                 eqpc->d_children.push_back(eqpc1);
    1536                 :    1792630 :                 eqpc->d_children.push_back(eqpc2);
    1537                 :            :                 // build conclusion if ids correspond to non-internal nodes or
    1538                 :            :                 // if non-internal nodes can be retrieved from them (in the
    1539                 :            :                 // case of n-ary applications), otherwise leave conclusion as
    1540                 :            :                 // null. This is only done for congruence kinds, since
    1541                 :            :                 // congruence is not used otherwise.
    1542                 :    1792630 :                 Kind k = d_nodes[currentNode].getKind();
    1543         [ +  + ]:    1792630 :                 if (d_congruenceKinds[k])
    1544                 :            :                 {
    1545                 :    1768380 :                   buildEqConclusion(currentNode, edgeNode, eqpc.get());
    1546                 :            :                 }
    1547                 :            :                 else
    1548                 :            :                 {
    1549 [ -  + ][ -  - ]:      48498 :                   Assert(k == Kind::EQUAL)
    1550 [ -  + ][ -  + ]:      24249 :                       << "not an internal node " << d_nodes[currentNode]
                 [ -  - ]
    1551                 :          0 :                       << " with non-congruence with " << k << "\n";
    1552                 :            :                 }
    1553                 :            :               }
    1554         [ +  - ]:    3836580 :               Trace("equality") << pop;
    1555                 :    3836580 :               break;
    1556                 :            :             }
    1557                 :            : 
    1558                 :      26698 :             case MERGED_THROUGH_REFLEXIVITY: {
    1559                 :            :               // x1 == x1
    1560         [ +  - ]:      26698 :               Trace("equality") << d_name << "::eq::getExplanation(): due to reflexivity, going deeper" << std::endl;
    1561         [ +  + ]:      26698 :               EqualityNodeId eqId = currentNode == d_trueId ? edgeNode : currentNode;
    1562                 :      26698 :               const FunctionApplication& eq = d_applications[eqId].d_original;
    1563 [ -  + ][ -  + ]:      26698 :               Assert(eq.isEquality()) << "Must be an equality";
                 [ -  - ]
    1564                 :            : 
    1565                 :            :               // Explain why a = b constant
    1566         [ +  - ]:      26698 :               Trace("equality") << push;
    1567                 :            :               std::shared_ptr<EqProof> eqpc1 =
    1568         [ +  + ]:      53396 :                   eqpc ? std::make_shared<EqProof>() : nullptr;
    1569                 :      26698 :               getExplanation(eq.d_a, eq.d_b, equalities, cache, eqpc1.get());
    1570         [ +  + ]:      26698 :               if( eqpc ){
    1571                 :       8433 :                 eqpc->d_children.push_back( eqpc1 );
    1572                 :            :               }
    1573         [ +  - ]:      26698 :               Trace("equality") << pop;
    1574                 :            : 
    1575                 :      26698 :               break;
    1576                 :            :             }
    1577                 :            : 
    1578                 :      41040 :             case MERGED_THROUGH_CONSTANTS: {
    1579                 :            :               // f(c1, ..., cn) = c semantically, we can just ignore it
    1580         [ +  - ]:      41040 :               Trace("equality") << d_name << "::eq::getExplanation(): due to constants, explain the constants" << std::endl;
    1581         [ +  - ]:      41040 :               Trace("equality") << push;
    1582                 :            : 
    1583                 :            :               // Get the node we interpreted
    1584                 :      82080 :               TNode interpreted;
    1585         [ +  + ]:      41040 :               if (eqpc)
    1586                 :            :               {
    1587                 :            :                 // build the conclusion f(c1, ..., cn) = c
    1588         [ +  + ]:      18364 :                 if (d_nodes[currentNode].isConst())
    1589                 :            :                 {
    1590                 :       7779 :                   interpreted = d_nodes[edgeNode];
    1591                 :       7779 :                   eqpc->d_node = d_nodes[edgeNode].eqNode(d_nodes[currentNode]);
    1592                 :            :                 }
    1593                 :            :                 else
    1594                 :            :                 {
    1595                 :      10585 :                   interpreted = d_nodes[currentNode];
    1596                 :      10585 :                   eqpc->d_node = d_nodes[currentNode].eqNode(d_nodes[edgeNode]);
    1597                 :            :                 }
    1598                 :            :               }
    1599                 :            :               else
    1600                 :            :               {
    1601                 :      22676 :                 interpreted = d_nodes[currentNode].isConst()
    1602                 :       8494 :                                   ? d_nodes[edgeNode]
    1603         [ +  + ]:      31170 :                                   : d_nodes[currentNode];
    1604                 :            :               }
    1605                 :            : 
    1606                 :            :               // Explain why a is a constant by explaining each argument
    1607         [ +  + ]:     122060 :               for (unsigned i = 0; i < interpreted.getNumChildren(); ++ i) {
    1608                 :      81020 :                 EqualityNodeId childId = getNodeId(interpreted[i]);
    1609 [ -  + ][ -  + ]:      81020 :                 Assert(isConstant(childId));
                 [ -  - ]
    1610                 :            :                 std::shared_ptr<EqProof> eqpcc =
    1611         [ +  + ]:     162040 :                     eqpc ? std::make_shared<EqProof>() : nullptr;
    1612                 :     162040 :                 getExplanation(childId,
    1613                 :      81020 :                                getEqualityNode(childId).getFind(),
    1614                 :            :                                equalities,
    1615                 :            :                                cache,
    1616                 :            :                                eqpcc.get());
    1617         [ +  + ]:      81020 :                 if( eqpc ) {
    1618                 :      36854 :                   eqpc->d_children.push_back( eqpcc );
    1619         [ -  + ]:      36854 :                   if (TraceIsOn("pf::ee"))
    1620                 :            :                   {
    1621         [ -  - ]:          0 :                     Trace("pf::ee")
    1622                 :          0 :                         << "MERGED_THROUGH_CONSTANTS. Dumping the child proof"
    1623                 :          0 :                         << std::endl;
    1624                 :          0 :                     eqpc->debug_print("pf::ee", 1);
    1625                 :            :                   }
    1626                 :            :                 }
    1627                 :            :               }
    1628                 :            : 
    1629         [ +  - ]:      41040 :               Trace("equality") << pop;
    1630                 :      41040 :               break;
    1631                 :            :             }
    1632                 :            : 
    1633                 :    3534000 :             default: {
    1634                 :            :               // Construct the equality
    1635         [ +  - ]:    7068000 :               Trace("equality") << d_name << "::eq::getExplanation(): adding: "
    1636                 :    3534000 :                                 << reason << std::endl;
    1637         [ +  - ]:    7068000 :               Trace("equality")
    1638                 :          0 :                   << d_name
    1639                 :          0 :                   << "::eq::getExplanation(): reason type = " << reasonType
    1640                 :    3534000 :                   << "\n";
    1641                 :    7068000 :               Node a = d_nodes[currentNode];
    1642                 :    7068000 :               Node b = d_nodes[d_equalityEdges[currentEdge].getNodeId()];
    1643                 :            : 
    1644         [ +  + ]:    3534000 :               if (eqpc) {
    1645         [ +  - ]:    1629480 :                 if (reasonType == MERGED_THROUGH_EQUALITY) {
    1646                 :            :                   // in the new proof infrastructure we can assume that "theory
    1647                 :            :                   // assumptions", which are a consequence of theory reasoning
    1648                 :            :                   // on other assumptions, are externally justified. In this
    1649                 :            :                   // case we can use (= a b) directly as the conclusion here.
    1650                 :    1629480 :                   eqpc->d_node = b.eqNode(a);
    1651                 :            :                 } else {
    1652                 :            :                   // The LFSC translator prefers (not (= a b)) over (= (= a b) false)
    1653                 :            : 
    1654         [ -  - ]:          0 :                   if (a == nodeManager()->mkConst(false))
    1655                 :            :                   {
    1656                 :          0 :                     eqpc->d_node = b.notNode();
    1657                 :            :                   }
    1658         [ -  - ]:          0 :                   else if (b == nodeManager()->mkConst(false))
    1659                 :            :                   {
    1660                 :          0 :                     eqpc->d_node = a.notNode();
    1661                 :            :                   }
    1662                 :            :                   else
    1663                 :            :                   {
    1664                 :          0 :                     eqpc->d_node = b.eqNode(a);
    1665                 :            :                   }
    1666                 :            :                 }
    1667                 :    1629480 :                 eqpc->d_id = reasonType;
    1668                 :            :               }
    1669                 :    3534000 :               equalities.push_back(reason);
    1670                 :    3534000 :               break;
    1671                 :            :             }
    1672                 :            :             }
    1673                 :            : 
    1674                 :            :             // Go to the previous
    1675                 :    7438320 :             currentEdge = bfsQueue[currentIndex].d_edgeId;
    1676                 :    7438320 :             currentIndex = bfsQueue[currentIndex].d_previousIndex;
    1677                 :            : 
    1678                 :            :             //---from Morgan---
    1679 [ +  + ][ +  + ]:    7438320 :             if (eqpc != NULL && eqpc->d_id == MERGED_THROUGH_REFLEXIVITY) {
                 [ +  + ]
    1680         [ +  - ]:       8433 :               if(eqpc->d_node.isNull()) {
    1681 [ -  + ][ -  + ]:       8433 :                 Assert(eqpc->d_children.size() == 1);
                 [ -  - ]
    1682                 :      16866 :                 std::shared_ptr<EqProof> p = eqpc;
    1683                 :       8433 :                 eqpc = p->d_children[0];
    1684                 :            :               } else {
    1685                 :          0 :                 Assert(eqpc->d_children.empty());
    1686                 :            :               }
    1687                 :            :             }
    1688                 :            :             //---end from Morgan---
    1689                 :            : 
    1690                 :    7438320 :             eqp_trans.push_back(eqpc);
    1691         [ +  + ]:    7438320 :           } while (currentEdge != null_id);
    1692                 :            : 
    1693         [ +  + ]:    3346740 :           if (eqp) {
    1694         [ +  + ]:    1585330 :             if(eqp_trans.size() == 1) {
    1695                 :     584327 :               *eqp = *eqp_trans[0];
    1696                 :            :             } else {
    1697                 :    1001000 :               eqp->d_id = MERGED_THROUGH_TRANS;
    1698                 :    1001000 :               eqp->d_children.insert( eqp->d_children.end(), eqp_trans.begin(), eqp_trans.end() );
    1699                 :            :               // build conclusion in case of equality between non-internal
    1700                 :            :               // nodes or of n-ary congruence kinds, otherwise leave as
    1701                 :            :               // null. The latter is necessary for the overall handling of
    1702                 :            :               // congruence proofs involving n-ary kinds, see
    1703                 :            :               // EqProof::reduceNestedCongruence for more details.
    1704                 :    1001000 :               buildEqConclusion(t1Id, t2Id, eqp);
    1705                 :            :             }
    1706         [ -  + ]:    1585330 :             if (TraceIsOn("pf::ee"))
    1707                 :            :             {
    1708                 :          0 :               eqp->debug_print("pf::ee", 1);
    1709                 :            :             }
    1710                 :            :           }
    1711                 :            : 
    1712                 :            :           // Done
    1713                 :    3346740 :           return;
    1714                 :            :         }
    1715                 :            : 
    1716                 :            :         // Push to the visitation queue if it's not the backward edge
    1717                 :   33485700 :         bfsQueue.push_back(BfsData(edge.getNodeId(), currentEdge, currentIndex));
    1718                 :            :       }
    1719                 :            : 
    1720                 :            :       // Go to the next edge
    1721                 :   49754100 :       currentEdge = edge.getNext();
    1722                 :            :     }
    1723                 :            : 
    1724                 :            :     // Go to the next node to visit
    1725                 :   17225000 :     ++ currentIndex;
    1726                 :   17225000 :   }
    1727                 :            : }
    1728                 :            : 
    1729                 :    1750190 : void EqualityEngine::addTriggerEquality(TNode eq) {
    1730 [ -  + ][ -  + ]:    1750190 :   Assert(eq.getKind() == Kind::EQUAL);
                 [ -  - ]
    1731                 :            : 
    1732         [ +  + ]:    1750190 :   if (d_done) {
    1733                 :         25 :     return;
    1734                 :            :   }
    1735                 :            : 
    1736                 :            :   // Add the terms
    1737                 :    1750170 :   addTermInternal(eq[0]);
    1738                 :    1750170 :   addTermInternal(eq[1]);
    1739                 :            : 
    1740                 :    1750170 :   bool skipTrigger = false;
    1741                 :            : 
    1742                 :            :   // If they are equal or disequal already, no need for the trigger
    1743         [ +  + ]:    1750170 :   if (areEqual(eq[0], eq[1])) {
    1744                 :      48747 :     d_notify->eqNotifyTriggerPredicate(eq, true);
    1745                 :      48747 :     skipTrigger = true;
    1746                 :            :   }
    1747         [ +  + ]:    1750170 :   if (areDisequal(eq[0], eq[1], true)) {
    1748                 :      24696 :     d_notify->eqNotifyTriggerPredicate(eq, false);
    1749                 :      24696 :     skipTrigger = true;
    1750                 :            :   }
    1751                 :            : 
    1752         [ +  + ]:    1750170 :   if (skipTrigger) {
    1753                 :      73443 :     return;
    1754                 :            :   }
    1755                 :            : 
    1756                 :            :   // Add the equality
    1757                 :    1676720 :   addTermInternal(eq);
    1758                 :            : 
    1759                 :            :   // Positive trigger
    1760                 :    1676720 :   addTriggerEqualityInternal(eq[0], eq[1], eq, true);
    1761                 :            :   // Negative trigger
    1762                 :    1676720 :   addTriggerEqualityInternal(eq, d_false, eq, false);
    1763                 :            : }
    1764                 :            : 
    1765                 :    2000640 : void EqualityEngine::addTriggerPredicate(TNode predicate) {
    1766 [ -  + ][ -  + ]:    2000640 :   Assert(predicate.getKind() != Kind::NOT);
                 [ -  - ]
    1767         [ +  + ]:    2000640 :   if (predicate.getKind() == Kind::EQUAL)
    1768                 :            :   {
    1769                 :            :     // equality is handled separately
    1770                 :    1750190 :     return addTriggerEquality(predicate);
    1771                 :            :   }
    1772 [ -  + ][ -  + ]:     250450 :   Assert(d_congruenceKinds.test(predicate.getKind()))
                 [ -  - ]
    1773                 :          0 :       << "No point in adding non-congruence predicates, kind is "
    1774                 :            :       << predicate.getKind();
    1775                 :            : 
    1776         [ +  + ]:     250450 :   if (d_done) {
    1777                 :         92 :     return;
    1778                 :            :   }
    1779                 :            : 
    1780                 :            :   // Add the term
    1781                 :     250358 :   addTermInternal(predicate);
    1782                 :            : 
    1783                 :     250358 :   bool skipTrigger = false;
    1784                 :            : 
    1785                 :            :   // If it's know already, no need for the trigger
    1786         [ +  + ]:     250358 :   if (areEqual(predicate, d_true)) {
    1787                 :      17826 :     d_notify->eqNotifyTriggerPredicate(predicate, true);
    1788                 :      17826 :     skipTrigger = true;
    1789                 :            :   }
    1790         [ +  + ]:     250358 :   if (areEqual(predicate, d_false)) {
    1791                 :       5255 :     d_notify->eqNotifyTriggerPredicate(predicate, false);
    1792                 :       5255 :     skipTrigger = true;
    1793                 :            :   }
    1794                 :            : 
    1795         [ +  + ]:     250358 :   if (skipTrigger) {
    1796                 :      23081 :     return;
    1797                 :            :   }
    1798                 :            : 
    1799                 :            :   // Positive trigger
    1800                 :     227277 :   addTriggerEqualityInternal(predicate, d_true, predicate, true);
    1801                 :            :   // Negative trigger
    1802                 :     227277 :   addTriggerEqualityInternal(predicate, d_false, predicate, false);
    1803                 :            : }
    1804                 :            : 
    1805                 :    3808000 : void EqualityEngine::addTriggerEqualityInternal(TNode t1, TNode t2, TNode trigger, bool polarity) {
    1806                 :            : 
    1807         [ +  - ]:    3808000 :   Trace("equality") << d_name << "::eq::addTrigger(" << t1 << ", " << t2 << ", " << trigger << ")" << std::endl;
    1808                 :            : 
    1809 [ -  + ][ -  + ]:    3808000 :   Assert(hasTerm(t1));
                 [ -  - ]
    1810 [ -  + ][ -  + ]:    3808000 :   Assert(hasTerm(t2));
                 [ -  - ]
    1811                 :            : 
    1812         [ -  + ]:    3808000 :   if (d_done) {
    1813                 :          0 :     return;
    1814                 :            :   }
    1815                 :            : 
    1816                 :            :   // Get the information about t1
    1817                 :    3808000 :   EqualityNodeId t1Id = getNodeId(t1);
    1818                 :    3808000 :   EqualityNodeId t1classId = getEqualityNode(t1Id).getFind();
    1819                 :            :   // We will attach it to the class representative, since then we know how to backtrack it
    1820                 :    3808000 :   TriggerId t1TriggerId = d_nodeTriggers[t1classId];
    1821                 :            : 
    1822                 :            :   // Get the information about t2
    1823                 :    3808000 :   EqualityNodeId t2Id = getNodeId(t2);
    1824                 :    3808000 :   EqualityNodeId t2classId = getEqualityNode(t2Id).getFind();
    1825                 :            :   // We will attach it to the class representative, since then we know how to backtrack it
    1826                 :    3808000 :   TriggerId t2TriggerId = d_nodeTriggers[t2classId];
    1827                 :            : 
    1828         [ +  - ]:    3808000 :   Trace("equality") << d_name << "::eq::addTrigger(" << trigger << "): " << t1Id << " (" << t1classId << ") = " << t2Id << " (" << t2classId << ")" << std::endl;
    1829                 :            : 
    1830                 :            :   // Create the triggers
    1831                 :    3808000 :   TriggerId t1NewTriggerId = d_equalityTriggers.size();
    1832                 :    3808000 :   d_equalityTriggers.push_back(Trigger(t1classId, t1TriggerId));
    1833                 :    3808000 :   d_equalityTriggersOriginal.push_back(TriggerInfo(trigger, polarity));
    1834                 :    3808000 :   TriggerId t2NewTriggerId = d_equalityTriggers.size();
    1835                 :    3808000 :   d_equalityTriggers.push_back(Trigger(t2classId, t2TriggerId));
    1836                 :    3808000 :   d_equalityTriggersOriginal.push_back(TriggerInfo(trigger, polarity));
    1837                 :            : 
    1838                 :            :   // Update the counters
    1839                 :    3808000 :   d_equalityTriggersCount = d_equalityTriggers.size();
    1840 [ -  + ][ -  + ]:    3808000 :   Assert(d_equalityTriggers.size() == d_equalityTriggersOriginal.size());
                 [ -  - ]
    1841 [ -  + ][ -  + ]:    3808000 :   Assert(d_equalityTriggers.size() % 2 == 0);
                 [ -  - ]
    1842                 :            : 
    1843                 :            :   // Add the trigger to the trigger graph
    1844                 :    3808000 :   d_nodeTriggers[t1classId] = t1NewTriggerId;
    1845                 :    3808000 :   d_nodeTriggers[t2classId] = t2NewTriggerId;
    1846                 :            : 
    1847         [ -  + ]:    3808000 :   if (TraceIsOn("equality::internal")) {
    1848                 :          0 :     debugPrintGraph();
    1849                 :            :   }
    1850                 :            : 
    1851         [ +  - ]:    3808000 :   Trace("equality") << d_name << "::eq::addTrigger(" << t1 << "," << t2 << ") => (" << t1NewTriggerId << ", " << t2NewTriggerId << ")" << std::endl;
    1852                 :            : }
    1853                 :            : 
    1854                 :     850452 : Node EqualityEngine::evaluateTerm(TNode node) {
    1855         [ +  - ]:     850452 :   Trace("equality::evaluation") << d_name << "::eq::evaluateTerm(" << node << ")" << std::endl;
    1856                 :    1700900 :   NodeBuilder builder(nodeManager());
    1857                 :     850452 :   builder << node.getKind();
    1858         [ -  + ]:     850452 :   if (node.getMetaKind() == kind::metakind::PARAMETERIZED) {
    1859                 :          0 :     builder << node.getOperator();
    1860                 :            :   }
    1861         [ +  + ]:    2022700 :   for (unsigned i = 0; i < node.getNumChildren(); ++ i) {
    1862                 :    2344510 :     TNode child = node[i];
    1863                 :    1172250 :     TNode childRep = getRepresentative(child);
    1864         [ +  - ]:    1172250 :     Trace("equality::evaluation") << d_name << "::eq::evaluateTerm: " << child << " -> " << childRep << std::endl;
    1865 [ -  + ][ -  + ]:    1172250 :     Assert(childRep.isConst());
                 [ -  - ]
    1866                 :    1172250 :     builder << childRep;
    1867                 :            :   }
    1868                 :     850452 :   Node newNode = builder;
    1869                 :    1700900 :   return d_env.getRewriter()->rewrite(newNode);
    1870                 :            : }
    1871                 :            : 
    1872                 :     507659 : void EqualityEngine::processEvaluationQueue() {
    1873                 :            : 
    1874         [ +  - ]:     507659 :   Trace("equality::evaluation") << d_name << "::eq::processEvaluationQueue(): start" << std::endl;
    1875                 :            : 
    1876         [ +  + ]:    1358110 :   while (!d_evaluationQueue.empty()) {
    1877                 :            :     // Get the node
    1878                 :     850452 :     EqualityNodeId id = d_evaluationQueue.front();
    1879                 :     850452 :     d_evaluationQueue.pop();
    1880                 :            : 
    1881                 :            :     // Replace the children with their representatives (must be constants)
    1882                 :     850452 :     Node nodeEvaluated = evaluateTerm(d_nodes[id]);
    1883         [ +  - ]:     850452 :     Trace("equality::evaluation") << d_name << "::eq::processEvaluationQueue(): " << d_nodes[id] << " evaluates to " << nodeEvaluated << std::endl;
    1884 [ -  + ][ -  + ]:     850452 :     Assert(nodeEvaluated.isConst());
                 [ -  - ]
    1885                 :     850452 :     addTermInternal(nodeEvaluated);
    1886                 :     850452 :     EqualityNodeId nodeEvaluatedId = getNodeId(nodeEvaluated);
    1887                 :            : 
    1888                 :            :     // Enqueue the semantic equality
    1889                 :     850452 :     enqueue(MergeCandidate(id, nodeEvaluatedId, MERGED_THROUGH_CONSTANTS, TNode::null()));
    1890                 :            :   }
    1891                 :            : 
    1892         [ +  - ]:     507659 :   Trace("equality::evaluation") << d_name << "::eq::processEvaluationQueue(): done" << std::endl;
    1893                 :     507659 : }
    1894                 :            : 
    1895                 :   85199100 : void EqualityEngine::propagate() {
    1896                 :            : 
    1897         [ +  + ]:   85199100 :   if (d_inPropagate) {
    1898                 :            :     // We're already in propagate, go back
    1899                 :      46185 :     return;
    1900                 :            :   }
    1901                 :            : 
    1902                 :            :   // Make sure we don't get in again
    1903                 :  170306000 :   ScopedBool inPropagate(d_inPropagate, true);
    1904                 :            : 
    1905         [ +  - ]:   85152900 :   Trace("equality") << d_name << "::eq::propagate()" << std::endl;
    1906                 :            : 
    1907 [ +  + ][ +  + ]:  185996000 :   while (!d_propagationQueue.empty() || !d_evaluationQueue.empty()) {
                 [ +  + ]
    1908                 :            : 
    1909         [ +  + ]:  100844000 :     if (d_done) {
    1910                 :            :       // If we're done, just empty the queue
    1911         [ +  + ]:    7657490 :       while (!d_propagationQueue.empty()) d_propagationQueue.pop_front();
    1912         [ +  + ]:     174751 :       while (!d_evaluationQueue.empty()) d_evaluationQueue.pop();
    1913                 :   12308300 :       continue;
    1914                 :            :     }
    1915                 :            : 
    1916                 :            :     // Process any evaluation requests
    1917         [ +  + ]:  100677000 :     if (!d_evaluationQueue.empty()) {
    1918                 :     507659 :       processEvaluationQueue();
    1919                 :     507659 :       continue;
    1920                 :            :     }
    1921                 :            : 
    1922                 :            :     // The current merge candidate
    1923                 :  100169000 :     const MergeCandidate current = d_propagationQueue.front();
    1924                 :  100169000 :     d_propagationQueue.pop_front();
    1925                 :            : 
    1926                 :            :     // Get the representatives
    1927                 :  100169000 :     EqualityNodeId t1classId = getEqualityNode(current.d_t1Id).getFind();
    1928                 :  100169000 :     EqualityNodeId t2classId = getEqualityNode(current.d_t2Id).getFind();
    1929                 :            : 
    1930                 :            :     // If already the same, we're done
    1931         [ +  + ]:  100169000 :     if (t1classId == t2classId) {
    1932                 :   11574000 :       continue;
    1933                 :            :     }
    1934                 :            : 
    1935 [ +  - ][ -  - ]:   88595200 :     Trace("equality::internal") << d_name << "::eq::propagate(): t1: " << (d_isInternal[t1classId] ? "internal" : "proper") << std::endl;
    1936 [ +  - ][ -  - ]:   88595200 :     Trace("equality::internal") << d_name << "::eq::propagate(): t2: " << (d_isInternal[t2classId] ? "internal" : "proper") << std::endl;
    1937                 :            : 
    1938                 :            :     // Get the nodes of the representatives
    1939                 :   88595200 :     EqualityNode& node1 = getEqualityNode(t1classId);
    1940                 :   88595200 :     EqualityNode& node2 = getEqualityNode(t2classId);
    1941                 :            : 
    1942 [ -  + ][ -  + ]:   88595200 :     Assert(node1.getFind() == t1classId);
                 [ -  - ]
    1943 [ -  + ][ -  + ]:   88595200 :     Assert(node2.getFind() == t2classId);
                 [ -  - ]
    1944                 :            : 
    1945                 :            :     // Add the actual equality to the equality graph
    1946                 :  177190000 :     addGraphEdge(
    1947                 :   88595200 :         current.d_t1Id, current.d_t2Id, current.d_type, current.d_reason);
    1948                 :            : 
    1949                 :            :     // If constants are being merged we're done
    1950 [ +  + ][ +  + ]:   88595200 :     if (d_isConstant[t1classId] && d_isConstant[t2classId]) {
                 [ +  + ]
    1951                 :            :       // When merging constants we are inconsistent, hence done
    1952                 :      59944 :       d_done = true;
    1953                 :            :       // But in order to keep invariants (edges = 2*equalities) we put an equalities in
    1954                 :            :       // Note that we can explain this merge as we have a graph edge
    1955                 :      59944 :       d_assertedEqualities.push_back(Equality(null_id, null_id));
    1956                 :      59944 :       d_assertedEqualitiesCount = d_assertedEqualitiesCount + 1;
    1957                 :            :       // Notify
    1958                 :      59944 :       d_notify->eqNotifyConstantTermMerge(d_nodes[t1classId],
    1959                 :      59944 :                                          d_nodes[t2classId]);
    1960                 :            :       // Empty the queue and exit
    1961                 :      59944 :       continue;
    1962                 :            :     }
    1963                 :            : 
    1964                 :            :     // Vector to collect the triggered events
    1965                 :  177071000 :     std::vector<TriggerId> triggers;
    1966                 :            : 
    1967                 :            :     // Figure out the merge preference
    1968                 :   88535300 :     EqualityNodeId mergeInto = t1classId;
    1969         [ +  + ]:   88535300 :     if (d_isInternal[t2classId] != d_isInternal[t1classId]) {
    1970                 :            :       // We always keep non-internal nodes as representatives: if any node in
    1971                 :            :       // the class is non-internal, then the representative will be non-internal
    1972         [ +  + ]:      47974 :       if (d_isInternal[t1classId]) {
    1973                 :      24355 :         mergeInto = t2classId;
    1974                 :            :       } else {
    1975                 :      23619 :         mergeInto = t1classId;
    1976                 :            :       }
    1977         [ +  + ]:   88487300 :     } else if (d_isConstant[t2classId] != d_isConstant[t1classId]) {
    1978                 :            :       // We always keep constants as representatives: if any (at most one) node
    1979                 :            :       // in the class in a constant, then the representative will be a constant
    1980         [ +  + ]:   72008500 :       if (d_isConstant[t2classId]) {
    1981                 :   66920400 :         mergeInto = t2classId;
    1982                 :            :       } else {
    1983                 :    5088080 :         mergeInto = t1classId;
    1984                 :            :       }
    1985         [ +  + ]:   16478800 :     } else if (node2.getSize() > node1.getSize()) {
    1986                 :            :       // We always merge into the bigger class to reduce the amount of traversing
    1987                 :            :       // we need to do
    1988                 :    7367450 :       mergeInto = t2classId;
    1989                 :            :     }
    1990                 :            : 
    1991         [ +  + ]:   88535300 :     if (mergeInto == t2classId) {
    1992         [ +  - ]:  148624000 :       Trace("equality") << d_name << "::eq::propagate(): merging "
    1993                 :          0 :                         << d_nodes[current.d_t1Id] << " into "
    1994                 :   74312200 :                         << d_nodes[current.d_t2Id] << std::endl;
    1995                 :   74312200 :       d_assertedEqualities.push_back(Equality(t2classId, t1classId));
    1996                 :   74312200 :       d_assertedEqualitiesCount = d_assertedEqualitiesCount + 1;
    1997         [ +  + ]:   74312200 :       if (!merge(node2, node1, triggers)) {
    1998                 :      13435 :         d_done = true;
    1999                 :            :       }
    2000                 :            :     } else {
    2001         [ +  - ]:   28446200 :       Trace("equality") << d_name << "::eq::propagate(): merging "
    2002                 :          0 :                         << d_nodes[current.d_t2Id] << " into "
    2003                 :   14223100 :                         << d_nodes[current.d_t1Id] << std::endl;
    2004                 :   14223100 :       d_assertedEqualities.push_back(Equality(t1classId, t2classId));
    2005                 :   14223100 :       d_assertedEqualitiesCount = d_assertedEqualitiesCount + 1;
    2006         [ +  + ]:   14223100 :     if (!merge(node1, node2, triggers)) {
    2007                 :      16098 :         d_done = true;
    2008                 :            :       }
    2009                 :            :     }
    2010                 :            : 
    2011                 :            :     // If not merging internal nodes, notify the master
    2012 [ +  + ][ +  + ]:   88535300 :     if (d_masterEqualityEngine && !d_isInternal[t1classId] && !d_isInternal[t2classId]) {
         [ +  + ][ +  + ]
    2013                 :   14533600 :       d_masterEqualityEngine->assertEqualityInternal(d_nodes[t1classId], d_nodes[t2classId], TNode::null());
    2014                 :   14533600 :       d_masterEqualityEngine->propagate();
    2015                 :            :     }
    2016                 :            : 
    2017                 :            :     // Notify the triggers
    2018         [ +  + ]:   88535300 :     if (!d_done)
    2019                 :            :     {
    2020 [ +  + ][ +  + ]:  111301000 :       for (size_t trigger_i = 0, trigger_end = triggers.size(); trigger_i < trigger_end && !d_done; ++ trigger_i) {
                 [ +  + ]
    2021                 :   22795200 :         const TriggerInfo& triggerInfo = d_equalityTriggersOriginal[triggers[trigger_i]];
    2022         [ +  + ]:   22795200 :         if (triggerInfo.d_trigger.getKind() == Kind::EQUAL)
    2023                 :            :         {
    2024                 :            :           // Special treatment for disequalities
    2025         [ +  + ]:   19051500 :           if (!triggerInfo.d_polarity)
    2026                 :            :           {
    2027                 :            :             // Store that we are propagating a diseauality
    2028                 :   21761800 :             TNode equality = triggerInfo.d_trigger;
    2029                 :   10880900 :             EqualityNodeId original = getNodeId(equality);
    2030                 :   21761800 :             TNode lhs = equality[0];
    2031                 :   21761800 :             TNode rhs = equality[1];
    2032                 :   10880900 :             EqualityNodeId lhsId = getNodeId(lhs);
    2033                 :   10880900 :             EqualityNodeId rhsId = getNodeId(rhs);
    2034                 :            :             // We use the THEORY_LAST as a marker for "marked as propagated, reasons stored".
    2035                 :            :             // This tag is added to an internal theories set that is only inserted in, so this is
    2036                 :            :             // safe. Had we iterated over, or done other set operations this might be dangerous.
    2037         [ +  + ]:   10880900 :             if (!hasPropagatedDisequality(THEORY_LAST, lhsId, rhsId)) {
    2038         [ +  + ]:   10880400 :               if (!hasPropagatedDisequality(lhsId, rhsId)) {
    2039                 :   10844800 :                 d_deducedDisequalityReasons.push_back(EqualityPair(original, d_falseId));
    2040                 :            :               }
    2041                 :   10880400 :               storePropagatedDisequality(THEORY_LAST, lhsId, rhsId);
    2042         [ +  + ]:   10880400 :               if (!d_notify->eqNotifyTriggerPredicate(triggerInfo.d_trigger,
    2043                 :   10880400 :                                                      triggerInfo.d_polarity))
    2044                 :            :               {
    2045                 :       1337 :                 d_done = true;
    2046                 :            :               }
    2047                 :            :             }
    2048                 :            :           }
    2049                 :            :           else
    2050                 :            :           {
    2051                 :            :             // Equalities are simple
    2052         [ +  + ]:    8170600 :             if (!d_notify->eqNotifyTriggerPredicate(triggerInfo.d_trigger,
    2053                 :    8170600 :                                                    triggerInfo.d_polarity))
    2054                 :            :             {
    2055                 :     103133 :               d_done = true;
    2056                 :            :             }
    2057                 :            :           }
    2058                 :            :         }
    2059                 :            :         else
    2060                 :            :         {
    2061         [ +  + ]:    3743720 :           if (!d_notify->eqNotifyTriggerPredicate(triggerInfo.d_trigger,
    2062                 :    3743720 :                                                  triggerInfo.d_polarity))
    2063                 :            :           {
    2064                 :       3347 :             d_done = true;
    2065                 :            :           }
    2066                 :            :         }
    2067                 :            :       }
    2068                 :            :     }
    2069                 :            :   }
    2070                 :            : }
    2071                 :            : 
    2072                 :          0 : void EqualityEngine::debugPrintGraph() const
    2073                 :            : {
    2074         [ -  - ]:          0 :   Trace("equality::internal") << std::endl << "Dumping graph" << std::endl;
    2075         [ -  - ]:          0 :   for (EqualityNodeId nodeId = 0; nodeId < d_nodes.size(); ++nodeId)
    2076                 :            :   {
    2077         [ -  - ]:          0 :     Trace("equality::internal") << d_nodes[nodeId] << " " << nodeId << "("
    2078                 :          0 :                                 << getEqualityNode(nodeId).getFind() << "):";
    2079                 :            : 
    2080                 :          0 :     EqualityEdgeId edgeId = d_equalityGraph[nodeId];
    2081         [ -  - ]:          0 :     while (edgeId != null_edge)
    2082                 :            :     {
    2083                 :          0 :       const EqualityEdge& edge = d_equalityEdges[edgeId];
    2084         [ -  - ]:          0 :       Trace("equality::internal")
    2085                 :          0 :           << " [" << edge.getNodeId() << "] " << d_nodes[edge.getNodeId()]
    2086                 :          0 :           << ":" << edge.getReason();
    2087                 :          0 :       edgeId = edge.getNext();
    2088                 :            :     }
    2089                 :            : 
    2090         [ -  - ]:          0 :     Trace("equality::internal") << std::endl;
    2091                 :            :   }
    2092         [ -  - ]:          0 :   Trace("equality::internal") << std::endl;
    2093                 :          0 : }
    2094                 :            : 
    2095                 :          0 : std::string EqualityEngine::debugPrintEqc() const
    2096                 :            : {
    2097                 :          0 :   std::stringstream ss;
    2098                 :          0 :   eq::EqClassesIterator eqcs2_i = eq::EqClassesIterator(this);
    2099         [ -  - ]:          0 :   while (!eqcs2_i.isFinished())
    2100                 :            :   {
    2101                 :          0 :     Node eqc = (*eqcs2_i);
    2102                 :          0 :     eq::EqClassIterator eqc2_i = eq::EqClassIterator(eqc, this);
    2103                 :          0 :     ss << "Eqc( " << eqc << " ) : { ";
    2104         [ -  - ]:          0 :     while (!eqc2_i.isFinished())
    2105                 :            :     {
    2106                 :          0 :       if ((*eqc2_i) != eqc && (*eqc2_i).getKind() != Kind::EQUAL)
    2107                 :            :       {
    2108                 :          0 :         ss << (*eqc2_i) << " ";
    2109                 :            :       }
    2110                 :          0 :       ++eqc2_i;
    2111                 :            :     }
    2112                 :          0 :     ss << " } " << std::endl;
    2113                 :          0 :     ++eqcs2_i;
    2114                 :            :   }
    2115                 :          0 :   return ss.str();
    2116                 :            : }
    2117                 :            : 
    2118                 :   78869200 : bool EqualityEngine::areEqual(TNode t1, TNode t2) const {
    2119         [ +  - ]:   78869200 :   Trace("equality") << d_name << "::eq::areEqual(" << t1 << "," << t2 << ")";
    2120                 :            : 
    2121 [ -  + ][ -  + ]:   78869200 :   Assert(hasTerm(t1));
                 [ -  - ]
    2122 [ -  + ][ -  + ]:   78869200 :   Assert(hasTerm(t2));
                 [ -  - ]
    2123                 :            : 
    2124                 :   78869200 :   bool result = getEqualityNode(t1).getFind() == getEqualityNode(t2).getFind();
    2125 [ +  - ][ -  - ]:   78869200 :   Trace("equality") << (result ? "\t(YES)" : "\t(NO)") << std::endl;
    2126                 :   78869200 :   return result;
    2127                 :            : }
    2128                 :            : 
    2129                 :   22644300 : bool EqualityEngine::areDisequal(TNode t1, TNode t2, bool ensureProof) const
    2130                 :            : {
    2131         [ +  - ]:   22644300 :   Trace("equality") << d_name << "::eq::areDisequal(" << t1 << "," << t2 << ")";
    2132                 :            : 
    2133                 :            :   // Add the terms
    2134 [ -  + ][ -  + ]:   22644300 :   Assert(hasTerm(t1));
                 [ -  - ]
    2135 [ -  + ][ -  + ]:   22644300 :   Assert(hasTerm(t2));
                 [ -  - ]
    2136                 :            : 
    2137                 :            :   // Get ids
    2138                 :   22644300 :   EqualityNodeId t1Id = getNodeId(t1);
    2139                 :   22644300 :   EqualityNodeId t2Id = getNodeId(t2);
    2140                 :            : 
    2141                 :            :   // If we propagated this disequality we're true
    2142         [ +  + ]:   22644300 :   if (hasPropagatedDisequality(t1Id, t2Id)) {
    2143         [ +  - ]:    7032400 :     Trace("equality") << "\t(YES)" << std::endl;
    2144                 :    7032400 :     return true;
    2145                 :            :   }
    2146                 :            : 
    2147                 :            :   // Get equivalence classes
    2148                 :   15611900 :   EqualityNodeId t1ClassId = getEqualityNode(t1Id).getFind();
    2149                 :   15611900 :   EqualityNodeId t2ClassId = getEqualityNode(t2Id).getFind();
    2150                 :            : 
    2151                 :            :   // We are semantically const, for remembering stuff
    2152                 :   15611900 :   EqualityEngine* nonConst = const_cast<EqualityEngine*>(this);
    2153                 :            : 
    2154                 :            :   // Check for constants
    2155 [ +  + ][ +  + ]:   15611900 :   if (d_isConstant[t1ClassId] && d_isConstant[t2ClassId] && t1ClassId != t2ClassId) {
         [ +  + ][ +  + ]
    2156         [ +  + ]:     118884 :     if (ensureProof) {
    2157                 :      14501 :       nonConst->d_deducedDisequalityReasons.push_back(EqualityPair(t1Id, t1ClassId));
    2158                 :      14501 :       nonConst->d_deducedDisequalityReasons.push_back(EqualityPair(t2Id, t2ClassId));
    2159                 :      14501 :       nonConst->storePropagatedDisequality(THEORY_LAST, t1Id, t2Id);
    2160                 :            :     }
    2161         [ +  - ]:     118884 :     Trace("equality") << "\t(YES)" << std::endl;
    2162                 :     118884 :     return true;
    2163                 :            :   }
    2164                 :            : 
    2165                 :            :   // Create the equality
    2166                 :   15493000 :   FunctionApplication eqNormalized(APP_EQUALITY, t1ClassId, t2ClassId);
    2167                 :   15493000 :   ApplicationIdsMap::const_iterator find = d_applicationLookup.find(eqNormalized);
    2168         [ +  + ]:   15493000 :   if (find != d_applicationLookup.end()) {
    2169         [ +  + ]:    6322300 :     if (getEqualityNode(find->second).getFind() == getEqualityNode(d_falseId).getFind()) {
    2170         [ +  + ]:     770383 :       if (ensureProof) {
    2171                 :            :         const FunctionApplication original =
    2172                 :       8542 :             d_applications[find->second].d_original;
    2173                 :       8542 :         nonConst->d_deducedDisequalityReasons.push_back(
    2174                 :       8542 :             EqualityPair(t1Id, original.d_a));
    2175                 :       8542 :         nonConst->d_deducedDisequalityReasons.push_back(EqualityPair(find->second, d_falseId));
    2176                 :       8542 :         nonConst->d_deducedDisequalityReasons.push_back(
    2177                 :       8542 :             EqualityPair(t2Id, original.d_b));
    2178                 :       8542 :         nonConst->storePropagatedDisequality(THEORY_LAST, t1Id, t2Id);
    2179                 :            :       }
    2180         [ +  - ]:     770383 :       Trace("equality") << "\t(YES)" << std::endl;
    2181                 :     770383 :       return true;
    2182                 :            :     }
    2183                 :            :   }
    2184                 :            : 
    2185                 :            :   // Check the symmetric disequality
    2186                 :   14722600 :   std::swap(eqNormalized.d_a, eqNormalized.d_b);
    2187                 :   14722600 :   find = d_applicationLookup.find(eqNormalized);
    2188         [ +  + ]:   14722600 :   if (find != d_applicationLookup.end()) {
    2189         [ +  + ]:    1354020 :     if (getEqualityNode(find->second).getFind() == getEqualityNode(d_falseId).getFind()) {
    2190         [ +  + ]:    1076480 :       if (ensureProof) {
    2191                 :            :         const FunctionApplication original =
    2192                 :       4537 :             d_applications[find->second].d_original;
    2193                 :       4537 :         nonConst->d_deducedDisequalityReasons.push_back(
    2194                 :       4537 :             EqualityPair(t2Id, original.d_a));
    2195                 :       4537 :         nonConst->d_deducedDisequalityReasons.push_back(EqualityPair(find->second, d_falseId));
    2196                 :       4537 :         nonConst->d_deducedDisequalityReasons.push_back(
    2197                 :       4537 :             EqualityPair(t1Id, original.d_b));
    2198                 :       4537 :         nonConst->storePropagatedDisequality(THEORY_LAST, t1Id, t2Id);
    2199                 :            :       }
    2200         [ +  - ]:    1076480 :       Trace("equality") << "\t(YES)" << std::endl;
    2201                 :    1076480 :       return true;
    2202                 :            :     }
    2203                 :            :   }
    2204                 :            : 
    2205                 :            :   // Couldn't deduce dis-equalityReturn whether the terms are disequal
    2206         [ +  - ]:   13646200 :   Trace("equality") << "\t(NO)" << std::endl;
    2207                 :   13646200 :   return false;
    2208                 :            : }
    2209                 :            : 
    2210                 :          0 : size_t EqualityEngine::getSize(TNode t) {
    2211                 :            :   // Add the term
    2212                 :          0 :   addTermInternal(t);
    2213                 :          0 :   return getEqualityNode(getEqualityNode(t).getFind()).getSize();
    2214                 :            : }
    2215                 :            : 
    2216                 :     280120 : std::string EqualityEngine::identify() const { return d_name; }
    2217                 :            : 
    2218                 :    8405270 : void EqualityEngine::addTriggerTerm(TNode t, TheoryId tag)
    2219                 :            : {
    2220         [ +  - ]:    8405270 :   Trace("equality::trigger") << d_name << "::eq::addTriggerTerm(" << t << ", " << tag << ")" << std::endl;
    2221                 :            : 
    2222 [ -  + ][ -  + ]:    8405270 :   Assert(tag != THEORY_LAST);
                 [ -  - ]
    2223                 :            : 
    2224         [ +  + ]:    8405270 :   if (d_done) {
    2225                 :          3 :     return;
    2226                 :            :   }
    2227                 :            : 
    2228                 :            :   // Add the term if it's not already there
    2229                 :    8405270 :   addTermInternal(t);
    2230                 :            : 
    2231         [ -  + ]:    8405270 :   if (!d_anyTermsAreTriggers)
    2232                 :            :   {
    2233                 :            :     // if we are not using triggers, we only add the term, but not as a trigger
    2234                 :          0 :     return;
    2235                 :            :   }
    2236                 :            : 
    2237                 :            :   // Get the node id
    2238                 :    8405270 :   EqualityNodeId eqNodeId = getNodeId(t);
    2239                 :    8405270 :   EqualityNode& eqNode = getEqualityNode(eqNodeId);
    2240                 :    8405270 :   EqualityNodeId classId = eqNode.getFind();
    2241                 :            : 
    2242                 :            :   // Possibly existing set of triggers
    2243                 :    8405270 :   TriggerTermSetRef triggerSetRef = d_nodeIndividualTrigger[classId];
    2244 [ +  + ][ +  + ]:    8405270 :   if (triggerSetRef != +null_set_id && getTriggerTermSet(triggerSetRef).hasTrigger(tag)) {
                 [ +  + ]
    2245                 :            :     // If the term already is in the equivalence class that a tagged representative, just notify
    2246                 :    2490930 :     EqualityNodeId triggerId = getTriggerTermSet(triggerSetRef).getTrigger(tag);
    2247         [ +  - ]:    4981860 :     Trace("equality::trigger")
    2248                 :          0 :         << d_name << "::eq::addTriggerTerm(" << t << ", " << tag
    2249                 :          0 :         << "): already have this trigger in class with " << d_nodes[triggerId]
    2250                 :    2490930 :         << std::endl;
    2251                 :    2490930 :     if (eqNodeId != triggerId
    2252                 :    2490930 :         && !notifyTriggerTermEquality(tag, t, d_nodes[triggerId], true))
    2253                 :            :     {
    2254                 :       1872 :       d_done = true;
    2255                 :            :     }
    2256                 :            :   } else {
    2257                 :            : 
    2258                 :            :     // Check for disequalities by going through the equivalence class looking for equalities in the
    2259                 :            :     // uselists that have been asserted to false. All the representatives appearing on the other
    2260                 :            :     // side of such disequalities, that have the tag on, are put in a set.
    2261                 :   11828700 :     TaggedEqualitiesSet disequalitiesToNotify;
    2262                 :    5914340 :     TheoryIdSet tags = TheoryIdSetUtil::setInsert(tag);
    2263                 :    5914340 :     getDisequalities(!d_isConstant[classId], classId, tags, disequalitiesToNotify);
    2264                 :            : 
    2265                 :            :     // Trigger data
    2266                 :            :     TheoryIdSet newSetTags;
    2267                 :            :     EqualityNodeId newSetTriggers[THEORY_LAST];
    2268                 :            :     unsigned newSetTriggersSize;
    2269                 :            : 
    2270                 :            :     // Setup the data for the new set
    2271         [ +  + ]:    5914340 :     if (triggerSetRef != null_set_id) {
    2272                 :            :       // Get the existing set
    2273                 :    1330980 :       TriggerTermSet& triggerSet = getTriggerTermSet(triggerSetRef);
    2274                 :            :       // Initialize the new set for copy/insert
    2275                 :    1330980 :       newSetTags = TheoryIdSetUtil::setInsert(tag, triggerSet.d_tags);
    2276                 :    1330980 :       newSetTriggersSize = 0;
    2277                 :            :       // Copy into to new one, and insert the new tag/id
    2278                 :    1330980 :       unsigned i = 0;
    2279                 :    1330980 :       TheoryIdSet tags2 = newSetTags;
    2280                 :            :       TheoryId current;
    2281         [ +  + ]:    4022150 :       while ((current = TheoryIdSetUtil::setPop(tags2)) != THEORY_LAST)
    2282                 :            :       {
    2283                 :            :         // Remove from the tags
    2284                 :    2691170 :         tags2 = TheoryIdSetUtil::setRemove(current, tags2);
    2285                 :            :         // Insert the id into the triggers
    2286                 :    2691170 :         newSetTriggers[newSetTriggersSize++] =
    2287         [ +  + ]:    2691170 :             current == tag ? eqNodeId : triggerSet.d_triggers[i++];
    2288                 :            :       }
    2289                 :            :     } else {
    2290                 :            :       // Setup a singleton
    2291                 :    4583360 :       newSetTags = TheoryIdSetUtil::setInsert(tag);
    2292                 :    4583360 :       newSetTriggers[0] = eqNodeId;
    2293                 :    4583360 :       newSetTriggersSize = 1;
    2294                 :            :     }
    2295                 :            : 
    2296                 :            :     // Add it to the list for backtracking
    2297                 :    5914340 :     d_triggerTermSetUpdates.push_back(TriggerSetUpdate(classId, triggerSetRef));
    2298                 :    5914340 :     d_triggerTermSetUpdatesSize = d_triggerTermSetUpdatesSize + 1;
    2299                 :            :     // Mark the the new set as a trigger
    2300                 :    5914340 :     d_nodeIndividualTrigger[classId] = triggerSetRef = newTriggerTermSet(newSetTags, newSetTriggers, newSetTriggersSize);
    2301                 :            : 
    2302                 :            :     // Propagate trigger term disequalities we remembered
    2303         [ +  - ]:    5914340 :     Trace("equality::trigger") << d_name << "::eq::addTriggerTerm(" << t << ", " << tag << "): propagating " << disequalitiesToNotify.size() << " disequalities " << std::endl;
    2304                 :    5914340 :     propagateTriggerTermDisequalities(tags, triggerSetRef, disequalitiesToNotify);
    2305                 :            :   }
    2306                 :            : }
    2307                 :            : 
    2308                 :   13787900 : bool EqualityEngine::isTriggerTerm(TNode t, TheoryId tag) const {
    2309         [ +  + ]:   13787900 :   if (!hasTerm(t)) return false;
    2310                 :   13787800 :   EqualityNodeId classId = getEqualityNode(t).getFind();
    2311                 :   13787800 :   TriggerTermSetRef triggerSetRef = d_nodeIndividualTrigger[classId];
    2312 [ +  + ][ +  - ]:   13787800 :   return triggerSetRef != +null_set_id && getTriggerTermSet(triggerSetRef).hasTrigger(tag);
    2313                 :            : }
    2314                 :            : 
    2315                 :            : 
    2316                 :    4820870 : TNode EqualityEngine::getTriggerTermRepresentative(TNode t, TheoryId tag) const {
    2317 [ -  + ][ -  + ]:    4820870 :   Assert(isTriggerTerm(t, tag));
                 [ -  - ]
    2318                 :    4820870 :   EqualityNodeId classId = getEqualityNode(t).getFind();
    2319                 :    4820870 :   const TriggerTermSet& triggerSet = getTriggerTermSet(d_nodeIndividualTrigger[classId]);
    2320                 :    4820870 :   unsigned i = 0;
    2321                 :    4820870 :   TheoryIdSet tags = triggerSet.d_tags;
    2322         [ +  + ]:    8211750 :   while (TheoryIdSetUtil::setPop(tags) != tag)
    2323                 :            :   {
    2324                 :    3390880 :     ++ i;
    2325                 :            :   }
    2326                 :    9641740 :   return d_nodes[triggerSet.d_triggers[i]];
    2327                 :            : }
    2328                 :            : 
    2329                 :   28877500 : void EqualityEngine::storeApplicationLookup(FunctionApplication& funNormalized, EqualityNodeId funId) {
    2330 [ -  + ][ -  + ]:   28877500 :   Assert(d_applicationLookup.find(funNormalized) == d_applicationLookup.end());
                 [ -  - ]
    2331                 :   28877500 :   d_applicationLookup[funNormalized] = funId;
    2332                 :   28877500 :   d_applicationLookups.push_back(funNormalized);
    2333                 :   28877500 :   d_applicationLookupsCount = d_applicationLookupsCount + 1;
    2334         [ +  - ]:   28877500 :   Trace("equality::backtrack") << "d_applicationLookupsCount = " << d_applicationLookupsCount << std::endl;
    2335         [ +  - ]:   28877500 :   Trace("equality::backtrack") << "d_applicationLookups.size() = " << d_applicationLookups.size() << std::endl;
    2336 [ -  + ][ -  + ]:   28877500 :   Assert(d_applicationLookupsCount == d_applicationLookups.size());
                 [ -  - ]
    2337                 :            : 
    2338                 :            :   // If an equality over constants we merge to false
    2339         [ +  + ]:   28877500 :   if (funNormalized.isEquality()) {
    2340         [ +  + ]:   21299900 :     if (funNormalized.d_a == funNormalized.d_b)
    2341                 :            :     {
    2342                 :    2102120 :       enqueue(MergeCandidate(funId, d_trueId, MERGED_THROUGH_REFLEXIVITY, TNode::null()));
    2343                 :            :     }
    2344 [ +  + ][ +  + ]:   19197800 :     else if (d_isConstant[funNormalized.d_a] && d_isConstant[funNormalized.d_b])
                 [ +  + ]
    2345                 :            :     {
    2346                 :    1895710 :       enqueue(MergeCandidate(funId, d_falseId, MERGED_THROUGH_CONSTANTS, TNode::null()));
    2347                 :            :     }
    2348                 :            :   }
    2349                 :   28877500 : }
    2350                 :            : 
    2351                 :   11599300 : EqualityEngine::TriggerTermSetRef EqualityEngine::newTriggerTermSet(
    2352                 :            :     TheoryIdSet newSetTags,
    2353                 :            :     EqualityNodeId* newSetTriggers,
    2354                 :            :     unsigned newSetTriggersSize)
    2355                 :            : {
    2356                 :            :   // Size of the required set
    2357                 :   11599300 :   size_t size = sizeof(TriggerTermSet) + newSetTriggersSize*sizeof(EqualityNodeId);
    2358                 :            :   // Align the size
    2359                 :   11599300 :   size = (size + 7) & ~((size_t)7);
    2360                 :            :   // Reallocate if necessary
    2361         [ -  + ]:   11599300 :   if (d_triggerDatabaseSize + size > d_triggerDatabaseAllocatedSize) {
    2362                 :          0 :     d_triggerDatabaseAllocatedSize *= 2;
    2363                 :          0 :     d_triggerDatabase = (char*) realloc(d_triggerDatabase, d_triggerDatabaseAllocatedSize);
    2364                 :            :   }
    2365                 :            :   // New reference
    2366                 :   11599300 :   TriggerTermSetRef newTriggerSetRef = d_triggerDatabaseSize;
    2367                 :            :   // Update the size
    2368                 :   11599300 :   d_triggerDatabaseSize = d_triggerDatabaseSize + size;
    2369                 :            :   // Copy the information
    2370                 :   11599300 :   TriggerTermSet& newSet = getTriggerTermSet(newTriggerSetRef);
    2371                 :   11599300 :   newSet.d_tags = newSetTags;
    2372         [ +  + ]:   98285700 :   for (unsigned i = 0; i < newSetTriggersSize; ++i) {
    2373                 :   86686400 :     newSet.d_triggers[i] = newSetTriggers[i];
    2374                 :            :   }
    2375                 :            :   // Return the new reference
    2376                 :   11599300 :   return newTriggerSetRef;
    2377                 :            : }
    2378                 :            : 
    2379                 :   37629400 : bool EqualityEngine::hasPropagatedDisequality(EqualityNodeId lhsId, EqualityNodeId rhsId) const {
    2380                 :   37629400 :   EqualityPair eq(lhsId, rhsId);
    2381                 :   37629400 :   bool propagated = d_propagatedDisequalities.find(eq) != d_propagatedDisequalities.end();
    2382                 :            : #ifdef CVC5_ASSERTIONS
    2383                 :   37629400 :   bool stored = d_disequalityReasonsMap.find(eq) != d_disequalityReasonsMap.end();
    2384 [ -  + ][ -  + ]:   37629400 :   Assert(propagated == stored) << "These two should be in sync";
                 [ -  - ]
    2385                 :            : #endif
    2386 [ +  - ][ -  - ]:   37629400 :   Trace("equality::disequality") << d_name << "::eq::hasPropagatedDisequality(" << d_nodes[lhsId] << ", " << d_nodes[rhsId] << ") => " << (propagated ? "true" : "false") << std::endl;
    2387                 :   37629400 :   return propagated;
    2388                 :            : }
    2389                 :            : 
    2390                 :   32260400 : bool EqualityEngine::hasPropagatedDisequality(TheoryId tag, EqualityNodeId lhsId, EqualityNodeId rhsId) const {
    2391                 :            : 
    2392                 :   32260400 :   EqualityPair eq(lhsId, rhsId);
    2393                 :            : 
    2394                 :   32260400 :   PropagatedDisequalitiesMap::const_iterator it = d_propagatedDisequalities.find(eq);
    2395         [ +  + ]:   32260400 :   if (it == d_propagatedDisequalities.end()) {
    2396 [ -  + ][ -  + ]:   25525500 :     Assert(d_disequalityReasonsMap.find(eq) == d_disequalityReasonsMap.end())
                 [ -  - ]
    2397                 :          0 :         << "Why do we have a proof if not propagated";
    2398         [ +  - ]:   25525500 :     Trace("equality::disequality") << d_name << "::eq::hasPropagatedDisequality(" << tag << ", " << d_nodes[lhsId] << ", " << d_nodes[rhsId] << ") => false" << std::endl;
    2399                 :   25525500 :     return false;
    2400                 :            :   }
    2401 [ -  + ][ -  + ]:    6734890 :   Assert(d_disequalityReasonsMap.find(eq) != d_disequalityReasonsMap.end())
                 [ -  - ]
    2402                 :          0 :       << "We propagated but there is no proof";
    2403                 :    6734890 :   bool result = TheoryIdSetUtil::setContains(tag, (*it).second);
    2404 [ +  - ][ -  - ]:    6734890 :   Trace("equality::disequality") << d_name << "::eq::hasPropagatedDisequality(" << tag << ", " << d_nodes[lhsId] << ", " << d_nodes[rhsId] << ") => " << (result ? "true" : "false") << std::endl;
    2405                 :    6734890 :   return result;
    2406                 :            : }
    2407                 :            : 
    2408                 :            : 
    2409                 :   15012600 : void EqualityEngine::storePropagatedDisequality(TheoryId tag, EqualityNodeId lhsId, EqualityNodeId rhsId) {
    2410 [ -  + ][ -  + ]:   15012600 :   Assert(!hasPropagatedDisequality(tag, lhsId, rhsId))
                 [ -  - ]
    2411                 :          0 :       << "Check before you store it";
    2412 [ -  + ][ -  + ]:   15012600 :   Assert(lhsId != rhsId) << "Wow, wtf!";
                 [ -  - ]
    2413                 :            : 
    2414         [ +  - ]:   15012600 :   Trace("equality::disequality") << d_name << "::eq::storePropagatedDisequality(" << tag << ", " << d_nodes[lhsId] << ", " << d_nodes[rhsId] << ")" << std::endl;
    2415                 :            : 
    2416                 :   15012600 :   EqualityPair pair1(lhsId, rhsId);
    2417                 :   15012600 :   EqualityPair pair2(rhsId, lhsId);
    2418                 :            : 
    2419                 :            :   // Store the fact that we've propagated this already
    2420                 :   15012600 :   TheoryIdSet notified = 0;
    2421                 :   15012600 :   PropagatedDisequalitiesMap::const_iterator find = d_propagatedDisequalities.find(pair1);
    2422         [ +  + ]:   15012600 :   if (find == d_propagatedDisequalities.end()) {
    2423                 :   12776500 :     notified = TheoryIdSetUtil::setInsert(tag);
    2424                 :            :   } else {
    2425                 :    2236100 :     notified = TheoryIdSetUtil::setInsert(tag, (*find).second);
    2426                 :            :   }
    2427                 :   15012600 :   d_propagatedDisequalities[pair1] = notified;
    2428                 :   15012600 :   d_propagatedDisequalities[pair2] = notified;
    2429                 :            : 
    2430                 :            :   // Store the proof if provided
    2431         [ +  + ]:   15012600 :   if (d_deducedDisequalityReasons.size() > d_deducedDisequalityReasonsSize) {
    2432         [ +  - ]:   12776500 :     Trace("equality::disequality") << d_name << "::eq::storePropagatedDisequality(" << tag << ", " << d_nodes[lhsId] << ", " << d_nodes[rhsId] << "): storing proof" << std::endl;
    2433 [ -  + ][ -  + ]:   12776500 :     Assert(d_disequalityReasonsMap.find(pair1) == d_disequalityReasonsMap.end())
                 [ -  - ]
    2434                 :          0 :         << "There can't be a proof if you're adding a new one";
    2435                 :   12776500 :     DisequalityReasonRef ref(d_deducedDisequalityReasonsSize, d_deducedDisequalityReasons.size());
    2436                 :            : #ifdef CVC5_ASSERTIONS
    2437                 :            :     // Check that the reasons are valid
    2438         [ +  + ]:   29402200 :     for (unsigned i = ref.d_mergesStart; i < ref.d_mergesEnd; ++i)
    2439                 :            :     {
    2440 [ -  + ][ -  + ]:   16625600 :       Assert(
                 [ -  - ]
    2441                 :            :           getEqualityNode(d_deducedDisequalityReasons[i].first).getFind()
    2442                 :            :           == getEqualityNode(d_deducedDisequalityReasons[i].second).getFind());
    2443                 :            :     }
    2444                 :            : #endif
    2445         [ -  + ]:   12776500 :     if (TraceIsOn("equality::disequality")) {
    2446         [ -  - ]:          0 :       for (unsigned i = ref.d_mergesStart; i < ref.d_mergesEnd; ++i)
    2447                 :            :       {
    2448                 :          0 :         TNode lhs = d_nodes[d_deducedDisequalityReasons[i].first];
    2449                 :          0 :         TNode rhs = d_nodes[d_deducedDisequalityReasons[i].second];
    2450         [ -  - ]:          0 :         Trace("equality::disequality") << d_name << "::eq::storePropagatedDisequality(): because " << lhs << " == " << rhs << std::endl;
    2451                 :            :       }
    2452                 :            :     }
    2453                 :            : 
    2454                 :            :     // Store for backtracking
    2455                 :   12776500 :     d_deducedDisequalities.push_back(pair1);
    2456                 :   12776500 :     d_deducedDisequalitiesSize = d_deducedDisequalities.size();
    2457                 :   12776500 :     d_deducedDisequalityReasonsSize = d_deducedDisequalityReasons.size();
    2458                 :            :     // Store the proof reference
    2459                 :   12776500 :     d_disequalityReasonsMap[pair1] = ref;
    2460                 :   12776500 :     d_disequalityReasonsMap[pair2] = ref;
    2461                 :            :   } else {
    2462 [ -  + ][ -  + ]:    2236100 :     Assert(d_disequalityReasonsMap.find(pair1) != d_disequalityReasonsMap.end())
                 [ -  - ]
    2463                 :          0 :         << "You must provide a proof initially";
    2464                 :            :   }
    2465                 :   15012600 : }
    2466                 :            : 
    2467                 :  182985000 : void EqualityEngine::getDisequalities(bool allowConstants,
    2468                 :            :                                       EqualityNodeId classId,
    2469                 :            :                                       TheoryIdSet inputTags,
    2470                 :            :                                       TaggedEqualitiesSet& out)
    2471                 :            : {
    2472                 :            :   // Must be empty on input
    2473 [ -  + ][ -  + ]:  182985000 :   Assert(out.size() == 0);
                 [ -  - ]
    2474                 :            :   // The class we are looking for, shouldn't have any of the tags we are looking for already set
    2475 [ +  + ][ -  + ]:  182985000 :   Assert(d_nodeIndividualTrigger[classId] == null_set_id
         [ -  + ][ -  - ]
    2476                 :            :          || TheoryIdSetUtil::setIntersection(
    2477                 :            :                 getTriggerTermSet(d_nodeIndividualTrigger[classId]).d_tags,
    2478                 :            :                 inputTags)
    2479                 :            :                 == 0);
    2480                 :            : 
    2481         [ +  + ]:  182985000 :   if (inputTags == 0) {
    2482                 :  114509000 :     return;
    2483                 :            :   }
    2484                 :            : 
    2485                 :            :   // Set of already (through disequalities) visited equivalence classes
    2486                 :   68475500 :   std::set<EqualityNodeId> alreadyVisited;
    2487                 :            : 
    2488                 :            :   // Go through the equivalence class
    2489                 :   68475500 :   EqualityNodeId currentId = classId;
    2490                 :    5638790 :   do {
    2491                 :            : 
    2492         [ +  - ]:   74114300 :     Trace("equality::trigger") << d_name << "::getDisequalities() : going through uselist of " << d_nodes[currentId] << std::endl;
    2493                 :            : 
    2494                 :            :     // Current node in the equivalence class
    2495                 :   74114300 :     EqualityNode& currentNode = getEqualityNode(currentId);
    2496                 :            : 
    2497                 :            :     // Go through the uselist and look for disequalities
    2498                 :   74114300 :     UseListNodeId currentUseId = currentNode.getUseList();
    2499         [ +  + ]:  111401000 :     while (currentUseId != null_uselist_id) {
    2500                 :   37287000 :       UseListNode& useListNode = d_useListNodes[currentUseId];
    2501                 :   37287000 :       EqualityNodeId funId = useListNode.getApplicationId();
    2502                 :            : 
    2503         [ +  - ]:   37287000 :       Trace("equality::trigger") << d_name << "::getDisequalities() : checking " << d_nodes[funId] << std::endl;
    2504                 :            : 
    2505                 :            :       const FunctionApplication& fun =
    2506                 :   37287000 :           d_applications[useListNode.getApplicationId()].d_original;
    2507                 :            :       // If it's an equality asserted to false, we do the work
    2508 [ +  + ][ +  + ]:   37287000 :       if (fun.isEquality() && getEqualityNode(funId).getFind() == getEqualityNode(d_false).getFind()) {
         [ +  + ][ +  + ]
                 [ -  - ]
    2509                 :            :         // Get the other equality member
    2510                 :    6367300 :         bool lhs = false;
    2511                 :    6367300 :         EqualityNodeId toCompare = fun.d_b;
    2512         [ +  + ]:    6367300 :         if (toCompare == currentId) {
    2513                 :    3549050 :           toCompare = fun.d_a;
    2514                 :    3549050 :           lhs = true;
    2515                 :            :         }
    2516                 :            :         // Representative of the other member
    2517                 :    6367300 :         EqualityNodeId toCompareRep = getEqualityNode(toCompare).getFind();
    2518         [ -  + ]:    6367300 :         if (toCompareRep == classId) {
    2519                 :            :           // We're in conflict, so we will send it out from merge
    2520                 :          0 :           out.clear();
    2521                 :          0 :           return;
    2522                 :            :         }
    2523                 :            :         // Check if we already have this one
    2524         [ +  + ]:    6367300 :         if (alreadyVisited.count(toCompareRep) == 0) {
    2525                 :            :           // Mark as visited
    2526                 :    5048900 :           alreadyVisited.insert(toCompareRep);
    2527                 :            :           // Get the trigger set
    2528                 :    5048900 :           TriggerTermSetRef toCompareTriggerSetRef = d_nodeIndividualTrigger[toCompareRep];
    2529                 :            :           // We only care if we're not both constants and there are trigger terms in the other class
    2530 [ +  + ][ +  + ]:    5048900 :           if ((allowConstants || !d_isConstant[toCompareRep]) && toCompareTriggerSetRef != null_set_id) {
         [ +  + ][ +  + ]
    2531                 :            :             // Tags of the other gey
    2532                 :    2484480 :             TriggerTermSet& toCompareTriggerSet = getTriggerTermSet(toCompareTriggerSetRef);
    2533                 :            :             // We only care if there are things in inputTags that is also in toCompareTags
    2534                 :    2484480 :             TheoryIdSet commonTags = TheoryIdSetUtil::setIntersection(
    2535                 :            :                 inputTags, toCompareTriggerSet.d_tags);
    2536         [ +  + ]:    2484480 :             if (commonTags) {
    2537                 :    1693820 :               out.push_back(TaggedEquality(funId, toCompareTriggerSetRef, lhs));
    2538                 :            :             }
    2539                 :            :           }
    2540                 :            :         }
    2541                 :            :       }
    2542                 :            :       // Go to the next one in the use list
    2543                 :   37287000 :       currentUseId = useListNode.getNext();
    2544                 :            :     }
    2545                 :            :     // Next in equivalence class
    2546                 :   74114300 :     currentId = currentNode.getNext();
    2547 [ +  - ][ +  + ]:   74114300 :   } while (!d_done && currentId != classId);
                 [ +  + ]
    2548                 :            : 
    2549                 :            : }
    2550                 :            : 
    2551                 :  182985000 : bool EqualityEngine::propagateTriggerTermDisequalities(
    2552                 :            :     TheoryIdSet tags,
    2553                 :            :     TriggerTermSetRef triggerSetRef,
    2554                 :            :     const TaggedEqualitiesSet& disequalitiesToNotify)
    2555                 :            : {
    2556                 :            :   // No tags, no food
    2557         [ +  + ]:  182985000 :   if (!tags) {
    2558                 :  114509000 :     return !d_done;
    2559                 :            :   }
    2560                 :            : 
    2561 [ -  + ][ -  + ]:   68475500 :   Assert(triggerSetRef != null_set_id);
                 [ -  - ]
    2562                 :            : 
    2563                 :            :   // This is the class trigger set
    2564                 :   68475500 :   const TriggerTermSet& triggerSet = getTriggerTermSet(triggerSetRef);
    2565                 :            :   // Go through the disequalities and notify
    2566                 :   68475500 :   TaggedEqualitiesSet::const_iterator it = disequalitiesToNotify.begin();
    2567                 :   68475500 :   TaggedEqualitiesSet::const_iterator it_end = disequalitiesToNotify.end();
    2568 [ +  + ][ +  + ]:   70116800 :   for (; !d_done && it != it_end; ++ it) {
                 [ +  + ]
    2569                 :            :     // The information about the equality that is asserted to false
    2570                 :    1660600 :     const TaggedEquality& disequalityInfo = *it;
    2571                 :            :     const TriggerTermSet& disequalityTriggerSet =
    2572                 :    1660600 :         getTriggerTermSet(disequalityInfo.d_triggerSetRef);
    2573                 :            :     TheoryIdSet commonTags =
    2574                 :    1660600 :         TheoryIdSetUtil::setIntersection(disequalityTriggerSet.d_tags, tags);
    2575 [ -  + ][ -  + ]:    1660600 :     Assert(commonTags);
                 [ -  - ]
    2576                 :            :     // This is the actual function
    2577                 :            :     const FunctionApplication& fun =
    2578                 :    1660600 :         d_applications[disequalityInfo.d_equalityId].d_original;
    2579                 :            :     // Figure out who we are comparing to in the original equality
    2580         [ +  + ]:    1660600 :     EqualityNodeId toCompare = disequalityInfo.d_lhs ? fun.d_a : fun.d_b;
    2581         [ +  + ]:    1660600 :     EqualityNodeId myCompare = disequalityInfo.d_lhs ? fun.d_b : fun.d_a;
    2582         [ +  + ]:    1660600 :     if (getEqualityNode(toCompare).getFind() == getEqualityNode(myCompare).getFind()) {
    2583                 :            :       // We're propagating a != a, which means we're inconsistent, just bail and let it go into
    2584                 :            :       // a regular conflict
    2585                 :      19320 :       return !d_done;
    2586                 :            :     }
    2587                 :            :     // Go through the tags, and add the disequalities
    2588                 :            :     TheoryId currentTag;
    2589                 :    2433740 :     while (
    2590                 :    4075020 :         !d_done
    2591 [ +  + ][ +  + ]:    4075020 :         && ((currentTag = TheoryIdSetUtil::setPop(commonTags)) != THEORY_LAST))
                 [ +  + ]
    2592                 :            :     {
    2593                 :            :       // Get the tag representative
    2594                 :    2433740 :       EqualityNodeId tagRep = disequalityTriggerSet.getTrigger(currentTag);
    2595                 :    2433740 :       EqualityNodeId myRep = triggerSet.getTrigger(currentTag);
    2596                 :            :       // Propagate
    2597         [ +  + ]:    2433740 :       if (!hasPropagatedDisequality(currentTag, myRep, tagRep)) {
    2598                 :            :         // Construct the proof if not there already
    2599         [ +  + ]:     171529 :         if (!hasPropagatedDisequality(myRep, tagRep)) {
    2600                 :      55310 :           d_deducedDisequalityReasons.push_back(EqualityPair(myCompare, myRep));
    2601                 :      55310 :           d_deducedDisequalityReasons.push_back(EqualityPair(toCompare, tagRep));
    2602                 :      55310 :           d_deducedDisequalityReasons.push_back(
    2603                 :     110620 :               EqualityPair(disequalityInfo.d_equalityId, d_falseId));
    2604                 :            :         }
    2605                 :            :         // Store the propagation
    2606                 :     171529 :         storePropagatedDisequality(currentTag, myRep, tagRep);
    2607                 :            :         // Notify
    2608         [ +  + ]:     343058 :         if (!notifyTriggerTermEquality(
    2609                 :     343058 :                 currentTag, d_nodes[myRep], d_nodes[tagRep], false))
    2610                 :            :         {
    2611                 :         50 :           d_done = true;
    2612                 :            :         }
    2613                 :            :       }
    2614                 :            :     }
    2615                 :            :   }
    2616                 :            : 
    2617                 :   68456200 :   return !d_done;
    2618                 :            : }
    2619                 :            : 
    2620                 :   16393200 : TheoryIdSet EqualityEngine::TriggerTermSet::hasTrigger(TheoryId tag) const
    2621                 :            : {
    2622                 :   16393200 :   return TheoryIdSetUtil::setContains(tag, d_tags);
    2623                 :            : }
    2624                 :            : 
    2625                 :    7358410 : EqualityNodeId EqualityEngine::TriggerTermSet::getTrigger(TheoryId tag) const
    2626                 :            : {
    2627                 :    7358410 :   return d_triggers[TheoryIdSetUtil::setIndex(tag, d_tags)];
    2628                 :            : }
    2629                 :            : 
    2630                 :            : } // Namespace uf
    2631                 :            : } // Namespace theory
    2632                 :            : }  // namespace cvc5::internal

Generated by: LCOV version 1.14