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: 1410 1591 88.6 %
Date: 2026-07-04 10:34:50 Functions: 60 64 93.8 %
Branches: 863 1362 63.4 %

           Branch data     Line data    Source code
       1                 :            : /******************************************************************************
       2                 :            :  * This file is part of the cvc5 project.
       3                 :            :  *
       4                 :            :  * Copyright (c) 2009-2026 by the authors listed in the file AUTHORS
       5                 :            :  * in the top-level source directory and their institutional affiliations.
       6                 :            :  * All rights reserved.  See the file COPYING in the top-level source
       7                 :            :  * directory for licensing information.
       8                 :            :  * ****************************************************************************
       9                 :            :  * [[ Add one-line brief description here ]]
      10                 :            :  *
      11                 :            :  *
      12                 :            :  * [[ Add lengthier description here ]]
      13                 :            :  * \todo document this file
      14                 :            :  */
      15                 :            : 
      16                 :            : #include "theory/uf/equality_engine.h"
      17                 :            : 
      18                 :            : #include "base/output.h"
      19                 :            : #include "options/smt_options.h"
      20                 :            : #include "smt/env.h"
      21                 :            : #include "theory/rewriter.h"
      22                 :            : #include "theory/uf/eq_proof.h"
      23                 :            : 
      24                 :            : namespace cvc5::internal {
      25                 :            : namespace theory {
      26                 :            : namespace eq {
      27                 :            : 
      28                 :     814402 : EqualityEngine::Statistics::Statistics(StatisticsRegistry& sr,
      29                 :     814402 :                                        const std::string& name)
      30                 :     814402 :     : d_mergesCount(sr.registerInt(name + "mergesCount")),
      31                 :     814402 :       d_termsCount(sr.registerInt(name + "termsCount")),
      32                 :     814402 :       d_functionTermsCount(sr.registerInt(name + "functionTermsCount")),
      33                 :     814402 :       d_constantTermsCount(sr.registerInt(name + "constantTermsCount"))
      34                 :            : {
      35                 :     814402 : }
      36                 :            : 
      37                 :            : /**
      38                 :            :  * Data used in the BFS search through the equality graph.
      39                 :            :  */
      40                 :            : struct BfsData
      41                 :            : {
      42                 :            :   // The current node
      43                 :            :   EqualityNodeId d_nodeId;
      44                 :            :   // The index of the edge we traversed
      45                 :            :   EqualityEdgeId d_edgeId;
      46                 :            :   // Index in the queue of the previous node. Shouldn't be too much of them, at
      47                 :            :   // most the size of the biggest equivalence class
      48                 :            :   size_t d_previousIndex;
      49                 :            : 
      50                 :   39505664 :   BfsData(EqualityNodeId nodeId = null_id,
      51                 :            :           EqualityEdgeId edgeId = null_edge,
      52                 :            :           size_t prev = 0)
      53                 :   39505664 :       : d_nodeId(nodeId), d_edgeId(edgeId), d_previousIndex(prev)
      54                 :            :   {
      55                 :   39505664 :   }
      56                 :            : };
      57                 :            : 
      58                 :            : class ScopedBool
      59                 :            : {
      60                 :            :   bool& d_watch;
      61                 :            :   bool d_oldValue;
      62                 :            : 
      63                 :            :  public:
      64                 :   57652992 :   ScopedBool(bool& watch, bool newValue) : d_watch(watch), d_oldValue(watch)
      65                 :            :   {
      66                 :   57652992 :     d_watch = newValue;
      67                 :   57652992 :   }
      68                 :   57652992 :   ~ScopedBool() { d_watch = d_oldValue; }
      69                 :            : };
      70                 :            : 
      71                 :            : EqualityEngineNotifyNone EqualityEngine::s_notifyNone;
      72                 :            : 
      73                 :     814402 : void EqualityEngine::init()
      74                 :            : {
      75         [ +  - ]:    1628804 :   Trace("equality") << "EqualityEdge::EqualityEngine(): id_null = " << +null_id
      76                 :     814402 :                     << std::endl;
      77         [ +  - ]:    1628804 :   Trace("equality") << "EqualityEdge::EqualityEngine(): edge_null = "
      78                 :     814402 :                     << +null_edge << std::endl;
      79         [ +  - ]:    1628804 :   Trace("equality") << "EqualityEdge::EqualityEngine(): trigger_null = "
      80                 :     814402 :                     << +null_trigger << std::endl;
      81                 :            : 
      82                 :            :   // Note that we previously checked whether the context level was zero here,
      83                 :            :   // to ensure that true/false could never be removed. However, this assertion
      84                 :            :   // restricts our ability to construct equality engines in nested contexts.
      85                 :            : 
      86                 :     814402 :   d_true = nodeManager()->mkConst<bool>(true);
      87                 :     814402 :   d_false = nodeManager()->mkConst<bool>(false);
      88                 :            : 
      89                 :     814402 :   d_triggerDatabaseAllocatedSize = 100000;
      90                 :     814402 :   d_triggerDatabase = (char*)malloc(d_triggerDatabaseAllocatedSize);
      91                 :            : 
      92                 :     814402 :   addTermInternal(d_true);
      93                 :     814402 :   addTermInternal(d_false);
      94                 :            : 
      95                 :     814402 :   d_trueId = getNodeId(d_true);
      96                 :     814402 :   d_falseId = getNodeId(d_false);
      97                 :     814402 : }
      98                 :            : 
      99                 :    1515490 : EqualityEngine::~EqualityEngine() { free(d_triggerDatabase); }
     100                 :            : 
     101                 :     154131 : EqualityEngine::EqualityEngine(Env& env,
     102                 :            :                                context::Context* c,
     103                 :            :                                std::string name,
     104                 :            :                                bool constantsAreTriggers,
     105                 :     154131 :                                bool anyTermTriggers)
     106                 :            :     : ContextNotifyObj(c),
     107                 :            :       EnvObj(env),
     108                 :     154131 :       d_masterEqualityEngine(nullptr),
     109                 :     154131 :       d_context(c),
     110                 :          0 :       d_done(c, false),
     111                 :     154131 :       d_notify(&s_notifyNone),
     112                 :     154131 :       d_applicationLookupsCount(c, 0),
     113                 :     154131 :       d_nodesCount(c, 0),
     114                 :     154131 :       d_assertedEqualitiesCount(c, 0),
     115                 :     154131 :       d_equalityTriggersCount(c, 0),
     116                 :     154131 :       d_subtermEvaluatesSize(c, 0),
     117                 :     154131 :       d_stats(statisticsRegistry(), name + "::"),
     118                 :     154131 :       d_inPropagate(false),
     119                 :     154131 :       d_constantsAreTriggers(constantsAreTriggers),
     120                 :     154131 :       d_anyTermsAreTriggers(anyTermTriggers),
     121                 :     154131 :       d_triggerDatabaseSize(c, 0),
     122                 :     154131 :       d_triggerTermSetUpdatesSize(c, 0),
     123                 :     154131 :       d_deducedDisequalitiesSize(c, 0),
     124                 :     154131 :       d_deducedDisequalityReasonsSize(c, 0),
     125                 :     154131 :       d_propagatedDisequalities(c),
     126                 :    1695441 :       d_name(name)
     127                 :            : {
     128                 :     154131 :   init();
     129                 :     154131 : }
     130                 :            : 
     131                 :     660271 : EqualityEngine::EqualityEngine(Env& env,
     132                 :            :                                context::Context* c,
     133                 :            :                                EqualityEngineNotify& notify,
     134                 :            :                                std::string name,
     135                 :            :                                bool constantsAreTriggers,
     136                 :     660271 :                                bool anyTermTriggers)
     137                 :            :     : ContextNotifyObj(c),
     138                 :            :       EnvObj(env),
     139                 :     660271 :       d_masterEqualityEngine(nullptr),
     140                 :     660271 :       d_proofEqualityEngine(nullptr),
     141                 :     660271 :       d_context(c),
     142                 :          0 :       d_done(c, false),
     143                 :     660271 :       d_notify(&s_notifyNone),
     144                 :     660271 :       d_applicationLookupsCount(c, 0),
     145                 :     660271 :       d_nodesCount(c, 0),
     146                 :     660271 :       d_assertedEqualitiesCount(c, 0),
     147                 :     660271 :       d_equalityTriggersCount(c, 0),
     148                 :     660271 :       d_subtermEvaluatesSize(c, 0),
     149                 :     660271 :       d_stats(statisticsRegistry(), name + "::"),
     150                 :     660271 :       d_inPropagate(false),
     151                 :     660271 :       d_constantsAreTriggers(constantsAreTriggers),
     152                 :     660271 :       d_anyTermsAreTriggers(anyTermTriggers),
     153                 :     660271 :       d_triggerDatabaseSize(c, 0),
     154                 :     660271 :       d_triggerTermSetUpdatesSize(c, 0),
     155                 :     660271 :       d_deducedDisequalitiesSize(c, 0),
     156                 :     660271 :       d_deducedDisequalityReasonsSize(c, 0),
     157                 :     660271 :       d_propagatedDisequalities(c),
     158                 :    7262981 :       d_name(name)
     159                 :            : {
     160                 :     660271 :   init();
     161                 :            :   // since init makes notifications (e.g. new eq class for true/false), and
     162                 :            :   // since the notify class may not be fully constructed yet, we
     163                 :            :   // don't set up the provided notification class until after initialization.
     164                 :     660271 :   d_notify = &notify;
     165                 :     660271 : }
     166                 :            : 
     167                 :     489168 : void EqualityEngine::setMasterEqualityEngine(EqualityEngine* master)
     168                 :            : {
     169 [ -  + ][ -  + ]:     489168 :   Assert(d_masterEqualityEngine == nullptr);
                 [ -  - ]
     170                 :     489168 :   d_masterEqualityEngine = master;
     171                 :     489168 : }
     172                 :            : 
     173                 :     138609 : void EqualityEngine::setProofEqualityEngine(ProofEqEngine* pfee)
     174                 :            : {
     175 [ -  + ][ -  + ]:     138609 :   Assert(d_proofEqualityEngine == nullptr);
                 [ -  - ]
     176                 :     138609 :   d_proofEqualityEngine = pfee;
     177                 :     138609 : }
     178                 :     190181 : ProofEqEngine* EqualityEngine::getProofEqualityEngine()
     179                 :            : {
     180                 :     190181 :   return d_proofEqualityEngine;
     181                 :            : }
     182                 :            : 
     183                 :   82553028 : void EqualityEngine::enqueue(const MergeCandidate& candidate, bool back)
     184                 :            : {
     185         [ +  - ]:  165106056 :   Trace("equality") << d_name << "::eq::enqueue({" << candidate.d_t1Id << "} "
     186                 :          0 :                     << d_nodes[candidate.d_t1Id] << ", {" << candidate.d_t2Id
     187                 :          0 :                     << "} " << d_nodes[candidate.d_t2Id] << ", "
     188                 :   82553028 :                     << static_cast<MergeReasonType>(candidate.d_type)
     189                 :   82553028 :                     << "). reason: " << candidate.d_reason << std::endl;
     190         [ +  - ]:   82553028 :   if (back)
     191                 :            :   {
     192                 :   82553028 :     d_propagationQueue.push_back(candidate);
     193                 :            :   }
     194                 :            :   else
     195                 :            :   {
     196                 :          0 :     d_propagationQueue.push_front(candidate);
     197                 :            :   }
     198                 :   82553028 : }
     199                 :            : 
     200                 :    6441889 : EqualityNodeId EqualityEngine::newApplicationNode(TNode original,
     201                 :            :                                                   EqualityNodeId t1,
     202                 :            :                                                   EqualityNodeId t2,
     203                 :            :                                                   FunctionApplicationType type)
     204                 :            : {
     205         [ +  - ]:   12883778 :   Trace("equality") << d_name << "::eq::newApplicationNode(" << original
     206                 :          0 :                     << ", {" << t1 << "} " << d_nodes[t1] << ", {" << t2 << "} "
     207                 :    6441889 :                     << d_nodes[t2] << ")" << std::endl;
     208                 :            : 
     209                 :    6441889 :   ++d_stats.d_functionTermsCount;
     210                 :            : 
     211                 :            :   // Get another id for this
     212                 :    6441889 :   EqualityNodeId funId = newNode(original);
     213                 :    6441889 :   FunctionApplication funOriginal(type, t1, t2);
     214                 :            :   // The function application we're creating
     215                 :    6441889 :   EqualityNodeId t1ClassId = getEqualityNode(t1).getFind();
     216                 :    6441889 :   EqualityNodeId t2ClassId = getEqualityNode(t2).getFind();
     217                 :    6441889 :   FunctionApplication funNormalized(type, t1ClassId, t2ClassId);
     218                 :            : 
     219         [ +  - ]:   12883778 :   Trace("equality") << d_name << "::eq::newApplicationNode: funOriginal: ("
     220                 :          0 :                     << type << " " << d_nodes[t1] << " " << d_nodes[t2]
     221                 :          0 :                     << "), funNorm: (" << type << " " << d_nodes[t1ClassId]
     222                 :    6441889 :                     << " " << d_nodes[t2ClassId] << ")\n";
     223                 :            : 
     224                 :            :   // We add the original version
     225                 :    6441889 :   d_applications[funId] = FunctionApplicationPair(funOriginal, funNormalized);
     226                 :            : 
     227                 :            :   // Add the lookup data, if it's not already there
     228                 :    6441889 :   ApplicationIdsMap::iterator find = d_applicationLookup.find(funNormalized);
     229         [ +  + ]:    6441889 :   if (find == d_applicationLookup.end())
     230                 :            :   {
     231         [ +  - ]:   11404750 :     Trace("equality") << d_name << "::eq::newApplicationNode(" << original
     232                 :          0 :                       << ", " << t1 << ", " << t2
     233                 :          0 :                       << "): no lookup, setting up funNorm: (" << type << " "
     234                 :          0 :                       << d_nodes[t1ClassId] << " " << d_nodes[t2ClassId]
     235                 :    5702375 :                       << ") => " << funId << std::endl;
     236                 :            :     // Mark the normalization to the lookup
     237                 :    5702375 :     storeApplicationLookup(funNormalized, funId);
     238                 :            :   }
     239                 :            :   else
     240                 :            :   {
     241                 :            :     // If it's there, we need to merge these two
     242         [ +  - ]:    1479028 :     Trace("equality") << d_name << "::eq::newApplicationNode(" << original
     243                 :          0 :                       << ", " << t1 << ", " << t2
     244                 :     739514 :                       << "): lookup exists, adding to queue" << std::endl;
     245         [ +  - ]:    1479028 :     Trace("equality") << d_name << "::eq::newApplicationNode(" << original
     246                 :          0 :                       << ", " << t1 << ", " << t2
     247                 :     739514 :                       << "): lookup = " << d_nodes[find->second] << std::endl;
     248                 :     739514 :     enqueue(MergeCandidate(
     249                 :    1479028 :         funId, find->second, MERGED_THROUGH_CONGRUENCE, TNode::null()));
     250                 :            :   }
     251                 :            : 
     252                 :            :   // Add to the use lists
     253         [ +  - ]:   12883778 :   Trace("equality") << d_name << "::eq::newApplicationNode(" << original << ", "
     254                 :          0 :                     << t1 << ", " << t2 << "): adding " << original
     255                 :    6441889 :                     << " to the uselist of " << d_nodes[t1] << std::endl;
     256                 :    6441889 :   d_equalityNodes[t1].usedIn(funId, d_useListNodes);
     257         [ +  - ]:   12883778 :   Trace("equality") << d_name << "::eq::newApplicationNode(" << original << ", "
     258                 :          0 :                     << t1 << ", " << t2 << "): adding " << original
     259                 :    6441889 :                     << " to the uselist of " << d_nodes[t2] << std::endl;
     260                 :    6441889 :   d_equalityNodes[t2].usedIn(funId, d_useListNodes);
     261                 :            : 
     262                 :            :   // Return the new id
     263         [ +  - ]:   12883778 :   Trace("equality") << d_name << "::eq::newApplicationNode(" << original << ", "
     264                 :    6441889 :                     << t1 << ", " << t2 << ") => " << funId << std::endl;
     265                 :            : 
     266                 :    6441889 :   return funId;
     267                 :            : }
     268                 :            : 
     269                 :   17462395 : EqualityNodeId EqualityEngine::newNode(TNode node)
     270                 :            : {
     271         [ +  - ]:   17462395 :   Trace("equality") << d_name << "::eq::newNode(" << node << ")" << std::endl;
     272                 :            : 
     273                 :   17462395 :   ++d_stats.d_termsCount;
     274                 :            : 
     275                 :            :   // Register the new id of the term
     276                 :   17462395 :   EqualityNodeId newId = d_nodes.size();
     277                 :   17462395 :   d_nodeIds[node] = newId;
     278                 :            :   // Add the node to it's position
     279                 :   17462395 :   d_nodes.push_back(node);
     280                 :            :   // Note if this is an application or not
     281                 :   17462395 :   d_applications.push_back(FunctionApplicationPair());
     282                 :            :   // Add the trigger list for this node
     283                 :   17462395 :   d_nodeTriggers.push_back(+null_trigger);
     284                 :            :   // Add it to the equality graph
     285                 :   17462395 :   d_equalityGraph.push_back(+null_edge);
     286                 :            :   // Mark the no-individual trigger
     287                 :   17462395 :   d_nodeIndividualTrigger.push_back(+null_set_id);
     288                 :            :   // Mark non-constant by default
     289                 :   17462395 :   d_isConstant.push_back(false);
     290                 :            :   // No terms to evaluate by defaul
     291                 :   17462395 :   d_subtermsToEvaluate.push_back(0);
     292                 :            :   // Mark equality nodes
     293                 :   17462395 :   d_isEquality.push_back(false);
     294                 :            :   // Mark the node as internal by default
     295                 :   17462395 :   d_isInternal.push_back(true);
     296                 :            :   // Add the equality node to the nodes
     297                 :   17462395 :   d_equalityNodes.push_back(EqualityNode(newId));
     298                 :            : 
     299                 :            :   // Increase the counters
     300                 :   17462395 :   d_nodesCount = d_nodesCount + 1;
     301                 :            : 
     302         [ +  - ]:   34924790 :   Trace("equality") << d_name << "::eq::newNode(" << node << ") => " << newId
     303                 :   17462395 :                     << std::endl;
     304                 :            : 
     305                 :   17462395 :   return newId;
     306                 :            : }
     307                 :            : 
     308                 :    5761344 : void EqualityEngine::addFunctionKind(Kind fun,
     309                 :            :                                      bool interpreted,
     310                 :            :                                      bool extOperator)
     311                 :            : {
     312                 :    5761344 :   d_congruenceKinds.set(fun);
     313         [ +  - ]:    5761344 :   if (fun != Kind::EQUAL)
     314                 :            :   {
     315         [ +  + ]:    5761344 :     if (interpreted)
     316                 :            :     {
     317         [ +  - ]:    2362660 :       Trace("equality::evaluation")
     318                 :          0 :           << d_name << "::eq::addFunctionKind(): " << fun << " is interpreted "
     319                 :    1181330 :           << std::endl;
     320                 :    1181330 :       d_congruenceKindsInterpreted.set(fun);
     321                 :            :     }
     322         [ +  + ]:    5761344 :     if (extOperator)
     323                 :            :     {
     324         [ +  - ]:       3888 :       Trace("equality::extoperator")
     325                 :          0 :           << d_name << "::eq::addFunctionKind(): " << fun
     326                 :       1944 :           << " is an external operator kind " << std::endl;
     327                 :       1944 :       d_congruenceKindsExtOperators.set(fun);
     328                 :            :     }
     329                 :            :   }
     330                 :    5761344 : }
     331                 :            : 
     332                 :    1285882 : void EqualityEngine::subtermEvaluates(EqualityNodeId id)
     333                 :            : {
     334         [ +  - ]:    2571764 :   Trace("equality::evaluation")
     335                 :          0 :       << d_name << "::eq::subtermEvaluates(" << d_nodes[id]
     336                 :    1285882 :       << "): " << d_subtermsToEvaluate[id] << std::endl;
     337 [ -  + ][ -  + ]:    1285882 :   Assert(!d_isInternal[id]);
                 [ -  - ]
     338 [ -  + ][ -  + ]:    1285882 :   Assert(d_subtermsToEvaluate[id] > 0);
                 [ -  - ]
     339         [ +  + ]:    1285882 :   if ((--d_subtermsToEvaluate[id]) == 0)
     340                 :            :   {
     341                 :     898111 :     d_evaluationQueue.push(id);
     342                 :            :   }
     343                 :    1285882 :   d_subtermEvaluates.push_back(id);
     344                 :    1285882 :   d_subtermEvaluatesSize = d_subtermEvaluates.size();
     345         [ +  - ]:    2571764 :   Trace("equality::evaluation")
     346                 :          0 :       << d_name << "::eq::subtermEvaluates(" << d_nodes[id] << "): new "
     347                 :    1285882 :       << d_subtermsToEvaluate[id] << std::endl;
     348                 :    1285882 : }
     349                 :            : 
     350                 :  119194673 : void EqualityEngine::addTermInternal(TNode t, bool isOperator)
     351                 :            : {
     352         [ +  - ]:  238389346 :   Trace("equality") << d_name << "::eq::addTermInternal(" << t << ")"
     353                 :  119194673 :                     << std::endl;
     354                 :            : 
     355                 :            :   // If there already, we're done
     356         [ +  + ]:  119194673 :   if (hasTerm(t))
     357                 :            :   {
     358         [ +  - ]:  205392912 :     Trace("equality") << d_name << "::eq::addTermInternal(" << t
     359                 :  102696456 :                       << "): already there" << std::endl;
     360                 :  102696470 :     return;
     361                 :            :   }
     362                 :            : 
     363         [ +  + ]:   16498217 :   if (d_done)
     364                 :            :   {
     365                 :         14 :     return;
     366                 :            :   }
     367                 :            : 
     368                 :            :   EqualityNodeId result;
     369                 :            : 
     370                 :   16498203 :   Kind tk = t.getKind();
     371         [ +  + ]:   16498203 :   if (tk == Kind::EQUAL)
     372                 :            :   {
     373                 :    4186098 :     addTermInternal(t[0]);
     374                 :    4186098 :     addTermInternal(t[1]);
     375                 :    4186098 :     EqualityNodeId t0id = getNodeId(t[0]);
     376                 :    4186098 :     EqualityNodeId t1id = getNodeId(t[1]);
     377                 :    4186098 :     result = newApplicationNode(t, t0id, t1id, APP_EQUALITY);
     378                 :    4186098 :     d_isInternal[result] = false;
     379                 :    4186098 :     d_isConstant[result] = false;
     380                 :            :   }
     381 [ +  + ][ +  + ]:   12312105 :   else if (t.getNumChildren() > 0 && d_congruenceKinds[tk])
                 [ +  + ]
     382                 :            :   {
     383                 :    1291599 :     TNode tOp = t.getOperator();
     384                 :            :     // Add the operator
     385                 :    1291599 :     addTermInternal(tOp, !isExternalOperatorKind(tk));
     386                 :    1291599 :     result = getNodeId(tOp);
     387                 :            :     // Add all the children and Curryfy
     388                 :    1291599 :     bool isInterpreted = isInterpretedFunctionKind(tk);
     389         [ +  + ]:    3547390 :     for (unsigned i = 0; i < t.getNumChildren(); ++i)
     390                 :            :     {
     391                 :            :       // Add the child
     392                 :    2255791 :       addTermInternal(t[i]);
     393                 :    2255791 :       EqualityNodeId tiId = getNodeId(t[i]);
     394                 :            :       // Add the application
     395         [ +  + ]:    2255791 :       result = newApplicationNode(
     396                 :            :           t, result, tiId, isInterpreted ? APP_INTERPRETED : APP_UNINTERPRETED);
     397                 :            :     }
     398                 :    1291599 :     d_isInternal[result] = false;
     399                 :    1291599 :     d_isConstant[result] = t.isConst();
     400                 :            :     // If interpreted, set the number of non-interpreted children
     401         [ +  + ]:    1291599 :     if (isInterpreted)
     402                 :            :     {
     403                 :            :       // How many children are not constants yet
     404                 :     135180 :       d_subtermsToEvaluate[result] = t.getNumChildren();
     405         [ +  + ]:     343789 :       for (unsigned i = 0; i < t.getNumChildren(); ++i)
     406                 :            :       {
     407         [ +  + ]:     208609 :         if (isConstant(getNodeId(t[i])))
     408                 :            :         {
     409         [ +  - ]:      70302 :           Trace("equality::evaluation")
     410                 :          0 :               << d_name << "::eq::addTermInternal(" << t << "): evaluates "
     411 [ -  + ][ -  - ]:      35151 :               << t[i] << std::endl;
     412                 :      35151 :           subtermEvaluates(result);
     413                 :            :         }
     414                 :            :       }
     415                 :            :     }
     416                 :    1291599 :   }
     417                 :            :   else
     418                 :            :   {
     419                 :            :     // Otherwise we just create the new id
     420                 :   11020506 :     result = newNode(t);
     421                 :            :     // Is this an operator
     422                 :   11020506 :     d_isInternal[result] = isOperator;
     423 [ +  + ][ +  + ]:   11020506 :     d_isConstant[result] = !isOperator && t.isConst();
     424                 :            :   }
     425                 :            : 
     426         [ +  + ]:   16498203 :   if (tk == Kind::EQUAL)
     427                 :            :   {
     428                 :            :     // We set this here as this only applies to actual terms, not the
     429                 :            :     // intermediate application terms
     430                 :    4186098 :     d_isEquality[result] = true;
     431                 :            :   }
     432                 :            :   else
     433                 :            :   {
     434                 :            :     // Notify e.g. the theory that owns this equality engine that there is a
     435                 :            :     // new equivalence class.
     436                 :   12312105 :     d_notify->eqNotifyNewClass(t);
     437 [ +  + ][ +  + ]:   12312105 :     if (d_constantsAreTriggers && d_isConstant[result])
                 [ +  + ]
     438                 :            :     {
     439                 :            :       // Non-Boolean constants are trigger terms for all tags
     440                 :    2020951 :       EqualityNodeId tId = getNodeId(t);
     441                 :            :       // Setup the new set
     442                 :    2020951 :       TheoryIdSet newSetTags = 0;
     443                 :            :       EqualityNodeId newSetTriggers[THEORY_LAST];
     444                 :    2020951 :       unsigned newSetTriggersSize = THEORY_LAST;
     445         [ +  + ]:   30314265 :       for (TheoryId currentTheory = THEORY_FIRST; currentTheory != THEORY_LAST;
     446                 :   28293314 :            ++currentTheory)
     447                 :            :       {
     448                 :   28293314 :         newSetTags = TheoryIdSetUtil::setInsert(currentTheory, newSetTags);
     449                 :   28293314 :         newSetTriggers[currentTheory] = tId;
     450                 :            :       }
     451                 :            :       // Add it to the list for backtracking
     452                 :    2020951 :       d_triggerTermSetUpdates.push_back(TriggerSetUpdate(tId, null_set_id));
     453                 :    2020951 :       d_triggerTermSetUpdatesSize = d_triggerTermSetUpdatesSize + 1;
     454                 :            :       // Mark the the new set as a trigger
     455                 :    2020951 :       d_nodeIndividualTrigger[tId] =
     456                 :    2020951 :           newTriggerTermSet(newSetTags, newSetTriggers, newSetTriggersSize);
     457                 :            :     }
     458                 :            :   }
     459                 :            : 
     460                 :            :   // If this is not an internal node, add it to the master
     461 [ +  + ][ +  + ]:   16498203 :   if (d_masterEqualityEngine && !d_isInternal[result])
                 [ +  + ]
     462                 :            :   {
     463                 :    4116811 :     d_masterEqualityEngine->addTermInternal(t);
     464                 :            :   }
     465                 :            : 
     466                 :            :   // Empty the queue
     467                 :   16498203 :   propagate();
     468                 :            : 
     469 [ -  + ][ -  + ]:   16498203 :   Assert(hasTerm(t));
                 [ -  - ]
     470                 :            : 
     471         [ +  - ]:   32996406 :   Trace("equality") << d_name << "::eq::addTermInternal(" << t << ") => "
     472                 :   16498203 :                     << result << std::endl;
     473                 :            : }
     474                 :            : 
     475                 : 1446929691 : bool EqualityEngine::hasTerm(TNode t) const
     476                 :            : {
     477                 : 1446929691 :   return d_nodeIds.find(t) != d_nodeIds.end();
     478                 :            : }
     479                 :            : 
     480                 :  667111473 : EqualityNodeId EqualityEngine::getNodeId(TNode node) const
     481                 :            : {
     482                 :  667111473 :   Assert(hasTerm(node)) << node;
     483                 :  667111473 :   return (*d_nodeIds.find(node)).second;
     484                 :            : }
     485                 :            : 
     486                 :  154603915 : EqualityNode& EqualityEngine::getEqualityNode(TNode t)
     487                 :            : {
     488                 :  154603915 :   return getEqualityNode(getNodeId(t));
     489                 :            : }
     490                 :            : 
     491                 : 1114105126 : EqualityNode& EqualityEngine::getEqualityNode(EqualityNodeId nodeId)
     492                 :            : {
     493 [ -  + ][ -  + ]: 1114105126 :   Assert(nodeId < d_equalityNodes.size());
                 [ -  - ]
     494                 : 1114105126 :   return d_equalityNodes[nodeId];
     495                 :            : }
     496                 :            : 
     497                 :  285483784 : const EqualityNode& EqualityEngine::getEqualityNode(TNode t) const
     498                 :            : {
     499                 :  285483784 :   return getEqualityNode(getNodeId(t));
     500                 :            : }
     501                 :            : 
     502                 :  714312024 : const EqualityNode& EqualityEngine::getEqualityNode(EqualityNodeId nodeId) const
     503                 :            : {
     504 [ -  + ][ -  + ]:  714312024 :   Assert(nodeId < d_equalityNodes.size());
                 [ -  - ]
     505                 :  714312024 :   return d_equalityNodes[nodeId];
     506                 :            : }
     507                 :            : 
     508                 :   41203138 : void EqualityEngine::assertEqualityInternal(TNode t1,
     509                 :            :                                             TNode t2,
     510                 :            :                                             TNode reason,
     511                 :            :                                             unsigned pid)
     512                 :            : {
     513         [ +  - ]:   82406276 :   Trace("equality") << d_name << "::eq::addEqualityInternal(" << t1 << "," << t2
     514                 :          0 :                     << "), reason = " << reason
     515                 :   41203138 :                     << ", pid = " << static_cast<MergeReasonType>(pid)
     516                 :   41203138 :                     << std::endl;
     517                 :            : 
     518         [ +  + ]:   41203138 :   if (d_done)
     519                 :            :   {
     520                 :        472 :     return;
     521                 :            :   }
     522                 :            : 
     523                 :            :   // Add the terms if they are not already in the database
     524                 :   41202666 :   addTermInternal(t1);
     525                 :   41202666 :   addTermInternal(t2);
     526                 :            : 
     527                 :            :   // Add to the queue and propagate
     528                 :   41202666 :   EqualityNodeId t1Id = getNodeId(t1);
     529                 :   41202666 :   EqualityNodeId t2Id = getNodeId(t2);
     530                 :   41202666 :   enqueue(MergeCandidate(t1Id, t2Id, pid, reason));
     531                 :            : }
     532                 :            : 
     533                 :    7956111 : bool EqualityEngine::assertPredicate(TNode t,
     534                 :            :                                      bool polarity,
     535                 :            :                                      TNode reason,
     536                 :            :                                      unsigned pid)
     537                 :            : {
     538         [ +  - ]:   15912222 :   Trace("equality") << d_name << "::eq::addPredicate(" << t << ","
     539         [ -  - ]:    7956111 :                     << (polarity ? "true" : "false") << ")" << std::endl;
     540 [ -  + ][ -  + ]:    7956111 :   Assert(t.getKind() != Kind::EQUAL) << "Use assertEquality instead";
                 [ -  - ]
     541         [ +  + ]:    7956111 :   TNode b = polarity ? d_true : d_false;
     542                 :    7956111 :   if (hasTerm(t) && areEqual(t, b))
     543                 :            :   {
     544                 :    1787248 :     return false;
     545                 :            :   }
     546                 :    6168863 :   assertEqualityInternal(t, b, reason, pid);
     547                 :    6168863 :   propagate();
     548                 :    6168863 :   return true;
     549                 :    7956111 : }
     550                 :            : 
     551                 :   33316595 : bool EqualityEngine::assertEquality(TNode eq,
     552                 :            :                                     bool polarity,
     553                 :            :                                     TNode reason,
     554                 :            :                                     unsigned pid)
     555                 :            : {
     556         [ +  - ]:   66633190 :   Trace("equality") << d_name << "::eq::addEquality(" << eq << ","
     557         [ -  - ]:   33316595 :                     << (polarity ? "true" : "false") << ")" << std::endl;
     558         [ +  + ]:   33316595 :   if (polarity)
     559                 :            :   {
     560                 :            :     // If two terms are already equal, don't assert anything
     561                 :   19857154 :     if (hasTerm(eq[0]) && hasTerm(eq[1]) && areEqual(eq[0], eq[1]))
     562                 :            :     {
     563                 :    4935377 :       return false;
     564                 :            :     }
     565                 :            :     // Add equality between terms
     566                 :   14921777 :     assertEqualityInternal(eq[0], eq[1], reason, pid);
     567                 :   14921777 :     propagate();
     568                 :            :   }
     569                 :            :   else
     570                 :            :   {
     571                 :            :     // If two terms are already dis-equal, don't assert anything
     572                 :   13459441 :     if (hasTerm(eq[0]) && hasTerm(eq[1]) && areDisequal(eq[0], eq[1], false))
     573                 :            :     {
     574                 :    7319976 :       return false;
     575                 :            :     }
     576                 :            : 
     577                 :            :     // notify the theory
     578                 :    6142501 :     d_notify->eqNotifyDisequal(eq[0], eq[1], reason);
     579                 :            : 
     580         [ +  - ]:   12285002 :     Trace("equality::trigger")
     581                 :          0 :         << d_name << "::eq::addEquality(" << eq << ","
     582         [ -  - ]:    6142501 :         << (polarity ? "true" : "false") << ")" << std::endl;
     583                 :            : 
     584                 :    6142501 :     assertEqualityInternal(eq, d_false, reason, pid);
     585                 :    6142501 :     propagate();
     586                 :            : 
     587         [ +  + ]:    6142501 :     if (d_done)
     588                 :            :     {
     589                 :       2084 :       return true;
     590                 :            :     }
     591                 :            : 
     592                 :            :     // If both have constant representatives, we don't notify anyone
     593                 :    6140417 :     EqualityNodeId a = getNodeId(eq[0]);
     594                 :    6140417 :     EqualityNodeId b = getNodeId(eq[1]);
     595                 :    6140417 :     EqualityNodeId aClassId = getEqualityNode(a).getFind();
     596                 :    6140417 :     EqualityNodeId bClassId = getEqualityNode(b).getFind();
     597 [ +  + ][ +  + ]:    6140417 :     if (d_isConstant[aClassId] && d_isConstant[bClassId])
                 [ +  + ]
     598                 :            :     {
     599                 :        952 :       return true;
     600                 :            :     }
     601                 :            : 
     602                 :            :     // If we are adding a disequality, notify of the shared term representatives
     603                 :    6139465 :     EqualityNodeId eqId = getNodeId(eq);
     604                 :    6139465 :     TriggerTermSetRef aTriggerRef = d_nodeIndividualTrigger[aClassId];
     605                 :    6139465 :     TriggerTermSetRef bTriggerRef = d_nodeIndividualTrigger[bClassId];
     606 [ +  + ][ +  + ]:    6139465 :     if (aTriggerRef != +null_set_id && bTriggerRef != +null_set_id)
     607                 :            :     {
     608         [ +  - ]:    5210890 :       Trace("equality::trigger")
     609                 :          0 :           << d_name << "::eq::addEquality(" << eq << ","
     610         [ -  - ]:    2605445 :           << (polarity ? "true" : "false") << ": have triggers" << std::endl;
     611                 :            :       // The sets of trigger terms
     612                 :    2605445 :       TriggerTermSet& aTriggerTerms = getTriggerTermSet(aTriggerRef);
     613                 :    2605445 :       TriggerTermSet& bTriggerTerms = getTriggerTermSet(bTriggerRef);
     614                 :            :       // Go through and notify the shared dis-equalities
     615                 :    2605445 :       TheoryIdSet aTags = aTriggerTerms.d_tags;
     616                 :    2605445 :       TheoryIdSet bTags = bTriggerTerms.d_tags;
     617                 :    2605445 :       TheoryId aTag = TheoryIdSetUtil::setPop(aTags);
     618                 :    2605445 :       TheoryId bTag = TheoryIdSetUtil::setPop(bTags);
     619                 :    2605445 :       int a_i = 0, b_i = 0;
     620 [ +  + ][ +  + ]:   15822939 :       while (aTag != THEORY_LAST && bTag != THEORY_LAST)
     621                 :            :       {
     622         [ +  + ]:   13217588 :         if (aTag < bTag)
     623                 :            :         {
     624                 :    5575733 :           aTag = TheoryIdSetUtil::setPop(aTags);
     625                 :    5575733 :           ++a_i;
     626                 :            :         }
     627         [ +  + ]:    7641855 :         else if (aTag > bTag)
     628                 :            :         {
     629                 :    3938270 :           bTag = TheoryIdSetUtil::setPop(bTags);
     630                 :    3938270 :           ++b_i;
     631                 :            :         }
     632                 :            :         else
     633                 :            :         {
     634                 :            :           // Same tags, notify
     635                 :    3703585 :           EqualityNodeId aSharedId = aTriggerTerms.d_triggers[a_i++];
     636                 :    3703585 :           EqualityNodeId bSharedId = bTriggerTerms.d_triggers[b_i++];
     637                 :            :           // Propagate
     638         [ +  + ]:    3703585 :           if (!hasPropagatedDisequality(aTag, aSharedId, bSharedId))
     639                 :            :           {
     640                 :            :             // Store a proof if not there already
     641         [ +  + ]:    3703581 :             if (!hasPropagatedDisequality(aSharedId, bSharedId))
     642                 :            :             {
     643                 :    1760607 :               d_deducedDisequalityReasons.push_back(EqualityPair(aSharedId, a));
     644                 :    1760607 :               d_deducedDisequalityReasons.push_back(EqualityPair(bSharedId, b));
     645                 :    1760607 :               d_deducedDisequalityReasons.push_back(
     646                 :    3521214 :                   EqualityPair(eqId, d_falseId));
     647                 :            :             }
     648                 :            :             // Store the propagation
     649                 :    3703581 :             storePropagatedDisequality(aTag, aSharedId, bSharedId);
     650                 :            :             // Notify
     651         [ +  - ]:    7407162 :             Trace("equality::trigger")
     652                 :          0 :                 << d_name << "::eq::addEquality(" << eq << ","
     653         [ -  - ]:    3703581 :                 << (polarity ? "true" : "false") << ": notifying " << aTag
     654                 :          0 :                 << " for " << d_nodes[aSharedId] << " != " << d_nodes[bSharedId]
     655                 :    3703581 :                 << std::endl;
     656         [ +  + ]:    7407162 :             if (!notifyTriggerTermEquality(
     657                 :    7407162 :                     aTag, d_nodes[aSharedId], d_nodes[bSharedId], false))
     658                 :            :             {
     659                 :         94 :               break;
     660                 :            :             }
     661                 :            :           }
     662                 :            :           // Pop the next tags
     663                 :    3703491 :           aTag = TheoryIdSetUtil::setPop(aTags);
     664                 :    3703491 :           bTag = TheoryIdSetUtil::setPop(bTags);
     665                 :            :         }
     666                 :            :       }
     667                 :            :     }
     668                 :            :   }
     669                 :   21061239 :   return true;
     670                 :            : }
     671                 :            : 
     672                 :  142666298 : TNode EqualityEngine::getRepresentative(TNode t) const
     673                 :            : {
     674         [ +  - ]:  285332596 :   Trace("equality::internal")
     675                 :  142666298 :       << d_name << "::eq::getRepresentative(" << t << ")" << std::endl;
     676 [ -  + ][ -  + ]:  142666298 :   Assert(hasTerm(t));
                 [ -  - ]
     677                 :  142666298 :   EqualityNodeId representativeId = getEqualityNode(t).getFind();
     678 [ -  + ][ -  + ]:  142666298 :   Assert(!d_isInternal[representativeId]);
                 [ -  - ]
     679         [ +  - ]:  285332596 :   Trace("equality::internal")
     680                 :          0 :       << d_name << "::eq::getRepresentative(" << t << ") => "
     681                 :  142666298 :       << d_nodes[representativeId] << std::endl;
     682                 :  142666298 :   return d_nodes[representativeId];
     683                 :            : }
     684                 :            : 
     685                 :   63099409 : bool EqualityEngine::merge(EqualityNode& class1,
     686                 :            :                            EqualityNode& class2,
     687                 :            :                            std::vector<TriggerId>& triggersFired)
     688                 :            : {
     689         [ +  - ]:  126198818 :   Trace("equality") << d_name << "::eq::merge(" << class1.getFind() << ","
     690                 :   63099409 :                     << class2.getFind() << ")" << std::endl;
     691                 :            : 
     692 [ -  + ][ -  + ]:   63099409 :   Assert(triggersFired.empty());
                 [ -  - ]
     693                 :            : 
     694                 :   63099409 :   ++d_stats.d_mergesCount;
     695                 :            : 
     696                 :   63099409 :   EqualityNodeId class1Id = class1.getFind();
     697                 :   63099409 :   EqualityNodeId class2Id = class2.getFind();
     698                 :            : 
     699                 :   63099409 :   Node n1 = d_nodes[class1Id];
     700                 :   63099409 :   Node n2 = d_nodes[class2Id];
     701                 :   63099409 :   EqualityNode cc1 = getEqualityNode(n1);
     702                 :   63099409 :   EqualityNode cc2 = getEqualityNode(n2);
     703                 :   63099409 :   bool doNotify = false;
     704                 :            :   // Determine if we should notify the owner of this class of this merge.
     705                 :            :   // The second part of this check is needed due to the internal implementation
     706                 :            :   // of this class. It ensures that we are merging terms and not operators.
     707 [ +  + ][ +  + ]:   63099409 :   if (class1Id == cc1.getFind() && class2Id == cc2.getFind())
                 [ +  + ]
     708                 :            :   {
     709                 :   60376099 :     doNotify = true;
     710                 :            :   }
     711                 :            : 
     712                 :            :   // Check for constant merges
     713                 :   63099409 :   bool class1isConstant = d_isConstant[class1Id];
     714                 :   63099409 :   bool class2isConstant = d_isConstant[class2Id];
     715 [ +  + ][ +  - ]:   63099409 :   Assert(class1isConstant || !class2isConstant)
         [ -  + ][ -  + ]
                 [ -  - ]
     716                 :          0 :       << "Should always merge into constants";
     717 [ +  + ][ +  - ]:   63099409 :   Assert(!class1isConstant || !class2isConstant) << "Don't merge constants";
         [ -  + ][ -  + ]
                 [ -  - ]
     718                 :            : 
     719                 :            :   // Trigger set of class 1
     720                 :   63099409 :   TriggerTermSetRef class1triggerRef = d_nodeIndividualTrigger[class1Id];
     721                 :            :   TheoryIdSet class1Tags = class1triggerRef == null_set_id
     722         [ +  + ]:   63099409 :                                ? 0
     723                 :   37885742 :                                : getTriggerTermSet(class1triggerRef).d_tags;
     724                 :            :   // Trigger set of class 2
     725                 :   63099409 :   TriggerTermSetRef class2triggerRef = d_nodeIndividualTrigger[class2Id];
     726                 :            :   TheoryIdSet class2Tags = class2triggerRef == null_set_id
     727         [ +  + ]:   63099409 :                                ? 0
     728                 :    6620349 :                                : getTriggerTermSet(class2triggerRef).d_tags;
     729                 :            : 
     730                 :            :   // Disequalities coming from class2
     731                 :   63099409 :   TaggedEqualitiesSet class2disequalitiesToNotify;
     732                 :            :   // Disequalities coming from class1
     733                 :   63099409 :   TaggedEqualitiesSet class1disequalitiesToNotify;
     734                 :            : 
     735                 :            :   // Individual tags
     736                 :            :   TheoryIdSet class1OnlyTags =
     737                 :   63099409 :       TheoryIdSetUtil::setDifference(class1Tags, class2Tags);
     738                 :            :   TheoryIdSet class2OnlyTags =
     739                 :   63099409 :       TheoryIdSetUtil::setDifference(class2Tags, class1Tags);
     740                 :            : 
     741                 :            :   // Only get disequalities if they are not both constant
     742 [ +  + ][ +  - ]:   63099409 :   if (!class1isConstant || !class2isConstant)
     743                 :            :   {
     744                 :   63099409 :     getDisequalities(!class1isConstant,
     745                 :            :                      class2Id,
     746                 :            :                      class1OnlyTags,
     747                 :            :                      class2disequalitiesToNotify);
     748                 :   63099409 :     getDisequalities(!class2isConstant,
     749                 :            :                      class1Id,
     750                 :            :                      class2OnlyTags,
     751                 :            :                      class1disequalitiesToNotify);
     752                 :            :   }
     753                 :            : 
     754                 :            :   // Update class2 representative information
     755         [ +  - ]:  126198818 :   Trace("equality") << d_name << "::eq::merge(" << class1.getFind() << ","
     756                 :   63099409 :                     << class2.getFind() << "): updating class " << class2Id
     757                 :   63099409 :                     << std::endl;
     758                 :   63099409 :   EqualityNodeId currentId = class2Id;
     759                 :            :   do
     760                 :            :   {
     761                 :            :     // Get the current node
     762                 :   81006359 :     EqualityNode& currentNode = getEqualityNode(currentId);
     763                 :            : 
     764                 :            :     // Update it's find to class1 id
     765         [ +  - ]:  162012718 :     Trace("equality") << d_name << "::eq::merge(" << class1.getFind() << ","
     766                 :   81006359 :                       << class2.getFind() << "): " << currentId << "->"
     767                 :   81006359 :                       << class1Id << std::endl;
     768                 :   81006359 :     currentNode.setFind(class1Id);
     769                 :            : 
     770                 :            :     // Go through the triggers and inform if necessary
     771                 :   81006359 :     TriggerId currentTrigger = d_nodeTriggers[currentId];
     772         [ +  + ]:  165130264 :     while (currentTrigger != null_trigger)
     773                 :            :     {
     774                 :   84123905 :       Trigger& trigger = d_equalityTriggers[currentTrigger];
     775                 :   84123905 :       Trigger& otherTrigger = d_equalityTriggers[currentTrigger ^ 1];
     776                 :            : 
     777                 :            :       // If the two are not already in the same class
     778         [ +  + ]:   84123905 :       if (otherTrigger.d_classId != trigger.d_classId)
     779                 :            :       {
     780                 :   70246641 :         trigger.d_classId = class1Id;
     781                 :            :         // If they became the same, call the trigger
     782         [ +  + ]:   70246641 :         if (otherTrigger.d_classId == class1Id)
     783                 :            :         {
     784                 :            :           // Id of the real trigger is half the internal one
     785                 :   25224120 :           triggersFired.push_back(currentTrigger);
     786                 :            :         }
     787                 :            :       }
     788                 :            : 
     789                 :            :       // Go to the next trigger
     790                 :   84123905 :       currentTrigger = trigger.d_nextTrigger;
     791                 :            :     }
     792                 :            : 
     793                 :            :     // Move to the next node
     794                 :   81006359 :     currentId = currentNode.getNext();
     795                 :            : 
     796         [ +  + ]:   81006359 :   } while (currentId != class2Id);
     797                 :            : 
     798                 :            :   // Update class2 table lookup and information if not a boolean
     799                 :            :   // since booleans can't be in an application
     800         [ +  + ]:   63099409 :   if (!d_isEquality[class2Id])
     801                 :            :   {
     802         [ +  - ]:   73927062 :     Trace("equality") << d_name << "::eq::merge(" << class1.getFind() << ","
     803                 :   36963531 :                       << class2.getFind() << "): updating lookups of "
     804                 :   36963531 :                       << class2Id << std::endl;
     805                 :            :     do
     806                 :            :     {
     807                 :            :       // Get the current node
     808                 :   51769985 :       EqualityNode& currentNode = getEqualityNode(currentId);
     809         [ +  - ]:  103539970 :       Trace("equality") << d_name << "::eq::merge(" << class1.getFind() << ","
     810                 :   51769985 :                         << class2.getFind() << "): updating lookups of node "
     811                 :   51769985 :                         << currentId << std::endl;
     812                 :            : 
     813                 :            :       // Go through the uselist and check for congruences
     814                 :   51769985 :       UseListNodeId currentUseId = currentNode.getUseList();
     815         [ +  + ]:  139319920 :       while (currentUseId != null_uselist_id)
     816                 :            :       {
     817                 :            :         // Get the node of the use list
     818                 :   87549935 :         UseListNode& useNode = d_useListNodes[currentUseId];
     819                 :            :         // Get the function application
     820                 :   87549935 :         EqualityNodeId funId = useNode.getApplicationId();
     821         [ +  - ]:  175099870 :         Trace("equality") << d_name << "::eq::merge(" << class1.getFind() << ","
     822                 :   87549935 :                           << class2.getFind() << "): " << d_nodes[currentId]
     823                 :   87549935 :                           << " in " << d_nodes[funId] << std::endl;
     824                 :            :         const FunctionApplication& fun =
     825                 :   87549935 :             d_applications[useNode.getApplicationId()].d_normalized;
     826                 :            :         // If it's interpreted and we can interpret
     827 [ +  + ][ +  + ]:   87549935 :         if (fun.isInterpreted() && class1isConstant && !d_isInternal[currentId])
         [ +  + ][ +  + ]
     828                 :            :         {
     829                 :            :           // Get the actual term id
     830                 :    1250731 :           TNode term = d_nodes[funId];
     831                 :    1250731 :           subtermEvaluates(getNodeId(term));
     832                 :    1250731 :         }
     833                 :            :         // Check if there is an application with find arguments
     834                 :   87549935 :         EqualityNodeId aNormalized = getEqualityNode(fun.d_a).getFind();
     835                 :   87549935 :         EqualityNodeId bNormalized = getEqualityNode(fun.d_b).getFind();
     836                 :   87549935 :         FunctionApplication funNormalized(fun.d_type, aNormalized, bNormalized);
     837                 :            :         ApplicationIdsMap::iterator find =
     838                 :   87549935 :             d_applicationLookup.find(funNormalized);
     839         [ +  + ]:   87549935 :         if (find != d_applicationLookup.end())
     840                 :            :         {
     841                 :            :           // Applications fun and the funNormalized can be merged due to
     842                 :            :           // congruence
     843                 :   61956457 :           if (getEqualityNode(funId).getFind()
     844         [ +  + ]:   61956457 :               != getEqualityNode(find->second).getFind())
     845                 :            :           {
     846                 :   35520087 :             enqueue(MergeCandidate(
     847                 :   71040174 :                 funId, find->second, MERGED_THROUGH_CONGRUENCE, TNode::null()));
     848                 :            :           }
     849                 :            :         }
     850                 :            :         else
     851                 :            :         {
     852                 :            :           // There is no representative, so we can add one, we remove this when
     853                 :            :           // backtracking
     854                 :   25593478 :           storeApplicationLookup(funNormalized, funId);
     855                 :            :         }
     856                 :            : 
     857                 :            :         // Go to the next one in the use list
     858                 :   87549935 :         currentUseId = useNode.getNext();
     859                 :            :       }
     860                 :            : 
     861                 :            :       // Move to the next node
     862                 :   51769985 :       currentId = currentNode.getNext();
     863         [ +  + ]:   51769985 :     } while (currentId != class2Id);
     864                 :            :   }
     865                 :            : 
     866                 :            :   // Now merge the lists
     867                 :   63099409 :   class1.merge<true>(class2);
     868                 :            : 
     869                 :            :   // notify the theory
     870         [ +  + ]:   63099409 :   if (doNotify)
     871                 :            :   {
     872                 :   60376105 :     d_notify->eqNotifyMerge(n1, n2);
     873                 :            :   }
     874                 :            : 
     875                 :            :   // Go through the trigger term disequalities and propagate
     876         [ +  + ]:   63099406 :   if (!propagateTriggerTermDisequalities(
     877                 :            :           class1OnlyTags, class1triggerRef, class2disequalitiesToNotify))
     878                 :            :   {
     879                 :         22 :     return false;
     880                 :            :   }
     881         [ +  + ]:   63099384 :   if (!propagateTriggerTermDisequalities(
     882                 :            :           class2OnlyTags, class2triggerRef, class1disequalitiesToNotify))
     883                 :            :   {
     884                 :         19 :     return false;
     885                 :            :   }
     886                 :            : 
     887                 :            :   // Notify the trigger term merges
     888         [ +  + ]:   63099365 :   if (class2triggerRef != +null_set_id)
     889                 :            :   {
     890         [ +  + ]:    6620330 :     if (class1triggerRef == +null_set_id)
     891                 :            :     {
     892                 :            :       // If class1 doesn't have individual triggers, but class2 does, mark it
     893                 :     343366 :       d_nodeIndividualTrigger[class1Id] = class2triggerRef;
     894                 :            :       // Add it to the list for backtracking
     895                 :     343366 :       d_triggerTermSetUpdates.push_back(
     896                 :     343366 :           TriggerSetUpdate(class1Id, +null_set_id));
     897                 :     343366 :       d_triggerTermSetUpdatesSize = d_triggerTermSetUpdatesSize + 1;
     898                 :            :     }
     899                 :            :     else
     900                 :            :     {
     901                 :            :       // Get the triggers
     902                 :    6276964 :       TriggerTermSet& class1triggers = getTriggerTermSet(class1triggerRef);
     903                 :    6276964 :       TriggerTermSet& class2triggers = getTriggerTermSet(class2triggerRef);
     904                 :            : 
     905                 :            :       // Initialize the merged set
     906                 :    6276964 :       TheoryIdSet newSetTags = TheoryIdSetUtil::setUnion(class1triggers.d_tags,
     907                 :            :                                                          class2triggers.d_tags);
     908                 :            :       EqualityNodeId newSetTriggers[THEORY_LAST];
     909                 :    6276964 :       unsigned newSetTriggersSize = 0;
     910                 :            : 
     911                 :    6276964 :       int i1 = 0;
     912                 :    6276964 :       int i2 = 0;
     913                 :    6276964 :       TheoryIdSet tags1 = class1triggers.d_tags;
     914                 :    6276964 :       TheoryIdSet tags2 = class2triggers.d_tags;
     915                 :    6276964 :       TheoryId tag1 = TheoryIdSetUtil::setPop(tags1);
     916                 :    6276964 :       TheoryId tag2 = TheoryIdSetUtil::setPop(tags2);
     917                 :            : 
     918                 :            :       // Comparing the THEORY_LAST is OK because all other theories are
     919                 :            :       // smaller, and will therefore be preferred
     920 [ +  + ][ +  + ]:   61389367 :       while (tag1 != THEORY_LAST || tag2 != THEORY_LAST)
     921                 :            :       {
     922         [ +  + ]:   55140980 :         if (tag1 < tag2)
     923                 :            :         {
     924                 :            :           // copy tag1
     925                 :   46781275 :           newSetTriggers[newSetTriggersSize++] =
     926                 :   46781275 :               class1triggers.d_triggers[i1++];
     927                 :   46781275 :           tag1 = TheoryIdSetUtil::setPop(tags1);
     928                 :            :         }
     929         [ +  + ]:    8359705 :         else if (tag1 > tag2)
     930                 :            :         {
     931                 :            :           // copy tag2
     932                 :       5802 :           newSetTriggers[newSetTriggersSize++] =
     933                 :       5802 :               class2triggers.d_triggers[i2++];
     934                 :       5802 :           tag2 = TheoryIdSetUtil::setPop(tags2);
     935                 :            :         }
     936                 :            :         else
     937                 :            :         {
     938                 :            :           // copy tag1
     939                 :    8353903 :           EqualityNodeId tag1id = newSetTriggers[newSetTriggersSize++] =
     940                 :    8353903 :               class1triggers.d_triggers[i1++];
     941                 :            :           // since they are both tagged notify of merge
     942                 :    8353903 :           EqualityNodeId tag2id = class2triggers.d_triggers[i2++];
     943         [ +  + ]:   16707806 :           if (!notifyTriggerTermEquality(
     944                 :   16707806 :                   tag1, d_nodes[tag1id], d_nodes[tag2id], true))
     945                 :            :           {
     946                 :      28577 :             return false;
     947                 :            :           }
     948                 :            :           // Next tags
     949                 :    8325326 :           tag1 = TheoryIdSetUtil::setPop(tags1);
     950                 :    8325326 :           tag2 = TheoryIdSetUtil::setPop(tags2);
     951                 :            :         }
     952                 :            :       }
     953                 :            : 
     954                 :            :       // Add the new trigger set, if different from previous one
     955         [ +  + ]:    6248387 :       if (class1triggers.d_tags != class2triggers.d_tags)
     956                 :            :       {
     957                 :            :         // Add it to the list for backtracking
     958                 :    3702909 :         d_triggerTermSetUpdates.push_back(
     959                 :    3702909 :             TriggerSetUpdate(class1Id, class1triggerRef));
     960                 :    3702909 :         d_triggerTermSetUpdatesSize = d_triggerTermSetUpdatesSize + 1;
     961                 :            :         // Mark the the new set as a trigger
     962                 :    3702909 :         d_nodeIndividualTrigger[class1Id] =
     963                 :    3702909 :             newTriggerTermSet(newSetTags, newSetTriggers, newSetTriggersSize);
     964                 :            :       }
     965                 :            :     }
     966                 :            :   }
     967                 :            : 
     968                 :            :   // Everything fine
     969                 :   63070788 :   return true;
     970                 :   63099418 : }
     971                 :            : 
     972                 :   63097841 : void EqualityEngine::undoMerge(EqualityNode& class1,
     973                 :            :                                EqualityNode& class2,
     974                 :            :                                EqualityNodeId class2Id)
     975                 :            : {
     976         [ +  - ]:  126195682 :   Trace("equality") << d_name << "::eq::undoMerge(" << class1.getFind() << ","
     977                 :   63097841 :                     << class2Id << ")" << std::endl;
     978                 :            : 
     979                 :            :   // Now unmerge the lists (same as merge)
     980                 :   63097841 :   class1.merge<false>(class2);
     981                 :            : 
     982                 :            :   // Update class2 representative information
     983                 :   63097841 :   EqualityNodeId currentId = class2Id;
     984         [ +  - ]:  126195682 :   Trace("equality") << d_name << "::eq::undoMerge(" << class1.getFind() << ","
     985                 :          0 :                     << class2Id << "): undoing representative info"
     986                 :   63097841 :                     << std::endl;
     987                 :            :   do
     988                 :            :   {
     989                 :            :     // Get the current node
     990                 :   81004748 :     EqualityNode& currentNode = getEqualityNode(currentId);
     991                 :            : 
     992                 :            :     // Update it's find to class1 id
     993                 :   81004748 :     currentNode.setFind(class2Id);
     994                 :            : 
     995                 :            :     // Go through the trigger list (if any) and undo the class
     996                 :   81004748 :     TriggerId currentTrigger = d_nodeTriggers[currentId];
     997         [ +  + ]:  165127987 :     while (currentTrigger != null_trigger)
     998                 :            :     {
     999                 :   84123239 :       Trigger& trigger = d_equalityTriggers[currentTrigger];
    1000                 :   84123239 :       trigger.d_classId = class2Id;
    1001                 :   84123239 :       currentTrigger = trigger.d_nextTrigger;
    1002                 :            :     }
    1003                 :            : 
    1004                 :            :     // Move to the next node
    1005                 :   81004748 :     currentId = currentNode.getNext();
    1006                 :            : 
    1007         [ +  + ]:   81004748 :   } while (currentId != class2Id);
    1008                 :   63097841 : }
    1009                 :            : 
    1010                 :  119607233 : void EqualityEngine::backtrack()
    1011                 :            : {
    1012         [ +  - ]:  119607233 :   Trace("equality::backtrack") << "backtracking" << std::endl;
    1013                 :            : 
    1014                 :            :   // If we need to backtrack then do it
    1015         [ +  + ]:  119607233 :   if (d_assertedEqualitiesCount < d_assertedEqualities.size())
    1016                 :            :   {
    1017                 :            :     // Clear the propagation queue
    1018         [ +  + ]:   10825912 :     while (!d_propagationQueue.empty())
    1019                 :            :     {
    1020                 :          6 :       d_propagationQueue.pop_front();
    1021                 :            :     }
    1022                 :            : 
    1023         [ +  - ]:   10825906 :     Trace("equality") << d_name << "::eq::backtrack(): nodes" << std::endl;
    1024                 :            : 
    1025                 :   73983609 :     for (int i = (int)d_assertedEqualities.size() - 1,
    1026                 :   10825906 :              i_end = (int)d_assertedEqualitiesCount;
    1027         [ +  + ]:   73983609 :          i >= i_end;
    1028                 :            :          --i)
    1029                 :            :     {
    1030                 :            :       // Get the ids of the merged classes
    1031                 :   63157703 :       Equality& eq = d_assertedEqualities[i];
    1032                 :            :       // Undo the merge
    1033         [ +  + ]:   63157703 :       if (eq.d_lhs != null_id)
    1034                 :            :       {
    1035                 :   63097841 :         undoMerge(
    1036                 :   63097841 :             d_equalityNodes[eq.d_lhs], d_equalityNodes[eq.d_rhs], eq.d_rhs);
    1037                 :            :       }
    1038                 :            :     }
    1039                 :            : 
    1040                 :   10825906 :     d_assertedEqualities.resize(d_assertedEqualitiesCount);
    1041                 :            : 
    1042         [ +  - ]:   10825906 :     Trace("equality") << d_name << "::eq::backtrack(): edges" << std::endl;
    1043                 :            : 
    1044                 :   10825906 :     for (int i = (int)d_equalityEdges.size() - 2,
    1045                 :   10825906 :              i_end = (int)(2 * d_assertedEqualitiesCount);
    1046         [ +  + ]:   73983609 :          i >= i_end;
    1047                 :   63157703 :          i -= 2)
    1048                 :            :     {
    1049                 :   63157703 :       EqualityEdge& edge1 = d_equalityEdges[i];
    1050                 :   63157703 :       EqualityEdge& edge2 = d_equalityEdges[i | 1];
    1051                 :   63157703 :       d_equalityGraph[edge2.getNodeId()] = edge1.getNext();
    1052                 :   63157703 :       d_equalityGraph[edge1.getNodeId()] = edge2.getNext();
    1053                 :            :     }
    1054                 :            : 
    1055                 :   10825906 :     d_equalityEdges.resize(2 * d_assertedEqualitiesCount);
    1056                 :            :   }
    1057                 :            : 
    1058         [ +  + ]:  119607233 :   if (d_triggerTermSetUpdates.size() > d_triggerTermSetUpdatesSize)
    1059                 :            :   {
    1060                 :            :     // Unset the individual triggers
    1061                 :    3226832 :     for (int i = d_triggerTermSetUpdates.size() - 1,
    1062                 :    3226832 :              i_end = d_triggerTermSetUpdatesSize;
    1063         [ +  + ]:   13569907 :          i >= i_end;
    1064                 :            :          --i)
    1065                 :            :     {
    1066                 :   10343075 :       const TriggerSetUpdate& update = d_triggerTermSetUpdates[i];
    1067                 :   10343075 :       d_nodeIndividualTrigger[update.d_classId] = update.d_oldValue;
    1068                 :            :     }
    1069                 :    3226832 :     d_triggerTermSetUpdates.resize(d_triggerTermSetUpdatesSize);
    1070                 :            :   }
    1071                 :            : 
    1072         [ +  + ]:  119607233 :   if (d_equalityTriggers.size() > d_equalityTriggersCount)
    1073                 :            :   {
    1074                 :            :     // Unlink the triggers from the lists
    1075                 :     174549 :     for (int i = d_equalityTriggers.size() - 1, i_end = d_equalityTriggersCount;
    1076         [ +  + ]:    7307557 :          i >= i_end;
    1077                 :            :          --i)
    1078                 :            :     {
    1079                 :    7133008 :       const Trigger& trigger = d_equalityTriggers[i];
    1080                 :    7133008 :       d_nodeTriggers[trigger.d_classId] = trigger.d_nextTrigger;
    1081                 :            :     }
    1082                 :            :     // Get rid of the triggers
    1083                 :     174549 :     d_equalityTriggers.resize(d_equalityTriggersCount);
    1084                 :     174549 :     d_equalityTriggersOriginal.resize(d_equalityTriggersCount);
    1085                 :            :   }
    1086                 :            : 
    1087         [ +  + ]:  119607233 :   if (d_applicationLookups.size() > d_applicationLookupsCount)
    1088                 :            :   {
    1089                 :   35264552 :     for (int i = d_applicationLookups.size() - 1,
    1090                 :    3969652 :              i_end = (int)d_applicationLookupsCount;
    1091         [ +  + ]:   35264552 :          i >= i_end;
    1092                 :            :          --i)
    1093                 :            :     {
    1094                 :   31294900 :       d_applicationLookup.erase(d_applicationLookups[i]);
    1095                 :            :     }
    1096                 :    3969652 :     d_applicationLookups.resize(d_applicationLookupsCount);
    1097                 :            :   }
    1098                 :            : 
    1099         [ +  + ]:  119607233 :   if (d_subtermEvaluates.size() > d_subtermEvaluatesSize)
    1100                 :            :   {
    1101                 :     271779 :     for (int i = d_subtermEvaluates.size() - 1,
    1102                 :     271779 :              i_end = (int)d_subtermEvaluatesSize;
    1103         [ +  + ]:    1557631 :          i >= i_end;
    1104                 :            :          --i)
    1105                 :            :     {
    1106                 :    1285852 :       d_subtermsToEvaluate[d_subtermEvaluates[i]]++;
    1107                 :            :     }
    1108                 :     271779 :     d_subtermEvaluates.resize(d_subtermEvaluatesSize);
    1109                 :            :   }
    1110                 :            : 
    1111         [ +  + ]:  119607233 :   if (d_nodes.size() > d_nodesCount)
    1112                 :            :   {
    1113                 :            :     // Go down the nodes, check the application nodes and remove them from
    1114                 :            :     // use-lists
    1115         [ +  + ]:   18272028 :     for (int i = d_nodes.size() - 1, i_end = (int)d_nodesCount; i >= i_end; --i)
    1116                 :            :     {
    1117                 :            :       // Remove from the node -> id map
    1118         [ +  - ]:   31661870 :       Trace("equality") << d_name << "::eq::backtrack(): removing node "
    1119                 :   15830935 :                         << d_nodes[i] << std::endl;
    1120                 :   15830935 :       d_nodeIds.erase(d_nodes[i]);
    1121                 :            : 
    1122                 :   15830935 :       const FunctionApplication& app = d_applications[i].d_original;
    1123         [ +  + ]:   15830935 :       if (!app.isNull())
    1124                 :            :       {
    1125                 :            :         // Remove b from use-list
    1126                 :    6441241 :         getEqualityNode(app.d_b).removeTopFromUseList(d_useListNodes);
    1127                 :            :         // Remove a from use-list
    1128                 :    6441241 :         getEqualityNode(app.d_a).removeTopFromUseList(d_useListNodes);
    1129                 :            :       }
    1130                 :            :     }
    1131                 :            : 
    1132                 :            :     // Now get rid of the nodes and the rest
    1133                 :    2441093 :     d_nodes.resize(d_nodesCount);
    1134                 :    2441093 :     d_applications.resize(d_nodesCount);
    1135                 :    2441093 :     d_nodeTriggers.resize(d_nodesCount);
    1136                 :    2441093 :     d_nodeIndividualTrigger.resize(d_nodesCount);
    1137                 :    2441093 :     d_isConstant.resize(d_nodesCount);
    1138                 :    2441093 :     d_subtermsToEvaluate.resize(d_nodesCount);
    1139                 :    2441093 :     d_isEquality.resize(d_nodesCount);
    1140                 :    2441093 :     d_isInternal.resize(d_nodesCount);
    1141                 :    2441093 :     d_equalityGraph.resize(d_nodesCount);
    1142                 :    2441093 :     d_equalityNodes.resize(d_nodesCount);
    1143                 :            :   }
    1144                 :            : 
    1145         [ +  + ]:  119607233 :   if (d_deducedDisequalities.size() > d_deducedDisequalitiesSize)
    1146                 :            :   {
    1147                 :   16925888 :     for (int i = d_deducedDisequalities.size() - 1,
    1148                 :    4426114 :              i_end = (int)d_deducedDisequalitiesSize;
    1149         [ +  + ]:   16925888 :          i >= i_end;
    1150                 :            :          --i)
    1151                 :            :     {
    1152                 :   12499774 :       EqualityPair pair = d_deducedDisequalities[i];
    1153 [ -  + ][ -  + ]:   12499774 :       Assert(d_disequalityReasonsMap.find(pair)
                 [ -  - ]
    1154                 :            :              != d_disequalityReasonsMap.end());
    1155                 :            :       // Remove from the map
    1156                 :   12499774 :       d_disequalityReasonsMap.erase(pair);
    1157                 :   12499774 :       std::swap(pair.first, pair.second);
    1158                 :   12499774 :       d_disequalityReasonsMap.erase(pair);
    1159                 :            :     }
    1160                 :    4426114 :     d_deducedDisequalityReasons.resize(d_deducedDisequalityReasonsSize);
    1161                 :    4426114 :     d_deducedDisequalities.resize(d_deducedDisequalitiesSize);
    1162                 :            :   }
    1163                 :  119607233 : }
    1164                 :            : 
    1165                 :   63159271 : void EqualityEngine::addGraphEdge(EqualityNodeId t1,
    1166                 :            :                                   EqualityNodeId t2,
    1167                 :            :                                   unsigned type,
    1168                 :            :                                   TNode reason)
    1169                 :            : {
    1170         [ +  - ]:  126318542 :   Trace("equality") << d_name << "::eq::addGraphEdge({" << t1 << "} "
    1171                 :          0 :                     << d_nodes[t1] << ", {" << t2 << "} " << d_nodes[t2] << ","
    1172                 :   63159271 :                     << reason << ")" << std::endl;
    1173                 :   63159271 :   EqualityEdgeId edge = d_equalityEdges.size();
    1174                 :   63159271 :   d_equalityEdges.push_back(
    1175                 :  126318542 :       EqualityEdge(t2, d_equalityGraph[t1], type, reason));
    1176                 :   63159271 :   d_equalityEdges.push_back(
    1177                 :  126318542 :       EqualityEdge(t1, d_equalityGraph[t2], type, reason));
    1178                 :   63159271 :   d_equalityGraph[t1] = edge;
    1179                 :   63159271 :   d_equalityGraph[t2] = edge | 1;
    1180                 :            : 
    1181         [ -  + ]:   63159271 :   if (TraceIsOn("equality::internal"))
    1182                 :            :   {
    1183                 :          0 :     debugPrintGraph();
    1184                 :            :   }
    1185                 :   63159271 : }
    1186                 :            : 
    1187                 :          0 : std::string EqualityEngine::edgesToString(EqualityEdgeId edgeId) const
    1188                 :            : {
    1189                 :          0 :   std::stringstream out;
    1190                 :          0 :   bool first = true;
    1191         [ -  - ]:          0 :   if (edgeId == null_edge)
    1192                 :            :   {
    1193                 :          0 :     out << "null";
    1194                 :            :   }
    1195                 :            :   else
    1196                 :            :   {
    1197         [ -  - ]:          0 :     while (edgeId != null_edge)
    1198                 :            :     {
    1199                 :          0 :       const EqualityEdge& edge = d_equalityEdges[edgeId];
    1200         [ -  - ]:          0 :       if (!first) out << ",";
    1201                 :          0 :       out << "{" << edge.getNodeId() << "} " << d_nodes[edge.getNodeId()];
    1202                 :          0 :       edgeId = edge.getNext();
    1203                 :          0 :       first = false;
    1204                 :            :     }
    1205                 :            :   }
    1206                 :          0 :   return out.str();
    1207                 :          0 : }
    1208                 :            : 
    1209                 :    2924987 : void EqualityEngine::buildEqConclusion(EqualityNodeId id1,
    1210                 :            :                                        EqualityNodeId id2,
    1211                 :            :                                        EqProof* eqp) const
    1212                 :            : {
    1213                 :    2924987 :   Kind k1 = d_nodes[id1].getKind();
    1214                 :    2924987 :   Kind k2 = d_nodes[id2].getKind();
    1215                 :            :   // only try to build if ids do not correspond to internal nodes. If they do,
    1216                 :            :   // only try to build build if full applications corresponding to the given ids
    1217                 :            :   // have the same congruence n-ary non-APPLY_* kind, since the internal nodes
    1218                 :            :   // may be full nodes.
    1219         [ +  + ]:    4341236 :   if ((d_isInternal[id1] || d_isInternal[id2])
    1220 [ +  + ][ +  - ]:    4725182 :       && (k1 != k2 || k1 == Kind::APPLY_UF || k1 == Kind::APPLY_CONSTRUCTOR
         [ +  + ][ +  + ]
                 [ +  + ]
    1221 [ +  - ][ +  - ]:     383946 :           || k1 == Kind::APPLY_SELECTOR || k1 == Kind::APPLY_TESTER
    1222         [ +  + ]:     383946 :           || !NodeManager::isNAryKind(k1)))
    1223                 :            :   {
    1224                 :    2910840 :     return;
    1225                 :            :   }
    1226         [ +  - ]:    2871034 :   Trace("equality") << "buildEqConclusion: {" << id1 << "} " << d_nodes[id1]
    1227                 :    1435517 :                     << "\n";
    1228         [ +  - ]:    2871034 :   Trace("equality") << "buildEqConclusion: {" << id2 << "} " << d_nodes[id2]
    1229                 :    1435517 :                     << "\n";
    1230         [ +  + ]:    8613102 :   Node eq[2];
    1231                 :    1435517 :   NodeManager* nm = nodeManager();
    1232         [ +  + ]:    4306551 :   for (unsigned i = 0; i < 2; ++i)
    1233                 :            :   {
    1234         [ +  + ]:    2871034 :     EqualityNodeId equalityNodeId = i == 0 ? id1 : id2;
    1235                 :    2871034 :     Node equalityNode = d_nodes[equalityNodeId];
    1236                 :            :     // if not an internal node, just retrieve it
    1237         [ +  + ]:    2871034 :     if (!d_isInternal[equalityNodeId])
    1238                 :            :     {
    1239                 :    2832498 :       eq[i] = equalityNode;
    1240                 :    2832498 :       continue;
    1241                 :            :     }
    1242                 :            :     // build node relative to partial application of this
    1243                 :            :     // n-ary kind. We get the full application, then we get
    1244                 :            :     // the arguments relative to how partial the internal
    1245                 :            :     // node is, and build the application
    1246                 :            : 
    1247                 :            :     // get number of children of partial app:
    1248                 :            :     // #children of full app - (id of full app - id of
    1249                 :            :     // partial app)
    1250                 :      38536 :     EqualityNodeId fullAppId = getNodeId(equalityNode);
    1251                 :      38536 :     EqualityNodeId curr = fullAppId;
    1252                 :      38536 :     unsigned separation = 0;
    1253 [ -  + ][ -  + ]:      38536 :     Assert(fullAppId >= equalityNodeId);
                 [ -  - ]
    1254         [ +  + ]:     108672 :     while (curr != equalityNodeId)
    1255                 :            :     {
    1256         [ +  + ]:      70136 :       separation = separation + (d_nodes[curr--] == equalityNode ? 1 : 0);
    1257                 :            :     }
    1258                 :            :     // compute separation, which is how many ids with the
    1259                 :            :     // same fullappnode exist between equalityNodeId and
    1260                 :            :     // fullAppId
    1261                 :      38536 :     unsigned numChildren = equalityNode.getNumChildren() - separation;
    1262 [ -  + ][ -  - ]:      38536 :     Assert(numChildren < equalityNode.getNumChildren())
    1263                 :          0 :         << "broke for numChildren " << numChildren << ", fullAppId "
    1264                 :          0 :         << fullAppId << ", equalityNodeId " << equalityNodeId << ", node "
    1265                 :      38536 :         << equalityNode << ", cong: {" << id1 << "} " << d_nodes[id1] << " = {"
    1266 [ -  + ][ -  + ]:      38536 :         << id2 << "} " << d_nodes[id2] << "\n";
                 [ -  - ]
    1267                 :            :     // if has at least as many children as the minimal
    1268                 :            :     // number of children of the n-ary kind, build the node
    1269         [ +  + ]:      38536 :     if (numChildren >= kind::metakind::getMinArityForKind(k1))
    1270                 :            :     {
    1271                 :      10242 :       std::vector<Node> children;
    1272         [ +  + ]:      33584 :       for (unsigned j = 0; j < numChildren; ++j)
    1273                 :            :       {
    1274                 :      23342 :         children.push_back(equalityNode[j]);
    1275                 :            :       }
    1276                 :      10242 :       eq[i] = nm->mkNode(k1, children);
    1277                 :      10242 :     }
    1278         [ +  + ]:    2871034 :   }
    1279                 :            :   // if built equality, add it as eqp's conclusion
    1280 [ +  + ][ +  - ]:    1435517 :   if (!eq[0].isNull() && !eq[1].isNull())
                 [ +  + ]
    1281                 :            :   {
    1282                 :    1421370 :     eqp->d_node = eq[0].eqNode(eq[1]);
    1283         [ +  - ]:    2842740 :     Trace("equality") << "buildEqConclusion: Built equality " << eqp->d_node
    1284                 :    1421370 :                       << "\n";
    1285                 :    1421370 :     return;
    1286                 :            :   }
    1287         [ +  - ]:      14147 :   Trace("equality") << "buildEqConclusion: Did not build equality\n";
    1288 [ +  + ][ -  - ]:    4306551 : }
    1289                 :            : 
    1290                 :     851337 : void EqualityEngine::explainEquality(TNode t1,
    1291                 :            :                                      TNode t2,
    1292                 :            :                                      bool polarity,
    1293                 :            :                                      std::vector<TNode>& equalities,
    1294                 :            :                                      EqProof* eqp) const
    1295                 :            : {
    1296         [ +  - ]:    1702674 :   Trace("pf::ee") << d_name << "::eq::explainEquality(" << t1 << ", " << t2
    1297         [ -  - ]:          0 :                   << ", " << (polarity ? "true" : "false") << ")"
    1298         [ -  - ]:     851337 :                   << ", proof = " << (eqp ? "ON" : "OFF") << std::endl;
    1299                 :            : 
    1300                 :            :   // The terms must be there already
    1301                 :     851337 :   Assert(hasTerm(t1) && hasTerm(t2));
    1302                 :            : 
    1303                 :            :   // Get the ids
    1304                 :     851337 :   EqualityNodeId t1Id = getNodeId(t1);
    1305                 :     851337 :   EqualityNodeId t2Id = getNodeId(t2);
    1306                 :            : 
    1307         [ +  - ]:     851337 :   Trace("pf::ee") << "Ids: " << t1Id << ", " << t2Id << "\n";
    1308                 :            : 
    1309         [ -  + ]:     851337 :   if (TraceIsOn("equality::internal"))
    1310                 :            :   {
    1311                 :          0 :     debugPrintGraph();
    1312                 :            :   }
    1313                 :            : 
    1314                 :     851337 :   std::map<std::pair<EqualityNodeId, EqualityNodeId>, EqProof*> cache;
    1315         [ +  + ]:     851337 :   if (polarity)
    1316                 :            :   {
    1317                 :            :     // Get the explanation
    1318                 :     792203 :     getExplanation(t1Id, t2Id, equalities, cache, eqp);
    1319                 :            :   }
    1320                 :            :   else
    1321                 :            :   {
    1322         [ +  + ]:      59134 :     if (eqp)
    1323                 :            :     {
    1324                 :      23638 :       eqp->d_id = MERGED_THROUGH_TRANS;
    1325                 :      23638 :       eqp->d_node = d_nodes[t1Id].eqNode(d_nodes[t2Id]).notNode();
    1326                 :            :     }
    1327                 :            : 
    1328                 :            :     // Get the reason for this disequality
    1329                 :      59134 :     EqualityPair pair(t1Id, t2Id);
    1330 [ -  + ][ -  + ]:      59134 :     Assert(d_disequalityReasonsMap.find(pair) != d_disequalityReasonsMap.end())
                 [ -  - ]
    1331                 :          0 :         << "Don't ask for stuff I didn't notify you about";
    1332                 :      59134 :     DisequalityReasonRef reasonRef = d_disequalityReasonsMap.find(pair)->second;
    1333         [ +  + ]:      59134 :     if (eqp)
    1334                 :            :     {
    1335         [ +  - ]:      47276 :       Trace("pf::ee") << "Deq reason for " << eqp->d_node << " "
    1336                 :          0 :                       << reasonRef.d_mergesStart << "..."
    1337                 :      23638 :                       << reasonRef.d_mergesEnd << std::endl;
    1338                 :            :     }
    1339         [ +  + ]:     141046 :     for (unsigned i = reasonRef.d_mergesStart; i < reasonRef.d_mergesEnd; ++i)
    1340                 :            :     {
    1341                 :      81912 :       EqualityPair toExplain = d_deducedDisequalityReasons[i];
    1342                 :      81912 :       std::shared_ptr<EqProof> eqpc;
    1343                 :            : 
    1344                 :            :       // If we're constructing a (transitivity) proof, we don't need to include
    1345                 :            :       // an explanation for x=x.
    1346 [ +  + ][ +  + ]:      81912 :       if (eqp && toExplain.first != toExplain.second)
    1347                 :            :       {
    1348                 :      27961 :         eqpc = std::make_shared<EqProof>();
    1349         [ +  - ]:      55922 :         Trace("pf::ee") << "Deq getExplanation #" << i << " for " << eqp->d_node
    1350                 :          0 :                         << " : " << toExplain.first << " " << toExplain.second
    1351                 :      27961 :                         << std::endl;
    1352                 :            :       }
    1353                 :            : 
    1354                 :      81912 :       getExplanation(
    1355                 :            :           toExplain.first, toExplain.second, equalities, cache, eqpc.get());
    1356                 :            : 
    1357         [ +  + ]:      81912 :       if (eqpc)
    1358                 :            :       {
    1359         [ -  + ]:      27961 :         if (TraceIsOn("pf::ee"))
    1360                 :            :         {
    1361         [ -  - ]:          0 :           Trace("pf::ee") << "Child proof is:" << std::endl;
    1362                 :          0 :           eqpc->debug_print("pf::ee", 1);
    1363                 :            :         }
    1364         [ +  + ]:      27961 :         if (eqpc->d_id == MERGED_THROUGH_TRANS)
    1365                 :            :         {
    1366                 :      16973 :           std::vector<std::shared_ptr<EqProof>> orderedChildren;
    1367                 :      16973 :           bool nullCongruenceFound = false;
    1368         [ +  + ]:      57781 :           for (const auto& child : eqpc->d_children)
    1369                 :            :           {
    1370                 :      40808 :             if (child->d_id == MERGED_THROUGH_CONGRUENCE
    1371 [ +  + ][ +  + ]:      40808 :                 && child->d_node.isNull())
                 [ +  + ]
    1372                 :            :             {
    1373                 :      21375 :               nullCongruenceFound = true;
    1374         [ +  - ]:      42750 :               Trace("pf::ee")
    1375                 :          0 :                   << "Have congruence with empty d_node. Splitting..."
    1376                 :      21375 :                   << std::endl;
    1377                 :      21375 :               orderedChildren.insert(orderedChildren.begin(),
    1378                 :      21375 :                                      child->d_children[0]);
    1379                 :      21375 :               orderedChildren.push_back(child->d_children[1]);
    1380                 :            :             }
    1381                 :            :             else
    1382                 :            :             {
    1383                 :      19433 :               orderedChildren.push_back(child);
    1384                 :            :             }
    1385                 :            :           }
    1386                 :            : 
    1387         [ +  + ]:      16973 :           if (nullCongruenceFound)
    1388                 :            :           {
    1389                 :      15514 :             eqpc->d_children = orderedChildren;
    1390         [ -  + ]:      15514 :             if (TraceIsOn("pf::ee"))
    1391                 :            :             {
    1392         [ -  - ]:          0 :               Trace("pf::ee")
    1393                 :          0 :                   << "Child proof's children have been reordered. It is now:"
    1394                 :          0 :                   << std::endl;
    1395                 :          0 :               eqpc->debug_print("pf::ee", 1);
    1396                 :            :             }
    1397                 :            :           }
    1398                 :      16973 :         }
    1399                 :            : 
    1400                 :      27961 :         eqp->d_children.push_back(eqpc);
    1401                 :            :       }
    1402                 :      81912 :     }
    1403                 :            : 
    1404         [ +  + ]:      59134 :     if (eqp)
    1405                 :            :     {
    1406         [ +  + ]:      23638 :       if (eqp->d_children.size() == 0)
    1407                 :            :       {
    1408                 :            :         // Corner case where this is actually a disequality between two
    1409                 :            :         // constants
    1410         [ +  - ]:         16 :         Trace("pf::ee")
    1411                 :          0 :             << "Encountered a constant disequality (not a transitivity proof): "
    1412                 :          8 :             << eqp->d_node << std::endl;
    1413 [ -  + ][ -  + ]:          8 :         Assert(eqp->d_node[0][0].isConst());
                 [ -  - ]
    1414 [ -  + ][ -  + ]:          8 :         Assert(eqp->d_node[0][1].isConst());
                 [ -  - ]
    1415                 :          8 :         eqp->d_id = MERGED_THROUGH_CONSTANTS;
    1416                 :            :       }
    1417         [ +  + ]:      23630 :       else if (eqp->d_children.size() == 1)
    1418                 :            :       {
    1419                 :      19643 :         Node cnode = eqp->d_children[0]->d_node;
    1420         [ +  - ]:      39286 :         Trace("pf::ee") << "Simplifying " << cnode << " from " << eqp->d_node
    1421                 :      19643 :                         << std::endl;
    1422                 :      19643 :         bool simpTrans = true;
    1423         [ +  - ]:      19643 :         if (cnode.getKind() == Kind::EQUAL)
    1424                 :            :         {
    1425                 :            :           // It may be the case that we have a proof of x = c2 and we want to
    1426                 :            :           // conclude x != c1. If this is the case, below we construct:
    1427                 :            :           //
    1428                 :            :           //          -------- MERGED_THROUGH_EQUALITY
    1429                 :            :           // x = c2   c1 != c2
    1430                 :            :           // ----------------- TRANS
    1431                 :            :           //     x != c1
    1432 [ +  + ][ +  + ]:      19643 :           TNode c1 = t1.isConst() ? t1 : (t2.isConst() ? t2 : TNode::null());
    1433 [ +  + ][ +  + ]:      19643 :           TNode nc = t1.isConst() ? t2 : (t2.isConst() ? t1 : TNode::null());
    1434                 :      19643 :           Node c2;
    1435                 :            :           // merge constants transitivity
    1436         [ +  + ]:      58376 :           for (unsigned i = 0; i < 2; i++)
    1437                 :            :           {
    1438                 :      39023 :             if (cnode[i].isConst() && cnode[1 - i] == nc)
    1439                 :            :             {
    1440                 :        290 :               c2 = cnode[i];
    1441                 :        290 :               break;
    1442                 :            :             }
    1443                 :            :           }
    1444 [ +  + ][ +  + ]:      19643 :           if (!c1.isNull() && !c2.isNull())
                 [ +  + ]
    1445                 :            :           {
    1446                 :        290 :             simpTrans = false;
    1447 [ -  + ][ -  + ]:        870 :             AssertEqual(c1.getType(), c2.getType());
                 [ -  - ]
    1448                 :        290 :             std::shared_ptr<EqProof> eqpmc = std::make_shared<EqProof>();
    1449                 :        290 :             eqpmc->d_id = MERGED_THROUGH_CONSTANTS;
    1450                 :        290 :             eqpmc->d_node = c1.eqNode(c2).eqNode(d_false);
    1451                 :        290 :             eqp->d_children.push_back(eqpmc);
    1452                 :        290 :           }
    1453                 :      19643 :         }
    1454         [ +  + ]:      19643 :         if (simpTrans)
    1455                 :            :         {
    1456                 :            :           // The transitivity proof has just one child. Simplify.
    1457                 :      19353 :           std::shared_ptr<EqProof> temp = eqp->d_children[0];
    1458                 :      19353 :           eqp->d_children.clear();
    1459                 :      19353 :           *eqp = *temp;
    1460                 :      19353 :         }
    1461                 :      19643 :       }
    1462                 :            : 
    1463         [ -  + ]:      23638 :       if (TraceIsOn("pf::ee"))
    1464                 :            :       {
    1465         [ -  - ]:          0 :         Trace("pf::ee") << "Disequality explanation final proof: " << std::endl;
    1466                 :          0 :         eqp->debug_print("pf::ee", 1);
    1467                 :            :       }
    1468                 :            :     }
    1469                 :            :   }
    1470                 :     851337 : }
    1471                 :            : 
    1472                 :      31444 : void EqualityEngine::explainPredicate(TNode p,
    1473                 :            :                                       bool polarity,
    1474                 :            :                                       std::vector<TNode>& assertions,
    1475                 :            :                                       EqProof* eqp) const
    1476                 :            : {
    1477         [ +  - ]:      62888 :   Trace("equality") << d_name << "::eq::explainPredicate(" << p << ")"
    1478                 :      31444 :                     << std::endl;
    1479                 :            :   // Must have the term
    1480 [ -  + ][ -  + ]:      31444 :   Assert(hasTerm(p));
                 [ -  - ]
    1481                 :      31444 :   std::map<std::pair<EqualityNodeId, EqualityNodeId>, EqProof*> cache;
    1482         [ -  + ]:      31444 :   if (TraceIsOn("equality::internal"))
    1483                 :            :   {
    1484                 :          0 :     debugPrintGraph();
    1485                 :            :   }
    1486                 :            :   // Get the explanation
    1487         [ +  + ]:      31444 :   getExplanation(
    1488                 :            :       getNodeId(p), polarity ? d_trueId : d_falseId, assertions, cache, eqp);
    1489                 :      31444 : }
    1490                 :            : 
    1491                 :     515205 : void EqualityEngine::explainLit(TNode lit,
    1492                 :            :                                 std::vector<TNode>& assumptions) const
    1493                 :            : {
    1494         [ +  - ]:     515205 :   Trace("eq-exp") << "explainLit: " << lit << std::endl;
    1495 [ -  + ][ -  + ]:     515205 :   Assert(lit.getKind() != Kind::AND);
                 [ -  - ]
    1496                 :     515205 :   bool polarity = lit.getKind() != Kind::NOT;
    1497         [ +  + ]:     515205 :   TNode atom = polarity ? lit : lit[0];
    1498                 :     515205 :   std::vector<TNode> tassumptions;
    1499         [ +  + ]:     515205 :   if (atom.getKind() == Kind::EQUAL)
    1500                 :            :   {
    1501 [ -  + ][ -  + ]:     494582 :     Assert(hasTerm(atom[0]));
                 [ -  - ]
    1502 [ -  + ][ -  + ]:     494582 :     Assert(hasTerm(atom[1]));
                 [ -  - ]
    1503         [ +  + ]:     494582 :     if (!polarity)
    1504                 :            :     {
    1505                 :            :       // ensure that we are ready to explain the disequality
    1506 [ -  + ][ -  + ]:      35494 :       AlwaysAssert(areDisequal(atom[0], atom[1], true));
                 [ -  - ]
    1507                 :            :     }
    1508         [ -  + ]:     459088 :     else if (atom[0] == atom[1])
    1509                 :            :     {
    1510                 :            :       // no need to explain reflexivity
    1511                 :          0 :       return;
    1512                 :            :     }
    1513                 :     494582 :     explainEquality(atom[0], atom[1], polarity, tassumptions);
    1514                 :            :   }
    1515                 :            :   else
    1516                 :            :   {
    1517                 :      20623 :     explainPredicate(atom, polarity, tassumptions);
    1518                 :            :   }
    1519                 :            :   // ensure that duplicates are removed
    1520         [ +  + ]:    2981733 :   for (TNode a : tassumptions)
    1521                 :            :   {
    1522                 :    2466528 :     if (std::find(assumptions.begin(), assumptions.end(), a)
    1523         [ +  + ]:    4933056 :         == assumptions.end())
    1524                 :            :     {
    1525 [ -  + ][ -  + ]:    2154150 :       Assert(!a.isNull());
                 [ -  - ]
    1526                 :    2154150 :       assumptions.push_back(a);
    1527                 :            :     }
    1528                 :    2466528 :   }
    1529 [ +  - ][ +  - ]:     515205 : }
    1530                 :            : 
    1531                 :     435236 : Node EqualityEngine::mkExplainLit(TNode lit) const
    1532                 :            : {
    1533 [ -  + ][ -  + ]:     435236 :   Assert(lit.getKind() != Kind::AND);
                 [ -  - ]
    1534                 :     435236 :   std::vector<TNode> assumptions;
    1535                 :     435236 :   explainLit(lit, assumptions);
    1536                 :     435236 :   Node ret;
    1537         [ -  + ]:     435236 :   if (assumptions.empty())
    1538                 :            :   {
    1539                 :          0 :     ret = nodeManager()->mkConst(true);
    1540                 :            :   }
    1541         [ +  + ]:     435236 :   else if (assumptions.size() == 1)
    1542                 :            :   {
    1543                 :      73977 :     ret = assumptions[0];
    1544                 :            :   }
    1545                 :            :   else
    1546                 :            :   {
    1547                 :     361259 :     ret = nodeManager()->mkNode(Kind::AND, assumptions);
    1548                 :            :   }
    1549                 :     870472 :   return ret;
    1550                 :     435236 : }
    1551                 :            : 
    1552                 :   10142870 : void EqualityEngine::getExplanation(
    1553                 :            :     EqualityNodeId t1Id,
    1554                 :            :     EqualityNodeId t2Id,
    1555                 :            :     std::vector<TNode>& equalities,
    1556                 :            :     std::map<std::pair<EqualityNodeId, EqualityNodeId>, EqProof*>& cache,
    1557                 :            :     EqProof* eqp) const
    1558                 :            : {
    1559         [ +  - ]:   20285740 :   Trace("eq-exp") << d_name << "::eq::getExplanation({" << t1Id << "} "
    1560                 :          0 :                   << d_nodes[t1Id] << ", {" << t2Id << "} " << d_nodes[t2Id]
    1561                 :   10142870 :                   << ") size = " << cache.size() << std::endl;
    1562                 :            : 
    1563                 :            :   // determine if we have already computed the explanation.
    1564                 :   10142870 :   std::pair<EqualityNodeId, EqualityNodeId> cacheKey;
    1565                 :   10142870 :   std::map<std::pair<EqualityNodeId, EqualityNodeId>, EqProof*>::iterator it;
    1566         [ +  + ]:   10142870 :   if (!eqp)
    1567                 :            :   {
    1568                 :            :     // If proofs are disabled, we order the ids, since explaining t1 = t2 is the
    1569                 :            :     // same as explaining t2 = t1.
    1570                 :    5847781 :     cacheKey = std::minmax(t1Id, t2Id);
    1571                 :    5847781 :     it = cache.find(cacheKey);
    1572         [ +  + ]:    5847781 :     if (it != cache.end())
    1573                 :            :     {
    1574                 :    2849940 :       return;
    1575                 :            :     }
    1576                 :            :   }
    1577                 :            :   else
    1578                 :            :   {
    1579                 :            :     // If proofs are enabled, note that proofs are sensitive to the order of t1
    1580                 :            :     // and t2, so we don't sort the ids in this case. TODO: Depending on how
    1581                 :            :     // issue #2965 is resolved, we may be able to revisit this, if it is the
    1582                 :            :     // case that proof/uf_proof.h,cpp is robust to equality ordering.
    1583                 :    4295089 :     cacheKey = std::pair<EqualityNodeId, EqualityNodeId>(t1Id, t2Id);
    1584                 :    4295089 :     it = cache.find(cacheKey);
    1585         [ +  + ]:    4295089 :     if (it != cache.end())
    1586                 :            :     {
    1587         [ +  + ]:    2029395 :       if (it->second)
    1588                 :            :       {
    1589                 :    2029376 :         eqp->d_id = it->second->d_id;
    1590                 :    2029376 :         eqp->d_children.insert(eqp->d_children.end(),
    1591                 :    2029376 :                                it->second->d_children.begin(),
    1592                 :    2029376 :                                it->second->d_children.end());
    1593                 :    2029376 :         eqp->d_node = it->second->d_node;
    1594                 :            :       }
    1595                 :            :       else
    1596                 :            :       {
    1597                 :            :         // We may have cached null in its place, create the trivial proof now.
    1598 [ -  + ][ -  + ]:         19 :         Assert(d_nodes[t1Id] == d_nodes[t2Id]);
                 [ -  - ]
    1599 [ -  + ][ -  + ]:         19 :         Assert(eqp->d_id == MERGED_THROUGH_REFLEXIVITY);
                 [ -  - ]
    1600                 :         19 :         eqp->d_node = d_nodes[t1Id].eqNode(d_nodes[t1Id]);
    1601                 :            :       }
    1602                 :    2029395 :       return;
    1603                 :            :     }
    1604                 :            :   }
    1605                 :    5263535 :   cache[cacheKey] = eqp;
    1606                 :            : 
    1607                 :            :   // We can only explain the nodes that got merged
    1608                 :            : #ifdef CVC5_ASSERTIONS
    1609                 :            :   bool canExplain =
    1610                 :    5263535 :       getEqualityNode(t1Id).getFind() == getEqualityNode(t2Id).getFind()
    1611 [ +  + ][ +  - ]:    5263535 :       || (d_done && isConstant(t1Id) && isConstant(t2Id));
         [ +  - ][ +  - ]
    1612                 :            : 
    1613         [ -  + ]:    5263535 :   if (!canExplain)
    1614                 :            :   {
    1615                 :          0 :     warning() << "Can't explain equality:" << std::endl;
    1616                 :          0 :     warning() << d_nodes[t1Id] << " with find "
    1617                 :          0 :               << d_nodes[getEqualityNode(t1Id).getFind()] << std::endl;
    1618                 :          0 :     warning() << d_nodes[t2Id] << " with find "
    1619                 :          0 :               << d_nodes[getEqualityNode(t2Id).getFind()] << std::endl;
    1620                 :            :   }
    1621 [ -  + ][ -  + ]:    5263535 :   Assert(canExplain);
                 [ -  - ]
    1622                 :            : #endif
    1623                 :            : 
    1624                 :            :   // If the nodes are the same, we're done
    1625         [ +  + ]:    5263535 :   if (t1Id == t2Id)
    1626                 :            :   {
    1627         [ +  + ]:    1390496 :     if (eqp)
    1628                 :            :     {
    1629                 :            :       // ignore equalities between function symbols, i.e. internal nullary
    1630                 :            :       // non-constant nodes.
    1631                 :            :       //
    1632                 :            :       // Note that this is robust for HOL because in that case function
    1633                 :            :       // symbols are not internal nodes
    1634         [ +  + ]:     772562 :       if (d_isInternal[t1Id] && d_nodes[t1Id].getNumChildren() == 0
    1635 [ +  + ][ +  - ]:     772562 :           && !d_isConstant[t1Id])
                 [ +  + ]
    1636                 :            :       {
    1637                 :     197748 :         eqp->d_node = Node::null();
    1638                 :            :       }
    1639                 :            :       else
    1640                 :            :       {
    1641 [ -  + ][ -  + ]:     376514 :         Assert(d_nodes[t1Id].getKind() != Kind::BUILTIN);
                 [ -  - ]
    1642                 :     376514 :         eqp->d_node = d_nodes[t1Id].eqNode(d_nodes[t1Id]);
    1643                 :            :       }
    1644                 :            :     }
    1645                 :    1390496 :     return;
    1646                 :            :   }
    1647                 :            : 
    1648                 :            :   // Queue for the BFS containing nodes
    1649                 :    3873039 :   std::vector<BfsData> bfsQueue;
    1650                 :            : 
    1651                 :            :   // Find a path from t1 to t2 in the graph (BFS)
    1652                 :    3873039 :   bfsQueue.push_back(BfsData(t1Id, null_id, 0));
    1653                 :    3873039 :   size_t currentIndex = 0;
    1654                 :            :   while (true)
    1655                 :            :   {
    1656                 :            :     // There should always be a path, and every node can be visited only once
    1657                 :            :     // (tree)
    1658 [ -  + ][ -  + ]:   23573856 :     Assert(currentIndex < bfsQueue.size());
                 [ -  - ]
    1659                 :            : 
    1660                 :            :     // The next node to visit
    1661                 :   23573856 :     BfsData current = bfsQueue[currentIndex];
    1662                 :   23573856 :     EqualityNodeId currentNode = current.d_nodeId;
    1663                 :            : 
    1664         [ +  - ]:   47147712 :     Trace("equality") << d_name << "::eq::getExplanation(): currentNode = {"
    1665                 :          0 :                       << currentNode << "} " << d_nodes[currentNode]
    1666                 :   23573856 :                       << std::endl;
    1667                 :            : 
    1668                 :            :     // Go through the equality edges of this node
    1669                 :   23573856 :     EqualityEdgeId currentEdge = d_equalityGraph[currentNode];
    1670         [ -  + ]:   23573856 :     if (TraceIsOn("equality"))
    1671                 :            :     {
    1672         [ -  - ]:          0 :       Trace("equality") << d_name
    1673                 :          0 :                         << "::eq::getExplanation(): edgesId =  " << currentEdge
    1674                 :          0 :                         << std::endl;
    1675         [ -  - ]:          0 :       Trace("equality") << d_name << "::eq::getExplanation(): edges =  "
    1676                 :          0 :                         << edgesToString(currentEdge) << std::endl;
    1677                 :            :     }
    1678                 :            : 
    1679         [ +  + ]:   77817781 :     while (currentEdge != null_edge)
    1680                 :            :     {
    1681                 :            :       // Get the edge
    1682                 :   58116964 :       const EqualityEdge& edge = d_equalityEdges[currentEdge];
    1683                 :            : 
    1684                 :            :       // If not just the backwards edge
    1685         [ +  + ]:   58116964 :       if ((currentEdge | 1u) != (current.d_edgeId | 1u))
    1686                 :            :       {
    1687         [ +  - ]:   79011328 :         Trace("equality") << d_name
    1688                 :          0 :                           << "::eq::getExplanation(): currentEdge = ({"
    1689                 :          0 :                           << currentNode << "} " << d_nodes[currentNode]
    1690                 :   39505664 :                           << ", {" << edge.getNodeId() << "} "
    1691                 :   39505664 :                           << d_nodes[edge.getNodeId()] << ")" << std::endl;
    1692                 :            : 
    1693                 :            :         // Did we find the path
    1694         [ +  + ]:   39505664 :         if (edge.getNodeId() == t2Id)
    1695                 :            :         {
    1696         [ +  - ]:    7746078 :           Trace("equality")
    1697                 :    3873039 :               << d_name << "::eq::getExplanation(): path found: " << std::endl;
    1698                 :            : 
    1699                 :    3873039 :           std::vector<std::shared_ptr<EqProof>> eqp_trans;
    1700                 :            : 
    1701                 :            :           // Reconstruct the path
    1702                 :            :           do
    1703                 :            :           {
    1704                 :            :             // The current node
    1705                 :    9113811 :             currentNode = bfsQueue[currentIndex].d_nodeId;
    1706                 :    9113811 :             EqualityNodeId edgeNode = d_equalityEdges[currentEdge].getNodeId();
    1707                 :            :             MergeReasonType reasonType = static_cast<MergeReasonType>(
    1708                 :    9113811 :                 d_equalityEdges[currentEdge].getReasonType());
    1709                 :    9113811 :             Node reason = d_equalityEdges[currentEdge].getReason();
    1710                 :            : 
    1711         [ +  - ]:   18227622 :             Trace("equality")
    1712                 :          0 :                 << d_name
    1713                 :          0 :                 << "::eq::getExplanation(): currentEdge = " << currentEdge
    1714                 :    9113811 :                 << ", currentNode = " << currentNode << std::endl;
    1715         [ +  - ]:   18227622 :             Trace("equality")
    1716                 :          0 :                 << d_name << "                       targetNode = {" << edgeNode
    1717                 :    9113811 :                 << "} " << d_nodes[edgeNode] << std::endl;
    1718         [ +  - ]:   18227622 :             Trace("equality")
    1719                 :          0 :                 << d_name << "                       in currentEdge = ({"
    1720                 :          0 :                 << currentNode << "} " << d_nodes[currentNode] << ", {"
    1721                 :    9113811 :                 << edge.getNodeId() << "} " << d_nodes[edge.getNodeId()] << ")"
    1722                 :    9113811 :                 << std::endl;
    1723         [ +  - ]:   18227622 :             Trace("equality")
    1724                 :          0 :                 << d_name
    1725                 :          0 :                 << "                       reason type = " << reasonType
    1726                 :    9113811 :                 << "\n";
    1727                 :            : 
    1728                 :    9113811 :             std::shared_ptr<EqProof> eqpc;
    1729                 :            :             ;
    1730                 :            :             // Make child proof if a proof is being constructed
    1731         [ +  + ]:    9113811 :             if (eqp)
    1732                 :            :             {
    1733                 :    3891753 :               eqpc = std::make_shared<EqProof>();
    1734                 :    3891753 :               eqpc->d_id = reasonType;
    1735                 :            :             }
    1736                 :            : 
    1737                 :            :             // Add the actual equality to the vector
    1738 [ +  + ][ +  + ]:    9113811 :             switch (reasonType)
    1739                 :            :             {
    1740                 :    4560191 :               case MERGED_THROUGH_CONGRUENCE:
    1741                 :            :               {
    1742                 :            :                 // f(x1, x2) == f(y1, y2) because x1 = y1 and x2 = y2
    1743         [ +  - ]:    9120382 :                 Trace("equality")
    1744                 :          0 :                     << d_name
    1745                 :          0 :                     << "::eq::getExplanation(): due to congruence, going deeper"
    1746                 :    4560191 :                     << std::endl;
    1747                 :            :                 const FunctionApplication& f1 =
    1748                 :    4560191 :                     d_applications[currentNode].d_original;
    1749                 :            :                 const FunctionApplication& f2 =
    1750                 :    4560191 :                     d_applications[edgeNode].d_original;
    1751                 :            : 
    1752         [ +  - ]:    4560191 :                 Trace("equality") << push;
    1753         [ +  - ]:    9120382 :                 Trace("equality")
    1754                 :    4560191 :                     << "Explaining left hand side equalities" << std::endl;
    1755                 :            :                 std::shared_ptr<EqProof> eqpc1 =
    1756         [ +  + ]:    4560191 :                     eqpc ? std::make_shared<EqProof>() : nullptr;
    1757                 :    4560191 :                 getExplanation(f1.d_a, f2.d_a, equalities, cache, eqpc1.get());
    1758         [ +  - ]:    9120382 :                 Trace("equality")
    1759                 :    4560191 :                     << "Explaining right hand side equalities" << std::endl;
    1760                 :            :                 std::shared_ptr<EqProof> eqpc2 =
    1761         [ +  + ]:    4560191 :                     eqpc ? std::make_shared<EqProof>() : nullptr;
    1762                 :    4560191 :                 getExplanation(f1.d_b, f2.d_b, equalities, cache, eqpc2.get());
    1763         [ +  + ]:    4560191 :                 if (eqpc)
    1764                 :            :                 {
    1765                 :    1946259 :                   eqpc->d_children.push_back(eqpc1);
    1766                 :    1946259 :                   eqpc->d_children.push_back(eqpc2);
    1767                 :            :                   // build conclusion if ids correspond to non-internal nodes or
    1768                 :            :                   // if non-internal nodes can be retrieved from them (in the
    1769                 :            :                   // case of n-ary applications), otherwise leave conclusion as
    1770                 :            :                   // null. This is only done for congruence kinds, since
    1771                 :            :                   // congruence is not used otherwise.
    1772                 :    1946259 :                   Kind k = d_nodes[currentNode].getKind();
    1773         [ +  + ]:    1946259 :                   if (d_congruenceKinds[k])
    1774                 :            :                   {
    1775                 :    1915272 :                     buildEqConclusion(currentNode, edgeNode, eqpc.get());
    1776                 :            :                   }
    1777                 :            :                   else
    1778                 :            :                   {
    1779 [ -  + ][ -  - ]:      61974 :                     Assert(k == Kind::EQUAL)
    1780 [ -  + ][ -  + ]:      30987 :                         << "not an internal node " << d_nodes[currentNode]
                 [ -  - ]
    1781                 :          0 :                         << " with non-congruence with " << k << "\n";
    1782                 :            :                   }
    1783                 :            :                 }
    1784         [ +  - ]:    4560191 :                 Trace("equality") << pop;
    1785                 :    4560191 :                 break;
    1786                 :    4560191 :               }
    1787                 :            : 
    1788                 :      25517 :               case MERGED_THROUGH_REFLEXIVITY:
    1789                 :            :               {
    1790                 :            :                 // x1 == x1
    1791         [ +  - ]:      51034 :                 Trace("equality") << d_name
    1792                 :            :                                   << "::eq::getExplanation(): due to "
    1793                 :          0 :                                      "reflexivity, going deeper"
    1794                 :      25517 :                                   << std::endl;
    1795                 :      25517 :                 EqualityNodeId eqId =
    1796         [ +  + ]:      25517 :                     currentNode == d_trueId ? edgeNode : currentNode;
    1797                 :      25517 :                 const FunctionApplication& eq = d_applications[eqId].d_original;
    1798 [ -  + ][ -  + ]:      25517 :                 Assert(eq.isEquality()) << "Must be an equality";
                 [ -  - ]
    1799                 :            : 
    1800                 :            :                 // Explain why a = b constant
    1801         [ +  - ]:      25517 :                 Trace("equality") << push;
    1802                 :            :                 std::shared_ptr<EqProof> eqpc1 =
    1803         [ +  + ]:      25517 :                     eqpc ? std::make_shared<EqProof>() : nullptr;
    1804                 :      25517 :                 getExplanation(eq.d_a, eq.d_b, equalities, cache, eqpc1.get());
    1805         [ +  + ]:      25517 :                 if (eqpc)
    1806                 :            :                 {
    1807                 :       8307 :                   eqpc->d_children.push_back(eqpc1);
    1808                 :            :                 }
    1809         [ +  - ]:      25517 :                 Trace("equality") << pop;
    1810                 :            : 
    1811                 :      25517 :                 break;
    1812                 :      25517 :               }
    1813                 :            : 
    1814                 :      46874 :               case MERGED_THROUGH_CONSTANTS:
    1815                 :            :               {
    1816                 :            :                 // f(c1, ..., cn) = c semantically, we can just ignore it
    1817         [ +  - ]:      93748 :                 Trace("equality") << d_name
    1818                 :            :                                   << "::eq::getExplanation(): due to "
    1819                 :          0 :                                      "constants, explain the constants"
    1820                 :      46874 :                                   << std::endl;
    1821         [ +  - ]:      46874 :                 Trace("equality") << push;
    1822                 :            : 
    1823                 :            :                 // Get the node we interpreted
    1824                 :      46874 :                 TNode interpreted;
    1825         [ +  + ]:      46874 :                 if (eqpc)
    1826                 :            :                 {
    1827                 :            :                   // build the conclusion f(c1, ..., cn) = c
    1828         [ +  + ]:      19503 :                   if (d_nodes[currentNode].isConst())
    1829                 :            :                   {
    1830                 :       9077 :                     interpreted = d_nodes[edgeNode];
    1831                 :       9077 :                     eqpc->d_node =
    1832                 :      18154 :                         d_nodes[edgeNode].eqNode(d_nodes[currentNode]);
    1833                 :            :                   }
    1834                 :            :                   else
    1835                 :            :                   {
    1836                 :      10426 :                     interpreted = d_nodes[currentNode];
    1837                 :      10426 :                     eqpc->d_node =
    1838                 :      20852 :                         d_nodes[currentNode].eqNode(d_nodes[edgeNode]);
    1839                 :            :                   }
    1840                 :            :                 }
    1841                 :            :                 else
    1842                 :            :                 {
    1843                 :      27371 :                   interpreted = d_nodes[currentNode].isConst()
    1844                 :      10334 :                                     ? d_nodes[edgeNode]
    1845         [ +  + ]:      37705 :                                     : d_nodes[currentNode];
    1846                 :            :                 }
    1847                 :            : 
    1848                 :            :                 // Explain why a is a constant by explaining each argument
    1849         [ +  + ]:     138286 :                 for (unsigned i = 0; i < interpreted.getNumChildren(); ++i)
    1850                 :            :                 {
    1851                 :      91412 :                   EqualityNodeId childId = getNodeId(interpreted[i]);
    1852 [ -  + ][ -  + ]:      91412 :                   Assert(isConstant(childId));
                 [ -  - ]
    1853                 :            :                   std::shared_ptr<EqProof> eqpcc =
    1854         [ +  + ]:      91412 :                       eqpc ? std::make_shared<EqProof>() : nullptr;
    1855                 :     182824 :                   getExplanation(childId,
    1856                 :      91412 :                                  getEqualityNode(childId).getFind(),
    1857                 :            :                                  equalities,
    1858                 :            :                                  cache,
    1859                 :            :                                  eqpcc.get());
    1860         [ +  + ]:      91412 :                   if (eqpc)
    1861                 :            :                   {
    1862                 :      38352 :                     eqpc->d_children.push_back(eqpcc);
    1863         [ -  + ]:      38352 :                     if (TraceIsOn("pf::ee"))
    1864                 :            :                     {
    1865         [ -  - ]:          0 :                       Trace("pf::ee")
    1866                 :          0 :                           << "MERGED_THROUGH_CONSTANTS. Dumping the child proof"
    1867                 :          0 :                           << std::endl;
    1868                 :          0 :                       eqpc->debug_print("pf::ee", 1);
    1869                 :            :                     }
    1870                 :            :                   }
    1871                 :      91412 :                 }
    1872                 :            : 
    1873         [ +  - ]:      46874 :                 Trace("equality") << pop;
    1874                 :      46874 :                 break;
    1875                 :      46874 :               }
    1876                 :            : 
    1877                 :    4481229 :               default:
    1878                 :            :               {
    1879                 :            :                 // Construct the equality
    1880         [ +  - ]:    8962458 :                 Trace("equality")
    1881                 :          0 :                     << d_name << "::eq::getExplanation(): adding: " << reason
    1882                 :    4481229 :                     << std::endl;
    1883         [ +  - ]:    8962458 :                 Trace("equality")
    1884                 :          0 :                     << d_name
    1885                 :          0 :                     << "::eq::getExplanation(): reason type = " << reasonType
    1886                 :    4481229 :                     << "\n";
    1887                 :    4481229 :                 Node a = d_nodes[currentNode];
    1888                 :    4481229 :                 Node b = d_nodes[d_equalityEdges[currentEdge].getNodeId()];
    1889                 :            : 
    1890         [ +  + ]:    4481229 :                 if (eqpc)
    1891                 :            :                 {
    1892         [ +  - ]:    1917684 :                   if (reasonType == MERGED_THROUGH_EQUALITY)
    1893                 :            :                   {
    1894                 :            :                     // in the new proof infrastructure we can assume that
    1895                 :            :                     // "theory assumptions", which are a consequence of theory
    1896                 :            :                     // reasoning on other assumptions, are externally justified.
    1897                 :            :                     // In this case we can use (= a b) directly as the
    1898                 :            :                     // conclusion here.
    1899                 :    1917684 :                     eqpc->d_node = b.eqNode(a);
    1900                 :            :                   }
    1901                 :            :                   else
    1902                 :            :                   {
    1903                 :            :                     // The LFSC translator prefers (not (= a b)) over (= (= a b)
    1904                 :            :                     // false)
    1905                 :            : 
    1906         [ -  - ]:          0 :                     if (a == nodeManager()->mkConst(false))
    1907                 :            :                     {
    1908                 :          0 :                       eqpc->d_node = b.notNode();
    1909                 :            :                     }
    1910         [ -  - ]:          0 :                     else if (b == nodeManager()->mkConst(false))
    1911                 :            :                     {
    1912                 :          0 :                       eqpc->d_node = a.notNode();
    1913                 :            :                     }
    1914                 :            :                     else
    1915                 :            :                     {
    1916                 :          0 :                       eqpc->d_node = b.eqNode(a);
    1917                 :            :                     }
    1918                 :            :                   }
    1919                 :    1917684 :                   eqpc->d_id = reasonType;
    1920                 :            :                 }
    1921                 :    4481229 :                 equalities.push_back(reason);
    1922                 :    4481229 :                 break;
    1923                 :    4481229 :               }
    1924                 :            :             }
    1925                 :            : 
    1926                 :            :             // Go to the previous
    1927                 :    9113811 :             currentEdge = bfsQueue[currentIndex].d_edgeId;
    1928                 :    9113811 :             currentIndex = bfsQueue[currentIndex].d_previousIndex;
    1929                 :            : 
    1930                 :            :             //---from Morgan---
    1931 [ +  + ][ +  + ]:    9113811 :             if (eqpc != nullptr && eqpc->d_id == MERGED_THROUGH_REFLEXIVITY)
                 [ +  + ]
    1932                 :            :             {
    1933         [ +  - ]:       8307 :               if (eqpc->d_node.isNull())
    1934                 :            :               {
    1935 [ -  + ][ -  + ]:       8307 :                 Assert(eqpc->d_children.size() == 1);
                 [ -  - ]
    1936                 :       8307 :                 std::shared_ptr<EqProof> p = eqpc;
    1937                 :       8307 :                 eqpc = p->d_children[0];
    1938                 :       8307 :               }
    1939                 :            :               else
    1940                 :            :               {
    1941                 :          0 :                 Assert(eqpc->d_children.empty());
    1942                 :            :               }
    1943                 :            :             }
    1944                 :            :             //---end from Morgan---
    1945                 :            : 
    1946                 :    9113811 :             eqp_trans.push_back(eqpc);
    1947         [ +  + ]:    9113811 :           } while (currentEdge != null_id);
    1948                 :            : 
    1949         [ +  + ]:    3873039 :           if (eqp)
    1950                 :            :           {
    1951         [ +  + ]:    1691432 :             if (eqp_trans.size() == 1)
    1952                 :            :             {
    1953                 :     681717 :               *eqp = *eqp_trans[0];
    1954                 :            :             }
    1955                 :            :             else
    1956                 :            :             {
    1957                 :    1009715 :               eqp->d_id = MERGED_THROUGH_TRANS;
    1958                 :    2019430 :               eqp->d_children.insert(
    1959                 :    1009715 :                   eqp->d_children.end(), eqp_trans.begin(), eqp_trans.end());
    1960                 :            :               // build conclusion in case of equality between non-internal
    1961                 :            :               // nodes or of n-ary congruence kinds, otherwise leave as
    1962                 :            :               // null. The latter is necessary for the overall handling of
    1963                 :            :               // congruence proofs involving n-ary kinds, see
    1964                 :            :               // EqProof::reduceNestedCongruence for more details.
    1965                 :    1009715 :               buildEqConclusion(t1Id, t2Id, eqp);
    1966                 :            :             }
    1967         [ -  + ]:    1691432 :             if (TraceIsOn("pf::ee"))
    1968                 :            :             {
    1969                 :          0 :               eqp->debug_print("pf::ee", 1);
    1970                 :            :             }
    1971                 :            :           }
    1972                 :            : 
    1973                 :            :           // Done
    1974                 :    3873039 :           return;
    1975                 :    3873039 :         }
    1976                 :            : 
    1977                 :            :         // Push to the visitation queue if it's not the backward edge
    1978                 :   35632625 :         bfsQueue.push_back(
    1979                 :   71265250 :             BfsData(edge.getNodeId(), currentEdge, currentIndex));
    1980                 :            :       }
    1981                 :            : 
    1982                 :            :       // Go to the next edge
    1983                 :   54243925 :       currentEdge = edge.getNext();
    1984                 :            :     }
    1985                 :            : 
    1986                 :            :     // Go to the next node to visit
    1987                 :   19700817 :     ++currentIndex;
    1988                 :   19700817 :   }
    1989                 :    3873039 : }
    1990                 :            : 
    1991                 :    1635637 : void EqualityEngine::addTriggerEquality(TNode eq)
    1992                 :            : {
    1993 [ -  + ][ -  + ]:    1635637 :   Assert(eq.getKind() == Kind::EQUAL);
                 [ -  - ]
    1994                 :            : 
    1995         [ +  + ]:    1635637 :   if (d_done)
    1996                 :            :   {
    1997                 :         23 :     return;
    1998                 :            :   }
    1999                 :            : 
    2000                 :            :   // Add the terms
    2001                 :    1635614 :   addTermInternal(eq[0]);
    2002                 :    1635614 :   addTermInternal(eq[1]);
    2003                 :            : 
    2004                 :    1635614 :   bool skipTrigger = false;
    2005                 :            : 
    2006                 :            :   // If they are equal or disequal already, no need for the trigger
    2007         [ +  + ]:    1635614 :   if (areEqual(eq[0], eq[1]))
    2008                 :            :   {
    2009                 :      49139 :     d_notify->eqNotifyTriggerPredicate(eq, true);
    2010                 :      49139 :     skipTrigger = true;
    2011                 :            :   }
    2012         [ +  + ]:    1635614 :   if (areDisequal(eq[0], eq[1], true))
    2013                 :            :   {
    2014                 :      24176 :     d_notify->eqNotifyTriggerPredicate(eq, false);
    2015                 :      24176 :     skipTrigger = true;
    2016                 :            :   }
    2017                 :            : 
    2018         [ +  + ]:    1635614 :   if (skipTrigger)
    2019                 :            :   {
    2020                 :      73315 :     return;
    2021                 :            :   }
    2022                 :            : 
    2023                 :            :   // Add the equality
    2024                 :    1562299 :   addTermInternal(eq);
    2025                 :            : 
    2026                 :            :   // Positive trigger
    2027                 :    1562299 :   addTriggerEqualityInternal(eq[0], eq[1], eq, true);
    2028                 :            :   // Negative trigger
    2029                 :    1562299 :   addTriggerEqualityInternal(eq, d_false, eq, false);
    2030                 :            : }
    2031                 :            : 
    2032                 :    1876701 : void EqualityEngine::addTriggerPredicate(TNode predicate)
    2033                 :            : {
    2034 [ -  + ][ -  + ]:    1876701 :   Assert(predicate.getKind() != Kind::NOT);
                 [ -  - ]
    2035         [ +  + ]:    1876701 :   if (predicate.getKind() == Kind::EQUAL)
    2036                 :            :   {
    2037                 :            :     // equality is handled separately
    2038                 :    1635637 :     return addTriggerEquality(predicate);
    2039                 :            :   }
    2040 [ -  + ][ -  + ]:     241064 :   Assert(d_congruenceKinds.test(predicate.getKind()))
                 [ -  - ]
    2041                 :          0 :       << "No point in adding non-congruence predicates, kind is "
    2042                 :            :       << predicate.getKind();
    2043                 :            : 
    2044         [ +  + ]:     241064 :   if (d_done)
    2045                 :            :   {
    2046                 :         90 :     return;
    2047                 :            :   }
    2048                 :            : 
    2049                 :            :   // Add the term
    2050                 :     240974 :   addTermInternal(predicate);
    2051                 :            : 
    2052                 :     240974 :   bool skipTrigger = false;
    2053                 :            : 
    2054                 :            :   // If it's know already, no need for the trigger
    2055         [ +  + ]:     240974 :   if (areEqual(predicate, d_true))
    2056                 :            :   {
    2057                 :      14923 :     d_notify->eqNotifyTriggerPredicate(predicate, true);
    2058                 :      14923 :     skipTrigger = true;
    2059                 :            :   }
    2060         [ +  + ]:     240974 :   if (areEqual(predicate, d_false))
    2061                 :            :   {
    2062                 :       4730 :     d_notify->eqNotifyTriggerPredicate(predicate, false);
    2063                 :       4730 :     skipTrigger = true;
    2064                 :            :   }
    2065                 :            : 
    2066         [ +  + ]:     240974 :   if (skipTrigger)
    2067                 :            :   {
    2068                 :      19653 :     return;
    2069                 :            :   }
    2070                 :            : 
    2071                 :            :   // Positive trigger
    2072                 :     221321 :   addTriggerEqualityInternal(predicate, d_true, predicate, true);
    2073                 :            :   // Negative trigger
    2074                 :     221321 :   addTriggerEqualityInternal(predicate, d_false, predicate, false);
    2075                 :            : }
    2076                 :            : 
    2077                 :    3567240 : void EqualityEngine::addTriggerEqualityInternal(TNode t1,
    2078                 :            :                                                 TNode t2,
    2079                 :            :                                                 TNode trigger,
    2080                 :            :                                                 bool polarity)
    2081                 :            : {
    2082         [ +  - ]:    7134480 :   Trace("equality") << d_name << "::eq::addTrigger(" << t1 << ", " << t2 << ", "
    2083                 :    3567240 :                     << trigger << ")" << std::endl;
    2084                 :            : 
    2085 [ -  + ][ -  + ]:    3567240 :   Assert(hasTerm(t1));
                 [ -  - ]
    2086 [ -  + ][ -  + ]:    3567240 :   Assert(hasTerm(t2));
                 [ -  - ]
    2087                 :            : 
    2088         [ -  + ]:    3567240 :   if (d_done)
    2089                 :            :   {
    2090                 :          0 :     return;
    2091                 :            :   }
    2092                 :            : 
    2093                 :            :   // Get the information about t1
    2094                 :    3567240 :   EqualityNodeId t1Id = getNodeId(t1);
    2095                 :    3567240 :   EqualityNodeId t1classId = getEqualityNode(t1Id).getFind();
    2096                 :            :   // We will attach it to the class representative, since then we know how to
    2097                 :            :   // backtrack it
    2098                 :    3567240 :   TriggerId t1TriggerId = d_nodeTriggers[t1classId];
    2099                 :            : 
    2100                 :            :   // Get the information about t2
    2101                 :    3567240 :   EqualityNodeId t2Id = getNodeId(t2);
    2102                 :    3567240 :   EqualityNodeId t2classId = getEqualityNode(t2Id).getFind();
    2103                 :            :   // We will attach it to the class representative, since then we know how to
    2104                 :            :   // backtrack it
    2105                 :    3567240 :   TriggerId t2TriggerId = d_nodeTriggers[t2classId];
    2106                 :            : 
    2107         [ +  - ]:    7134480 :   Trace("equality") << d_name << "::eq::addTrigger(" << trigger << "): " << t1Id
    2108                 :          0 :                     << " (" << t1classId << ") = " << t2Id << " (" << t2classId
    2109                 :    3567240 :                     << ")" << std::endl;
    2110                 :            : 
    2111                 :            :   // Create the triggers
    2112                 :    3567240 :   TriggerId t1NewTriggerId = d_equalityTriggers.size();
    2113                 :    3567240 :   d_equalityTriggers.push_back(Trigger(t1classId, t1TriggerId));
    2114                 :    3567240 :   d_equalityTriggersOriginal.push_back(TriggerInfo(trigger, polarity));
    2115                 :    3567240 :   TriggerId t2NewTriggerId = d_equalityTriggers.size();
    2116                 :    3567240 :   d_equalityTriggers.push_back(Trigger(t2classId, t2TriggerId));
    2117                 :    3567240 :   d_equalityTriggersOriginal.push_back(TriggerInfo(trigger, polarity));
    2118                 :            : 
    2119                 :            :   // Update the counters
    2120                 :    3567240 :   d_equalityTriggersCount = d_equalityTriggers.size();
    2121 [ -  + ][ -  + ]:    3567240 :   Assert(d_equalityTriggers.size() == d_equalityTriggersOriginal.size());
                 [ -  - ]
    2122 [ -  + ][ -  + ]:    3567240 :   Assert(d_equalityTriggers.size() % 2 == 0);
                 [ -  - ]
    2123                 :            : 
    2124                 :            :   // Add the trigger to the trigger graph
    2125                 :    3567240 :   d_nodeTriggers[t1classId] = t1NewTriggerId;
    2126                 :    3567240 :   d_nodeTriggers[t2classId] = t2NewTriggerId;
    2127                 :            : 
    2128         [ -  + ]:    3567240 :   if (TraceIsOn("equality::internal"))
    2129                 :            :   {
    2130                 :          0 :     debugPrintGraph();
    2131                 :            :   }
    2132                 :            : 
    2133         [ +  - ]:    7134480 :   Trace("equality") << d_name << "::eq::addTrigger(" << t1 << "," << t2
    2134                 :          0 :                     << ") => (" << t1NewTriggerId << ", " << t2NewTriggerId
    2135                 :    3567240 :                     << ")" << std::endl;
    2136                 :            : }
    2137                 :            : 
    2138                 :     886415 : Node EqualityEngine::evaluateTerm(TNode node)
    2139                 :            : {
    2140         [ +  - ]:    1772830 :   Trace("equality::evaluation")
    2141                 :     886415 :       << d_name << "::eq::evaluateTerm(" << node << ")" << std::endl;
    2142                 :     886415 :   NodeBuilder builder(nodeManager());
    2143                 :     886415 :   builder << node.getKind();
    2144         [ +  + ]:     886415 :   if (node.getMetaKind() == kind::metakind::PARAMETERIZED)
    2145                 :            :   {
    2146                 :         31 :     builder << node.getOperator();
    2147                 :            :   }
    2148         [ +  + ]:    2118072 :   for (unsigned i = 0; i < node.getNumChildren(); ++i)
    2149                 :            :   {
    2150                 :    1231657 :     TNode child = node[i];
    2151                 :    1231657 :     TNode childRep = getRepresentative(child);
    2152         [ +  - ]:    2463314 :     Trace("equality::evaluation") << d_name << "::eq::evaluateTerm: " << child
    2153                 :    1231657 :                                   << " -> " << childRep << std::endl;
    2154 [ -  + ][ -  + ]:    1231657 :     Assert(childRep.isConst());
                 [ -  - ]
    2155                 :    1231657 :     builder << childRep;
    2156                 :    1231657 :   }
    2157                 :     886415 :   Node newNode = builder;
    2158                 :    1772830 :   return d_env.getRewriter()->rewrite(newNode);
    2159                 :     886415 : }
    2160                 :            : 
    2161                 :     526137 : void EqualityEngine::processEvaluationQueue()
    2162                 :            : {
    2163         [ +  - ]:    1052274 :   Trace("equality::evaluation")
    2164                 :     526137 :       << d_name << "::eq::processEvaluationQueue(): start" << std::endl;
    2165                 :            : 
    2166         [ +  + ]:    1412552 :   while (!d_evaluationQueue.empty())
    2167                 :            :   {
    2168                 :            :     // Get the node
    2169                 :     886415 :     EqualityNodeId id = d_evaluationQueue.front();
    2170                 :     886415 :     d_evaluationQueue.pop();
    2171                 :            : 
    2172                 :            :     // Replace the children with their representatives (must be constants)
    2173                 :     886415 :     Node nodeEvaluated = evaluateTerm(d_nodes[id]);
    2174         [ +  - ]:    1772830 :     Trace("equality::evaluation")
    2175                 :          0 :         << d_name << "::eq::processEvaluationQueue(): " << d_nodes[id]
    2176                 :     886415 :         << " evaluates to " << nodeEvaluated << std::endl;
    2177 [ -  + ][ -  + ]:     886415 :     Assert(nodeEvaluated.isConst());
                 [ -  - ]
    2178                 :     886415 :     addTermInternal(nodeEvaluated);
    2179                 :     886415 :     EqualityNodeId nodeEvaluatedId = getNodeId(nodeEvaluated);
    2180                 :            : 
    2181                 :            :     // Enqueue the semantic equality
    2182                 :     886415 :     enqueue(MergeCandidate(
    2183                 :    1772830 :         id, nodeEvaluatedId, MERGED_THROUGH_CONSTANTS, TNode::null()));
    2184                 :     886415 :   }
    2185                 :            : 
    2186         [ +  - ]:    1052274 :   Trace("equality::evaluation")
    2187                 :     526137 :       << d_name << "::eq::processEvaluationQueue(): done" << std::endl;
    2188                 :     526137 : }
    2189                 :            : 
    2190                 :   57701341 : void EqualityEngine::propagate()
    2191                 :            : {
    2192         [ +  + ]:   57701341 :   if (d_inPropagate)
    2193                 :            :   {
    2194                 :            :     // We're already in propagate, go back
    2195                 :      48349 :     return;
    2196                 :            :   }
    2197                 :            : 
    2198                 :            :   // Make sure we don't get in again
    2199                 :   57652992 :   ScopedBool inPropagate(d_inPropagate, true);
    2200                 :            : 
    2201         [ +  - ]:   57652992 :   Trace("equality") << d_name << "::eq::propagate()" << std::endl;
    2202                 :            : 
    2203 [ +  + ][ +  + ]:  133262361 :   while (!d_propagationQueue.empty() || !d_evaluationQueue.empty())
                 [ +  + ]
    2204                 :            :   {
    2205         [ +  + ]:   75609372 :     if (d_done)
    2206                 :            :     {
    2207                 :            :       // If we're done, just empty the queue
    2208         [ +  + ]:    7838111 :       while (!d_propagationQueue.empty()) d_propagationQueue.pop_front();
    2209         [ +  + ]:     195858 :       while (!d_evaluationQueue.empty()) d_evaluationQueue.pop();
    2210                 :   12509963 :       continue;
    2211                 :            :     }
    2212                 :            : 
    2213                 :            :     // Process any evaluation requests
    2214         [ +  + ]:   75425210 :     if (!d_evaluationQueue.empty())
    2215                 :            :     {
    2216                 :     526137 :       processEvaluationQueue();
    2217                 :     526137 :       continue;
    2218                 :            :     }
    2219                 :            : 
    2220                 :            :     // The current merge candidate
    2221                 :   74899073 :     const MergeCandidate current = d_propagationQueue.front();
    2222                 :   74899073 :     d_propagationQueue.pop_front();
    2223                 :            : 
    2224                 :            :     // Get the representatives
    2225                 :   74899073 :     EqualityNodeId t1classId = getEqualityNode(current.d_t1Id).getFind();
    2226                 :   74899073 :     EqualityNodeId t2classId = getEqualityNode(current.d_t2Id).getFind();
    2227                 :            : 
    2228                 :            :     // If already the same, we're done
    2229         [ +  + ]:   74899073 :     if (t1classId == t2classId)
    2230                 :            :     {
    2231                 :   11739802 :       continue;
    2232                 :            :     }
    2233                 :            : 
    2234         [ +  - ]:  126318542 :     Trace("equality::internal")
    2235                 :          0 :         << d_name << "::eq::propagate(): t1: "
    2236         [ -  - ]:   63159271 :         << (d_isInternal[t1classId] ? "internal" : "proper") << std::endl;
    2237         [ +  - ]:  126318542 :     Trace("equality::internal")
    2238                 :          0 :         << d_name << "::eq::propagate(): t2: "
    2239         [ -  - ]:   63159271 :         << (d_isInternal[t2classId] ? "internal" : "proper") << std::endl;
    2240                 :            : 
    2241                 :            :     // Get the nodes of the representatives
    2242                 :   63159271 :     EqualityNode& node1 = getEqualityNode(t1classId);
    2243                 :   63159271 :     EqualityNode& node2 = getEqualityNode(t2classId);
    2244                 :            : 
    2245 [ -  + ][ -  + ]:   63159271 :     Assert(node1.getFind() == t1classId);
                 [ -  - ]
    2246 [ -  + ][ -  + ]:   63159271 :     Assert(node2.getFind() == t2classId);
                 [ -  - ]
    2247                 :            : 
    2248                 :            :     // Add the actual equality to the equality graph
    2249                 :  126318542 :     addGraphEdge(
    2250                 :   63159271 :         current.d_t1Id, current.d_t2Id, current.d_type, current.d_reason);
    2251                 :            : 
    2252                 :            :     // If constants are being merged we're done
    2253 [ +  + ][ +  + ]:   63159271 :     if (d_isConstant[t1classId] && d_isConstant[t2classId])
                 [ +  + ]
    2254                 :            :     {
    2255                 :            :       // When merging constants we are inconsistent, hence done
    2256                 :      59862 :       d_done = true;
    2257                 :            :       // But in order to keep invariants (edges = 2*equalities) we put an
    2258                 :            :       // equalities in Note that we can explain this merge as we have a graph
    2259                 :            :       // edge
    2260                 :      59862 :       d_assertedEqualities.push_back(Equality(null_id, null_id));
    2261                 :      59862 :       d_assertedEqualitiesCount = d_assertedEqualitiesCount + 1;
    2262                 :            :       // Notify
    2263                 :      59862 :       d_notify->eqNotifyConstantTermMerge(d_nodes[t1classId],
    2264                 :      59862 :                                           d_nodes[t2classId]);
    2265                 :            :       // Empty the queue and exit
    2266                 :      59862 :       continue;
    2267                 :            :     }
    2268                 :            : 
    2269                 :            :     // Vector to collect the triggered events
    2270                 :   63099409 :     std::vector<TriggerId> triggers;
    2271                 :            : 
    2272                 :            :     // Figure out the merge preference
    2273                 :   63099409 :     EqualityNodeId mergeInto = t1classId;
    2274         [ +  + ]:   63099409 :     if (d_isInternal[t2classId] != d_isInternal[t1classId])
    2275                 :            :     {
    2276                 :            :       // We always keep non-internal nodes as representatives: if any node in
    2277                 :            :       // the class is non-internal, then the representative will be non-internal
    2278         [ +  + ]:      95789 :       if (d_isInternal[t1classId])
    2279                 :            :       {
    2280                 :      56749 :         mergeInto = t2classId;
    2281                 :            :       }
    2282                 :            :       else
    2283                 :            :       {
    2284                 :      39040 :         mergeInto = t1classId;
    2285                 :            :       }
    2286                 :            :     }
    2287         [ +  + ]:   63003620 :     else if (d_isConstant[t2classId] != d_isConstant[t1classId])
    2288                 :            :     {
    2289                 :            :       // We always keep constants as representatives: if any (at most one) node
    2290                 :            :       // in the class in a constant, then the representative will be a constant
    2291         [ +  + ]:   44313466 :       if (d_isConstant[t2classId])
    2292                 :            :       {
    2293                 :   38995458 :         mergeInto = t2classId;
    2294                 :            :       }
    2295                 :            :       else
    2296                 :            :       {
    2297                 :    5318008 :         mergeInto = t1classId;
    2298                 :            :       }
    2299                 :            :     }
    2300         [ +  + ]:   18690154 :     else if (node2.getSize() > node1.getSize())
    2301                 :            :     {
    2302                 :            :       // We always merge into the bigger class to reduce the amount of
    2303                 :            :       // traversing we need to do
    2304                 :    8106957 :       mergeInto = t2classId;
    2305                 :            :     }
    2306                 :            : 
    2307         [ +  + ]:   63099409 :     if (mergeInto == t2classId)
    2308                 :            :     {
    2309         [ +  - ]:   94318328 :       Trace("equality") << d_name << "::eq::propagate(): merging "
    2310                 :          0 :                         << d_nodes[current.d_t1Id] << " into "
    2311                 :   47159164 :                         << d_nodes[current.d_t2Id] << std::endl;
    2312                 :   47159164 :       d_assertedEqualities.push_back(Equality(t2classId, t1classId));
    2313                 :   47159164 :       d_assertedEqualitiesCount = d_assertedEqualitiesCount + 1;
    2314         [ +  + ]:   47159164 :       if (!merge(node2, node1, triggers))
    2315                 :            :       {
    2316                 :      13095 :         d_done = true;
    2317                 :            :       }
    2318                 :            :     }
    2319                 :            :     else
    2320                 :            :     {
    2321         [ +  - ]:   31880490 :       Trace("equality") << d_name << "::eq::propagate(): merging "
    2322                 :          0 :                         << d_nodes[current.d_t2Id] << " into "
    2323                 :   15940245 :                         << d_nodes[current.d_t1Id] << std::endl;
    2324                 :   15940245 :       d_assertedEqualities.push_back(Equality(t1classId, t2classId));
    2325                 :   15940245 :       d_assertedEqualitiesCount = d_assertedEqualitiesCount + 1;
    2326         [ +  + ]:   15940245 :       if (!merge(node1, node2, triggers))
    2327                 :            :       {
    2328                 :      15523 :         d_done = true;
    2329                 :            :       }
    2330                 :            :     }
    2331                 :            : 
    2332                 :            :     // If not merging internal nodes, notify the master
    2333         [ +  + ]:   16063632 :     if (d_masterEqualityEngine && !d_isInternal[t1classId]
    2334 [ +  + ][ +  + ]:   79163038 :         && !d_isInternal[t2classId])
                 [ +  + ]
    2335                 :            :     {
    2336                 :   27939994 :       d_masterEqualityEngine->assertEqualityInternal(
    2337                 :   41909991 :           d_nodes[t1classId], d_nodes[t2classId], TNode::null());
    2338                 :   13969997 :       d_masterEqualityEngine->propagate();
    2339                 :            :     }
    2340                 :            : 
    2341                 :            :     // Notify the triggers
    2342         [ +  + ]:   63099406 :     if (!d_done)
    2343                 :            :     {
    2344                 :   87700351 :       for (size_t trigger_i = 0, trigger_end = triggers.size();
    2345 [ +  + ][ +  + ]:   87700351 :            trigger_i < trigger_end && !d_done;
                 [ +  + ]
    2346                 :            :            ++trigger_i)
    2347                 :            :       {
    2348                 :            :         const TriggerInfo& triggerInfo =
    2349                 :   24629563 :             d_equalityTriggersOriginal[triggers[trigger_i]];
    2350         [ +  + ]:   24629563 :         if (triggerInfo.d_trigger.getKind() == Kind::EQUAL)
    2351                 :            :         {
    2352                 :            :           // Special treatment for disequalities
    2353         [ +  + ]:   21177934 :           if (!triggerInfo.d_polarity)
    2354                 :            :           {
    2355                 :            :             // Store that we are propagating a diseauality
    2356                 :   10695881 :             TNode equality = triggerInfo.d_trigger;
    2357                 :   10695881 :             EqualityNodeId original = getNodeId(equality);
    2358                 :   10695881 :             TNode lhs = equality[0];
    2359                 :   10695881 :             TNode rhs = equality[1];
    2360                 :   10695881 :             EqualityNodeId lhsId = getNodeId(lhs);
    2361                 :   10695881 :             EqualityNodeId rhsId = getNodeId(rhs);
    2362                 :            :             // We use the THEORY_LAST as a marker for "marked as propagated,
    2363                 :            :             // reasons stored". This tag is added to an internal theories set
    2364                 :            :             // that is only inserted in, so this is safe. Had we iterated over,
    2365                 :            :             // or done other set operations this might be dangerous.
    2366         [ +  + ]:   10695881 :             if (!hasPropagatedDisequality(THEORY_LAST, lhsId, rhsId))
    2367                 :            :             {
    2368         [ +  + ]:   10695099 :               if (!hasPropagatedDisequality(lhsId, rhsId))
    2369                 :            :               {
    2370                 :   10660578 :                 d_deducedDisequalityReasons.push_back(
    2371                 :   21321156 :                     EqualityPair(original, d_falseId));
    2372                 :            :               }
    2373                 :   10695099 :               storePropagatedDisequality(THEORY_LAST, lhsId, rhsId);
    2374         [ +  + ]:   10695099 :               if (!d_notify->eqNotifyTriggerPredicate(triggerInfo.d_trigger,
    2375                 :   10695099 :                                                       triggerInfo.d_polarity))
    2376                 :            :               {
    2377                 :       4059 :                 d_done = true;
    2378                 :            :               }
    2379                 :            :             }
    2380                 :   10695881 :           }
    2381                 :            :           else
    2382                 :            :           {
    2383                 :            :             // Equalities are simple
    2384         [ +  + ]:   10482053 :             if (!d_notify->eqNotifyTriggerPredicate(triggerInfo.d_trigger,
    2385                 :   10482053 :                                                     triggerInfo.d_polarity))
    2386                 :            :             {
    2387                 :     120855 :               d_done = true;
    2388                 :            :             }
    2389                 :            :           }
    2390                 :            :         }
    2391                 :            :         else
    2392                 :            :         {
    2393         [ +  + ]:    3451629 :           if (!d_notify->eqNotifyTriggerPredicate(triggerInfo.d_trigger,
    2394                 :    3451629 :                                                   triggerInfo.d_polarity))
    2395                 :            :           {
    2396                 :       3153 :             d_done = true;
    2397                 :            :           }
    2398                 :            :         }
    2399                 :            :       }
    2400                 :            :     }
    2401         [ +  + ]:   74899076 :   }
    2402                 :   57652992 : }
    2403                 :            : 
    2404                 :          0 : void EqualityEngine::debugPrintGraph() const
    2405                 :            : {
    2406         [ -  - ]:          0 :   Trace("equality::internal") << std::endl << "Dumping graph" << std::endl;
    2407         [ -  - ]:          0 :   for (EqualityNodeId nodeId = 0; nodeId < d_nodes.size(); ++nodeId)
    2408                 :            :   {
    2409         [ -  - ]:          0 :     Trace("equality::internal") << d_nodes[nodeId] << " " << nodeId << "("
    2410                 :          0 :                                 << getEqualityNode(nodeId).getFind() << "):";
    2411                 :            : 
    2412                 :          0 :     EqualityEdgeId edgeId = d_equalityGraph[nodeId];
    2413         [ -  - ]:          0 :     while (edgeId != null_edge)
    2414                 :            :     {
    2415                 :          0 :       const EqualityEdge& edge = d_equalityEdges[edgeId];
    2416         [ -  - ]:          0 :       Trace("equality::internal")
    2417                 :          0 :           << " [" << edge.getNodeId() << "] " << d_nodes[edge.getNodeId()]
    2418                 :          0 :           << ":" << edge.getReason();
    2419                 :          0 :       edgeId = edge.getNext();
    2420                 :            :     }
    2421                 :            : 
    2422         [ -  - ]:          0 :     Trace("equality::internal") << std::endl;
    2423                 :            :   }
    2424         [ -  - ]:          0 :   Trace("equality::internal") << std::endl;
    2425                 :          0 : }
    2426                 :            : 
    2427                 :          0 : std::string EqualityEngine::debugPrintEqc() const
    2428                 :            : {
    2429                 :          0 :   std::stringstream ss;
    2430                 :          0 :   eq::EqClassesIterator eqcs2_i = eq::EqClassesIterator(this);
    2431         [ -  - ]:          0 :   while (!eqcs2_i.isFinished())
    2432                 :            :   {
    2433                 :          0 :     Node eqc = (*eqcs2_i);
    2434                 :          0 :     eq::EqClassIterator eqc2_i = eq::EqClassIterator(eqc, this);
    2435                 :          0 :     ss << "Eqc( " << eqc << " ) : { ";
    2436         [ -  - ]:          0 :     while (!eqc2_i.isFinished())
    2437                 :            :     {
    2438                 :          0 :       if ((*eqc2_i) != eqc && (*eqc2_i).getKind() != Kind::EQUAL)
    2439                 :            :       {
    2440                 :          0 :         ss << (*eqc2_i) << " ";
    2441                 :            :       }
    2442                 :          0 :       ++eqc2_i;
    2443                 :            :     }
    2444                 :          0 :     ss << " } " << std::endl;
    2445                 :          0 :     ++eqcs2_i;
    2446                 :          0 :   }
    2447                 :          0 :   return ss.str();
    2448                 :          0 : }
    2449                 :            : 
    2450                 :   62346428 : bool EqualityEngine::areEqual(TNode t1, TNode t2) const
    2451                 :            : {
    2452         [ +  - ]:   62346428 :   Trace("equality") << d_name << "::eq::areEqual(" << t1 << "," << t2 << ")";
    2453                 :            : 
    2454 [ -  + ][ -  + ]:   62346428 :   Assert(hasTerm(t1));
                 [ -  - ]
    2455 [ -  + ][ -  + ]:   62346428 :   Assert(hasTerm(t2));
                 [ -  - ]
    2456                 :            : 
    2457                 :   62346428 :   bool result = getEqualityNode(t1).getFind() == getEqualityNode(t2).getFind();
    2458 [ +  - ][ -  - ]:   62346428 :   Trace("equality") << (result ? "\t(YES)" : "\t(NO)") << std::endl;
    2459                 :   62346428 :   return result;
    2460                 :            : }
    2461                 :            : 
    2462                 :   22862849 : bool EqualityEngine::areDisequal(TNode t1, TNode t2, bool ensureProof) const
    2463                 :            : {
    2464         [ +  - ]:   22862849 :   Trace("equality") << d_name << "::eq::areDisequal(" << t1 << "," << t2 << ")";
    2465                 :            : 
    2466                 :            :   // Add the terms
    2467 [ -  + ][ -  + ]:   22862849 :   Assert(hasTerm(t1));
                 [ -  - ]
    2468 [ -  + ][ -  + ]:   22862849 :   Assert(hasTerm(t2));
                 [ -  - ]
    2469                 :            : 
    2470                 :            :   // Get ids
    2471                 :   22862849 :   EqualityNodeId t1Id = getNodeId(t1);
    2472                 :   22862849 :   EqualityNodeId t2Id = getNodeId(t2);
    2473                 :            : 
    2474                 :            :   // If we propagated this disequality we're true
    2475         [ +  + ]:   22862849 :   if (hasPropagatedDisequality(t1Id, t2Id))
    2476                 :            :   {
    2477         [ +  - ]:    7626312 :     Trace("equality") << "\t(YES)" << std::endl;
    2478                 :    7626312 :     return true;
    2479                 :            :   }
    2480                 :            : 
    2481                 :            :   // Get equivalence classes
    2482                 :   15236537 :   EqualityNodeId t1ClassId = getEqualityNode(t1Id).getFind();
    2483                 :   15236537 :   EqualityNodeId t2ClassId = getEqualityNode(t2Id).getFind();
    2484                 :            : 
    2485                 :            :   // We are semantically const, for remembering stuff
    2486                 :   15236537 :   EqualityEngine* nonConst = const_cast<EqualityEngine*>(this);
    2487                 :            : 
    2488                 :            :   // Check for constants
    2489         [ +  + ]:   19862103 :   if (d_isConstant[t1ClassId] && d_isConstant[t2ClassId]
    2490 [ +  + ][ +  + ]:   19862103 :       && t1ClassId != t2ClassId)
                 [ +  + ]
    2491                 :            :   {
    2492         [ +  + ]:     117530 :     if (ensureProof)
    2493                 :            :     {
    2494                 :      15433 :       nonConst->d_deducedDisequalityReasons.push_back(
    2495                 :          0 :           EqualityPair(t1Id, t1ClassId));
    2496                 :      15433 :       nonConst->d_deducedDisequalityReasons.push_back(
    2497                 :          0 :           EqualityPair(t2Id, t2ClassId));
    2498                 :      15433 :       nonConst->storePropagatedDisequality(THEORY_LAST, t1Id, t2Id);
    2499                 :            :     }
    2500         [ +  - ]:     117530 :     Trace("equality") << "\t(YES)" << std::endl;
    2501                 :     117530 :     return true;
    2502                 :            :   }
    2503                 :            : 
    2504                 :            :   // Create the equality
    2505                 :   15119007 :   FunctionApplication eqNormalized(APP_EQUALITY, t1ClassId, t2ClassId);
    2506                 :            :   ApplicationIdsMap::const_iterator find =
    2507                 :   15119007 :       d_applicationLookup.find(eqNormalized);
    2508         [ +  + ]:   15119007 :   if (find != d_applicationLookup.end())
    2509                 :            :   {
    2510                 :    6230274 :     if (getEqualityNode(find->second).getFind()
    2511         [ +  + ]:    6230274 :         == getEqualityNode(d_falseId).getFind())
    2512                 :            :     {
    2513         [ +  + ]:     744729 :       if (ensureProof)
    2514                 :            :       {
    2515                 :            :         const FunctionApplication original =
    2516                 :       8479 :             d_applications[find->second].d_original;
    2517                 :       8479 :         nonConst->d_deducedDisequalityReasons.push_back(
    2518                 :       8479 :             EqualityPair(t1Id, original.d_a));
    2519                 :       8479 :         nonConst->d_deducedDisequalityReasons.push_back(
    2520                 :       8479 :             EqualityPair(find->second, d_falseId));
    2521                 :       8479 :         nonConst->d_deducedDisequalityReasons.push_back(
    2522                 :       8479 :             EqualityPair(t2Id, original.d_b));
    2523                 :       8479 :         nonConst->storePropagatedDisequality(THEORY_LAST, t1Id, t2Id);
    2524                 :            :       }
    2525         [ +  - ]:     744729 :       Trace("equality") << "\t(YES)" << std::endl;
    2526                 :     744729 :       return true;
    2527                 :            :     }
    2528                 :            :   }
    2529                 :            : 
    2530                 :            :   // Check the symmetric disequality
    2531                 :   14374278 :   std::swap(eqNormalized.d_a, eqNormalized.d_b);
    2532                 :   14374278 :   find = d_applicationLookup.find(eqNormalized);
    2533         [ +  + ]:   14374278 :   if (find != d_applicationLookup.end())
    2534                 :            :   {
    2535                 :    1254661 :     if (getEqualityNode(find->second).getFind()
    2536         [ +  + ]:    1254661 :         == getEqualityNode(d_falseId).getFind())
    2537                 :            :     {
    2538         [ +  + ]:     965796 :       if (ensureProof)
    2539                 :            :       {
    2540                 :            :         const FunctionApplication original =
    2541                 :       3726 :             d_applications[find->second].d_original;
    2542                 :       3726 :         nonConst->d_deducedDisequalityReasons.push_back(
    2543                 :       3726 :             EqualityPair(t2Id, original.d_a));
    2544                 :       3726 :         nonConst->d_deducedDisequalityReasons.push_back(
    2545                 :       3726 :             EqualityPair(find->second, d_falseId));
    2546                 :       3726 :         nonConst->d_deducedDisequalityReasons.push_back(
    2547                 :       3726 :             EqualityPair(t1Id, original.d_b));
    2548                 :       3726 :         nonConst->storePropagatedDisequality(THEORY_LAST, t1Id, t2Id);
    2549                 :            :       }
    2550         [ +  - ]:     965796 :       Trace("equality") << "\t(YES)" << std::endl;
    2551                 :     965796 :       return true;
    2552                 :            :     }
    2553                 :            :   }
    2554                 :            : 
    2555                 :            :   // Couldn't deduce dis-equalityReturn whether the terms are disequal
    2556         [ +  - ]:   13408482 :   Trace("equality") << "\t(NO)" << std::endl;
    2557                 :   13408482 :   return false;
    2558                 :            : }
    2559                 :            : 
    2560                 :          0 : size_t EqualityEngine::getSize(TNode t)
    2561                 :            : {
    2562                 :            :   // Add the term
    2563                 :          0 :   addTermInternal(t);
    2564                 :          0 :   return getEqualityNode(getEqualityNode(t).getFind()).getSize();
    2565                 :            : }
    2566                 :            : 
    2567                 :     277218 : std::string EqualityEngine::identify() const { return d_name; }
    2568                 :            : 
    2569                 :    7858354 : void EqualityEngine::addTriggerTerm(TNode t, TheoryId tag)
    2570                 :            : {
    2571         [ +  - ]:   15716708 :   Trace("equality::trigger") << d_name << "::eq::addTriggerTerm(" << t << ", "
    2572                 :    7858354 :                              << tag << ")" << std::endl;
    2573                 :            : 
    2574 [ -  + ][ -  + ]:    7858354 :   Assert(tag != THEORY_LAST);
                 [ -  - ]
    2575                 :            : 
    2576         [ +  + ]:    7858354 :   if (d_done)
    2577                 :            :   {
    2578                 :          3 :     return;
    2579                 :            :   }
    2580                 :            : 
    2581                 :            :   // Add the term if it's not already there
    2582                 :    7858351 :   addTermInternal(t);
    2583                 :            : 
    2584         [ -  + ]:    7858351 :   if (!d_anyTermsAreTriggers)
    2585                 :            :   {
    2586                 :            :     // if we are not using triggers, we only add the term, but not as a trigger
    2587                 :          0 :     return;
    2588                 :            :   }
    2589                 :            : 
    2590                 :            :   // Get the node id
    2591                 :    7858351 :   EqualityNodeId eqNodeId = getNodeId(t);
    2592                 :    7858351 :   EqualityNode& eqNode = getEqualityNode(eqNodeId);
    2593                 :    7858351 :   EqualityNodeId classId = eqNode.getFind();
    2594                 :            : 
    2595                 :            :   // Possibly existing set of triggers
    2596                 :    7858351 :   TriggerTermSetRef triggerSetRef = d_nodeIndividualTrigger[classId];
    2597                 :    7858351 :   if (triggerSetRef != +null_set_id
    2598 [ +  + ][ +  + ]:    7858351 :       && getTriggerTermSet(triggerSetRef).hasTrigger(tag))
                 [ +  + ]
    2599                 :            :   {
    2600                 :            :     // If the term already is in the equivalence class that a tagged
    2601                 :            :     // representative, just notify
    2602                 :    2144519 :     EqualityNodeId triggerId = getTriggerTermSet(triggerSetRef).getTrigger(tag);
    2603         [ +  - ]:    4289038 :     Trace("equality::trigger")
    2604                 :          0 :         << d_name << "::eq::addTriggerTerm(" << t << ", " << tag
    2605                 :          0 :         << "): already have this trigger in class with " << d_nodes[triggerId]
    2606                 :    2144519 :         << std::endl;
    2607                 :    2144519 :     if (eqNodeId != triggerId
    2608                 :    2144519 :         && !notifyTriggerTermEquality(tag, t, d_nodes[triggerId], true))
    2609                 :            :     {
    2610                 :       1913 :       d_done = true;
    2611                 :            :     }
    2612                 :            :   }
    2613                 :            :   else
    2614                 :            :   {
    2615                 :            :     // Check for disequalities by going through the equivalence class looking
    2616                 :            :     // for equalities in the uselists that have been asserted to false. All the
    2617                 :            :     // representatives appearing on the other side of such disequalities, that
    2618                 :            :     // have the tag on, are put in a set.
    2619                 :    5713832 :     TaggedEqualitiesSet disequalitiesToNotify;
    2620                 :    5713832 :     TheoryIdSet tags = TheoryIdSetUtil::setInsert(tag);
    2621                 :    5713832 :     getDisequalities(
    2622                 :    5713832 :         !d_isConstant[classId], classId, tags, disequalitiesToNotify);
    2623                 :            : 
    2624                 :            :     // Trigger data
    2625                 :            :     TheoryIdSet newSetTags;
    2626                 :            :     EqualityNodeId newSetTriggers[THEORY_LAST];
    2627                 :            :     unsigned newSetTriggersSize;
    2628                 :            : 
    2629                 :            :     // Setup the data for the new set
    2630         [ +  + ]:    5713832 :     if (triggerSetRef != null_set_id)
    2631                 :            :     {
    2632                 :            :       // Get the existing set
    2633                 :    1316456 :       TriggerTermSet& triggerSet = getTriggerTermSet(triggerSetRef);
    2634                 :            :       // Initialize the new set for copy/insert
    2635                 :    1316456 :       newSetTags = TheoryIdSetUtil::setInsert(tag, triggerSet.d_tags);
    2636                 :    1316456 :       newSetTriggersSize = 0;
    2637                 :            :       // Copy into to new one, and insert the new tag/id
    2638                 :    1316456 :       unsigned i = 0;
    2639                 :    1316456 :       TheoryIdSet tags2 = newSetTags;
    2640                 :            :       TheoryId current;
    2641         [ +  + ]:    3994236 :       while ((current = TheoryIdSetUtil::setPop(tags2)) != THEORY_LAST)
    2642                 :            :       {
    2643                 :            :         // Remove from the tags
    2644                 :    2677780 :         tags2 = TheoryIdSetUtil::setRemove(current, tags2);
    2645                 :            :         // Insert the id into the triggers
    2646                 :    2677780 :         newSetTriggers[newSetTriggersSize++] =
    2647         [ +  + ]:    2677780 :             current == tag ? eqNodeId : triggerSet.d_triggers[i++];
    2648                 :            :       }
    2649                 :            :     }
    2650                 :            :     else
    2651                 :            :     {
    2652                 :            :       // Setup a singleton
    2653                 :    4397376 :       newSetTags = TheoryIdSetUtil::setInsert(tag);
    2654                 :    4397376 :       newSetTriggers[0] = eqNodeId;
    2655                 :    4397376 :       newSetTriggersSize = 1;
    2656                 :            :     }
    2657                 :            : 
    2658                 :            :     // Add it to the list for backtracking
    2659                 :    5713832 :     d_triggerTermSetUpdates.push_back(TriggerSetUpdate(classId, triggerSetRef));
    2660                 :    5713832 :     d_triggerTermSetUpdatesSize = d_triggerTermSetUpdatesSize + 1;
    2661                 :            :     // Mark the the new set as a trigger
    2662                 :   11427664 :     d_nodeIndividualTrigger[classId] = triggerSetRef =
    2663                 :    5713832 :         newTriggerTermSet(newSetTags, newSetTriggers, newSetTriggersSize);
    2664                 :            : 
    2665                 :            :     // Propagate trigger term disequalities we remembered
    2666         [ +  - ]:   11427664 :     Trace("equality::trigger")
    2667                 :          0 :         << d_name << "::eq::addTriggerTerm(" << t << ", " << tag
    2668                 :    5713832 :         << "): propagating " << disequalitiesToNotify.size()
    2669                 :    5713832 :         << " disequalities " << std::endl;
    2670                 :    5713832 :     propagateTriggerTermDisequalities(
    2671                 :            :         tags, triggerSetRef, disequalitiesToNotify);
    2672                 :    5713832 :   }
    2673                 :            : }
    2674                 :            : 
    2675                 :   13603368 : bool EqualityEngine::isTriggerTerm(TNode t, TheoryId tag) const
    2676                 :            : {
    2677         [ +  + ]:   13603368 :   if (!hasTerm(t)) return false;
    2678                 :   13603259 :   EqualityNodeId classId = getEqualityNode(t).getFind();
    2679                 :   13603259 :   TriggerTermSetRef triggerSetRef = d_nodeIndividualTrigger[classId];
    2680                 :            :   return triggerSetRef != +null_set_id
    2681 [ +  + ][ +  - ]:   13603259 :          && getTriggerTermSet(triggerSetRef).hasTrigger(tag);
    2682                 :            : }
    2683                 :            : 
    2684                 :    4521371 : TNode EqualityEngine::getTriggerTermRepresentative(TNode t, TheoryId tag) const
    2685                 :            : {
    2686 [ -  + ][ -  + ]:    4521371 :   Assert(isTriggerTerm(t, tag));
                 [ -  - ]
    2687                 :    4521371 :   EqualityNodeId classId = getEqualityNode(t).getFind();
    2688                 :            :   const TriggerTermSet& triggerSet =
    2689                 :    4521371 :       getTriggerTermSet(d_nodeIndividualTrigger[classId]);
    2690                 :    4521371 :   unsigned i = 0;
    2691                 :    4521371 :   TheoryIdSet tags = triggerSet.d_tags;
    2692         [ +  + ]:    7854861 :   while (TheoryIdSetUtil::setPop(tags) != tag)
    2693                 :            :   {
    2694                 :    3333490 :     ++i;
    2695                 :            :   }
    2696                 :    9042742 :   return d_nodes[triggerSet.d_triggers[i]];
    2697                 :            : }
    2698                 :            : 
    2699                 :   31295853 : void EqualityEngine::storeApplicationLookup(FunctionApplication& funNormalized,
    2700                 :            :                                             EqualityNodeId funId)
    2701                 :            : {
    2702 [ -  + ][ -  + ]:   31295853 :   Assert(d_applicationLookup.find(funNormalized) == d_applicationLookup.end());
                 [ -  - ]
    2703                 :   31295853 :   d_applicationLookup[funNormalized] = funId;
    2704                 :   31295853 :   d_applicationLookups.push_back(funNormalized);
    2705                 :   31295853 :   d_applicationLookupsCount = d_applicationLookupsCount + 1;
    2706         [ +  - ]:   62591706 :   Trace("equality::backtrack")
    2707                 :          0 :       << "d_applicationLookupsCount = " << d_applicationLookupsCount
    2708                 :   31295853 :       << std::endl;
    2709         [ +  - ]:   62591706 :   Trace("equality::backtrack")
    2710                 :   31295853 :       << "d_applicationLookups.size() = " << d_applicationLookups.size()
    2711                 :   31295853 :       << std::endl;
    2712 [ -  + ][ -  + ]:   31295853 :   Assert(d_applicationLookupsCount == d_applicationLookups.size());
                 [ -  - ]
    2713                 :            : 
    2714                 :            :   // If an equality over constants we merge to false
    2715         [ +  + ]:   31295853 :   if (funNormalized.isEquality())
    2716                 :            :   {
    2717         [ +  + ]:   23920710 :     if (funNormalized.d_a == funNormalized.d_b)
    2718                 :            :     {
    2719                 :    2469336 :       enqueue(MergeCandidate(
    2720                 :    4938672 :           funId, d_trueId, MERGED_THROUGH_REFLEXIVITY, TNode::null()));
    2721                 :            :     }
    2722 [ +  + ][ +  + ]:   21451374 :     else if (d_isConstant[funNormalized.d_a] && d_isConstant[funNormalized.d_b])
                 [ +  + ]
    2723                 :            :     {
    2724                 :    1735010 :       enqueue(MergeCandidate(
    2725                 :    3470020 :           funId, d_falseId, MERGED_THROUGH_CONSTANTS, TNode::null()));
    2726                 :            :     }
    2727                 :            :   }
    2728                 :   31295853 : }
    2729                 :            : 
    2730                 :   11437692 : EqualityEngine::TriggerTermSetRef EqualityEngine::newTriggerTermSet(
    2731                 :            :     TheoryIdSet newSetTags,
    2732                 :            :     EqualityNodeId* newSetTriggers,
    2733                 :            :     unsigned newSetTriggersSize)
    2734                 :            : {
    2735                 :            :   // Size of the required set
    2736                 :   11437692 :   size_t size =
    2737                 :   11437692 :       sizeof(TriggerTermSet) + newSetTriggersSize * sizeof(EqualityNodeId);
    2738                 :            :   // Align the size
    2739                 :   11437692 :   size = (size + 7) & ~((size_t)7);
    2740                 :            :   // Reallocate if necessary
    2741         [ -  + ]:   11437692 :   if (d_triggerDatabaseSize + size > d_triggerDatabaseAllocatedSize)
    2742                 :            :   {
    2743                 :          0 :     d_triggerDatabaseAllocatedSize *= 2;
    2744                 :          0 :     d_triggerDatabase =
    2745                 :          0 :         (char*)realloc(d_triggerDatabase, d_triggerDatabaseAllocatedSize);
    2746                 :            :   }
    2747                 :            :   // New reference
    2748                 :   11437692 :   TriggerTermSetRef newTriggerSetRef = d_triggerDatabaseSize;
    2749                 :            :   // Update the size
    2750                 :   11437692 :   d_triggerDatabaseSize = d_triggerDatabaseSize + size;
    2751                 :            :   // Copy the information
    2752                 :   11437692 :   TriggerTermSet& newSet = getTriggerTermSet(newTriggerSetRef);
    2753                 :   11437692 :   newSet.d_tags = newSetTags;
    2754         [ +  + ]:   98461673 :   for (unsigned i = 0; i < newSetTriggersSize; ++i)
    2755                 :            :   {
    2756                 :   87023981 :     newSet.d_triggers[i] = newSetTriggers[i];
    2757                 :            :   }
    2758                 :            :   // Return the new reference
    2759                 :   11437692 :   return newTriggerSetRef;
    2760                 :            : }
    2761                 :            : 
    2762                 :   37420981 : bool EqualityEngine::hasPropagatedDisequality(EqualityNodeId lhsId,
    2763                 :            :                                               EqualityNodeId rhsId) const
    2764                 :            : {
    2765                 :   37420981 :   EqualityPair eq(lhsId, rhsId);
    2766                 :            :   bool propagated =
    2767                 :   37420981 :       d_propagatedDisequalities.find(eq) != d_propagatedDisequalities.end();
    2768                 :            : #ifdef CVC5_ASSERTIONS
    2769                 :            :   bool stored =
    2770                 :   37420981 :       d_disequalityReasonsMap.find(eq) != d_disequalityReasonsMap.end();
    2771 [ -  + ][ -  + ]:   37420981 :   Assert(propagated == stored) << "These two should be in sync";
                 [ -  - ]
    2772                 :            : #endif
    2773         [ +  - ]:   74841962 :   Trace("equality::disequality")
    2774                 :          0 :       << d_name << "::eq::hasPropagatedDisequality(" << d_nodes[lhsId] << ", "
    2775         [ -  - ]:   37420981 :       << d_nodes[rhsId] << ") => " << (propagated ? "true" : "false")
    2776                 :   37420981 :       << std::endl;
    2777                 :   37420981 :   return propagated;
    2778                 :            : }
    2779                 :            : 
    2780                 :   31404763 : bool EqualityEngine::hasPropagatedDisequality(TheoryId tag,
    2781                 :            :                                               EqualityNodeId lhsId,
    2782                 :            :                                               EqualityNodeId rhsId) const
    2783                 :            : {
    2784                 :   31404763 :   EqualityPair eq(lhsId, rhsId);
    2785                 :            : 
    2786                 :            :   PropagatedDisequalitiesMap::const_iterator it =
    2787                 :   31404763 :       d_propagatedDisequalities.find(eq);
    2788         [ +  + ]:   31404763 :   if (it == d_propagatedDisequalities.end())
    2789                 :            :   {
    2790 [ -  + ][ -  + ]:   24972158 :     Assert(d_disequalityReasonsMap.find(eq) == d_disequalityReasonsMap.end())
                 [ -  - ]
    2791                 :          0 :         << "Why do we have a proof if not propagated";
    2792         [ +  - ]:   49944316 :     Trace("equality::disequality")
    2793                 :          0 :         << d_name << "::eq::hasPropagatedDisequality(" << tag << ", "
    2794                 :          0 :         << d_nodes[lhsId] << ", " << d_nodes[rhsId] << ") => false"
    2795                 :   24972158 :         << std::endl;
    2796                 :   24972158 :     return false;
    2797                 :            :   }
    2798 [ -  + ][ -  + ]:    6432605 :   Assert(d_disequalityReasonsMap.find(eq) != d_disequalityReasonsMap.end())
                 [ -  - ]
    2799                 :          0 :       << "We propagated but there is no proof";
    2800                 :    6432605 :   bool result = TheoryIdSetUtil::setContains(tag, (*it).second);
    2801         [ +  - ]:   12865210 :   Trace("equality::disequality")
    2802                 :          0 :       << d_name << "::eq::hasPropagatedDisequality(" << tag << ", "
    2803                 :          0 :       << d_nodes[lhsId] << ", " << d_nodes[rhsId] << ") => "
    2804         [ -  - ]:    6432605 :       << (result ? "true" : "false") << std::endl;
    2805                 :    6432605 :   return result;
    2806                 :            : }
    2807                 :            : 
    2808                 :   14585770 : void EqualityEngine::storePropagatedDisequality(TheoryId tag,
    2809                 :            :                                                 EqualityNodeId lhsId,
    2810                 :            :                                                 EqualityNodeId rhsId)
    2811                 :            : {
    2812 [ -  + ][ -  + ]:   14585770 :   Assert(!hasPropagatedDisequality(tag, lhsId, rhsId))
                 [ -  - ]
    2813                 :          0 :       << "Check before you store it";
    2814 [ -  + ][ -  + ]:   14585770 :   Assert(lhsId != rhsId) << "Wow, wtf!";
                 [ -  - ]
    2815                 :            : 
    2816         [ +  - ]:   29171540 :   Trace("equality::disequality")
    2817                 :          0 :       << d_name << "::eq::storePropagatedDisequality(" << tag << ", "
    2818                 :   14585770 :       << d_nodes[lhsId] << ", " << d_nodes[rhsId] << ")" << std::endl;
    2819                 :            : 
    2820                 :   14585770 :   EqualityPair pair1(lhsId, rhsId);
    2821                 :   14585770 :   EqualityPair pair2(rhsId, lhsId);
    2822                 :            : 
    2823                 :            :   // Store the fact that we've propagated this already
    2824                 :   14585770 :   TheoryIdSet notified = 0;
    2825                 :            :   PropagatedDisequalitiesMap::const_iterator find =
    2826                 :   14585770 :       d_propagatedDisequalities.find(pair1);
    2827         [ +  + ]:   14585770 :   if (find == d_propagatedDisequalities.end())
    2828                 :            :   {
    2829                 :   12499898 :     notified = TheoryIdSetUtil::setInsert(tag);
    2830                 :            :   }
    2831                 :            :   else
    2832                 :            :   {
    2833                 :    2085872 :     notified = TheoryIdSetUtil::setInsert(tag, (*find).second);
    2834                 :            :   }
    2835                 :   14585770 :   d_propagatedDisequalities[pair1] = notified;
    2836                 :   14585770 :   d_propagatedDisequalities[pair2] = notified;
    2837                 :            : 
    2838                 :            :   // Store the proof if provided
    2839         [ +  + ]:   14585770 :   if (d_deducedDisequalityReasons.size() > d_deducedDisequalityReasonsSize)
    2840                 :            :   {
    2841         [ +  - ]:   24999796 :     Trace("equality::disequality")
    2842                 :          0 :         << d_name << "::eq::storePropagatedDisequality(" << tag << ", "
    2843                 :          0 :         << d_nodes[lhsId] << ", " << d_nodes[rhsId] << "): storing proof"
    2844                 :   12499898 :         << std::endl;
    2845 [ -  + ][ -  + ]:   12499898 :     Assert(d_disequalityReasonsMap.find(pair1) == d_disequalityReasonsMap.end())
                 [ -  - ]
    2846                 :          0 :         << "There can't be a proof if you're adding a new one";
    2847                 :            :     DisequalityReasonRef ref(d_deducedDisequalityReasonsSize,
    2848                 :   12499898 :                              d_deducedDisequalityReasons.size());
    2849                 :            : #ifdef CVC5_ASSERTIONS
    2850                 :            :     // Check that the reasons are valid
    2851         [ +  + ]:   28663003 :     for (unsigned i = ref.d_mergesStart; i < ref.d_mergesEnd; ++i)
    2852                 :            :     {
    2853 [ -  + ][ -  + ]:   16163105 :       Assert(
                 [ -  - ]
    2854                 :            :           getEqualityNode(d_deducedDisequalityReasons[i].first).getFind()
    2855                 :            :           == getEqualityNode(d_deducedDisequalityReasons[i].second).getFind());
    2856                 :            :     }
    2857                 :            : #endif
    2858         [ -  + ]:   12499898 :     if (TraceIsOn("equality::disequality"))
    2859                 :            :     {
    2860         [ -  - ]:          0 :       for (unsigned i = ref.d_mergesStart; i < ref.d_mergesEnd; ++i)
    2861                 :            :       {
    2862                 :          0 :         TNode lhs = d_nodes[d_deducedDisequalityReasons[i].first];
    2863                 :          0 :         TNode rhs = d_nodes[d_deducedDisequalityReasons[i].second];
    2864         [ -  - ]:          0 :         Trace("equality::disequality")
    2865                 :          0 :             << d_name << "::eq::storePropagatedDisequality(): because " << lhs
    2866                 :          0 :             << " == " << rhs << std::endl;
    2867                 :          0 :       }
    2868                 :            :     }
    2869                 :            : 
    2870                 :            :     // Store for backtracking
    2871                 :   12499898 :     d_deducedDisequalities.push_back(pair1);
    2872                 :   12499898 :     d_deducedDisequalitiesSize = d_deducedDisequalities.size();
    2873                 :   12499898 :     d_deducedDisequalityReasonsSize = d_deducedDisequalityReasons.size();
    2874                 :            :     // Store the proof reference
    2875                 :   12499898 :     d_disequalityReasonsMap[pair1] = ref;
    2876                 :   12499898 :     d_disequalityReasonsMap[pair2] = ref;
    2877                 :            :   }
    2878                 :            :   else
    2879                 :            :   {
    2880 [ -  + ][ -  + ]:    2085872 :     Assert(d_disequalityReasonsMap.find(pair1) != d_disequalityReasonsMap.end())
                 [ -  - ]
    2881                 :          0 :         << "You must provide a proof initially";
    2882                 :            :   }
    2883                 :   14585770 : }
    2884                 :            : 
    2885                 :  131912650 : void EqualityEngine::getDisequalities(bool allowConstants,
    2886                 :            :                                       EqualityNodeId classId,
    2887                 :            :                                       TheoryIdSet inputTags,
    2888                 :            :                                       TaggedEqualitiesSet& out)
    2889                 :            : {
    2890                 :            :   // Must be empty on input
    2891 [ -  + ][ -  + ]:  131912650 :   Assert(out.size() == 0);
                 [ -  - ]
    2892                 :            :   // The class we are looking for, shouldn't have any of the tags we are looking
    2893                 :            :   // for already set
    2894 [ +  + ][ +  - ]:  131912650 :   Assert(d_nodeIndividualTrigger[classId] == null_set_id
         [ -  + ][ -  + ]
                 [ -  - ]
    2895                 :            :          || TheoryIdSetUtil::setIntersection(
    2896                 :            :                 getTriggerTermSet(d_nodeIndividualTrigger[classId]).d_tags,
    2897                 :            :                 inputTags)
    2898                 :            :                 == 0);
    2899                 :            : 
    2900         [ +  + ]:  131912650 :   if (inputTags == 0)
    2901                 :            :   {
    2902                 :   90535474 :     return;
    2903                 :            :   }
    2904                 :            : 
    2905                 :            :   // Set of already (through disequalities) visited equivalence classes
    2906                 :   41377176 :   std::set<EqualityNodeId> alreadyVisited;
    2907                 :            : 
    2908                 :            :   // Go through the equivalence class
    2909                 :   41377176 :   EqualityNodeId currentId = classId;
    2910                 :            :   do
    2911                 :            :   {
    2912         [ +  - ]:   94948382 :     Trace("equality::trigger")
    2913                 :          0 :         << d_name << "::getDisequalities() : going through uselist of "
    2914                 :   47474191 :         << d_nodes[currentId] << std::endl;
    2915                 :            : 
    2916                 :            :     // Current node in the equivalence class
    2917                 :   47474191 :     EqualityNode& currentNode = getEqualityNode(currentId);
    2918                 :            : 
    2919                 :            :     // Go through the uselist and look for disequalities
    2920                 :   47474191 :     UseListNodeId currentUseId = currentNode.getUseList();
    2921         [ +  + ]:   84001351 :     while (currentUseId != null_uselist_id)
    2922                 :            :     {
    2923                 :   36527160 :       UseListNode& useListNode = d_useListNodes[currentUseId];
    2924                 :   36527160 :       EqualityNodeId funId = useListNode.getApplicationId();
    2925                 :            : 
    2926         [ +  - ]:   73054320 :       Trace("equality::trigger") << d_name << "::getDisequalities() : checking "
    2927                 :   36527160 :                                  << d_nodes[funId] << std::endl;
    2928                 :            : 
    2929                 :            :       const FunctionApplication& fun =
    2930                 :   36527160 :           d_applications[useListNode.getApplicationId()].d_original;
    2931                 :            :       // If it's an equality asserted to false, we do the work
    2932                 :   73054320 :       if (fun.isEquality()
    2933 [ +  + ][ +  + ]:   64932257 :           && getEqualityNode(funId).getFind()
    2934 [ +  + ][ +  + ]:   64932257 :                  == getEqualityNode(d_false).getFind())
                 [ -  - ]
    2935                 :            :       {
    2936                 :            :         // Get the other equality member
    2937                 :    6049960 :         bool lhs = false;
    2938                 :    6049960 :         EqualityNodeId toCompare = fun.d_b;
    2939         [ +  + ]:    6049960 :         if (toCompare == currentId)
    2940                 :            :         {
    2941                 :    3401159 :           toCompare = fun.d_a;
    2942                 :    3401159 :           lhs = true;
    2943                 :            :         }
    2944                 :            :         // Representative of the other member
    2945                 :    6049960 :         EqualityNodeId toCompareRep = getEqualityNode(toCompare).getFind();
    2946         [ -  + ]:    6049960 :         if (toCompareRep == classId)
    2947                 :            :         {
    2948                 :            :           // We're in conflict, so we will send it out from merge
    2949                 :          0 :           out.clear();
    2950                 :          0 :           return;
    2951                 :            :         }
    2952                 :            :         // Check if we already have this one
    2953         [ +  + ]:    6049960 :         if (alreadyVisited.count(toCompareRep) == 0)
    2954                 :            :         {
    2955                 :            :           // Mark as visited
    2956                 :    4907276 :           alreadyVisited.insert(toCompareRep);
    2957                 :            :           // Get the trigger set
    2958                 :            :           TriggerTermSetRef toCompareTriggerSetRef =
    2959                 :    4907276 :               d_nodeIndividualTrigger[toCompareRep];
    2960                 :            :           // We only care if we're not both constants and there are trigger
    2961                 :            :           // terms in the other class
    2962         [ +  + ]:    2281660 :           if ((allowConstants || !d_isConstant[toCompareRep])
    2963 [ +  + ][ +  + ]:    7188936 :               && toCompareTriggerSetRef != null_set_id)
                 [ +  + ]
    2964                 :            :           {
    2965                 :            :             // Tags of the other gey
    2966                 :            :             TriggerTermSet& toCompareTriggerSet =
    2967                 :    2416823 :                 getTriggerTermSet(toCompareTriggerSetRef);
    2968                 :            :             // We only care if there are things in inputTags that is also in
    2969                 :            :             // toCompareTags
    2970                 :    2416823 :             TheoryIdSet commonTags = TheoryIdSetUtil::setIntersection(
    2971                 :            :                 inputTags, toCompareTriggerSet.d_tags);
    2972         [ +  + ]:    2416823 :             if (commonTags)
    2973                 :            :             {
    2974                 :    1680867 :               out.push_back(TaggedEquality(funId, toCompareTriggerSetRef, lhs));
    2975                 :            :             }
    2976                 :            :           }
    2977                 :            :         }
    2978                 :            :       }
    2979                 :            :       // Go to the next one in the use list
    2980                 :   36527160 :       currentUseId = useListNode.getNext();
    2981                 :            :     }
    2982                 :            :     // Next in equivalence class
    2983                 :   47474191 :     currentId = currentNode.getNext();
    2984 [ +  - ][ +  + ]:   47474191 :   } while (!d_done && currentId != classId);
                 [ +  + ]
    2985         [ +  - ]:   41377176 : }
    2986                 :            : 
    2987                 :  131912622 : bool EqualityEngine::propagateTriggerTermDisequalities(
    2988                 :            :     TheoryIdSet tags,
    2989                 :            :     TriggerTermSetRef triggerSetRef,
    2990                 :            :     const TaggedEqualitiesSet& disequalitiesToNotify)
    2991                 :            : {
    2992                 :            :   // No tags, no food
    2993         [ +  + ]:  131912622 :   if (!tags)
    2994                 :            :   {
    2995                 :   90535447 :     return !d_done;
    2996                 :            :   }
    2997                 :            : 
    2998 [ -  + ][ -  + ]:   41377175 :   Assert(triggerSetRef != null_set_id);
                 [ -  - ]
    2999                 :            : 
    3000                 :            :   // This is the class trigger set
    3001                 :   41377175 :   const TriggerTermSet& triggerSet = getTriggerTermSet(triggerSetRef);
    3002                 :            :   // Go through the disequalities and notify
    3003                 :   41377175 :   TaggedEqualitiesSet::const_iterator it = disequalitiesToNotify.begin();
    3004                 :   41377175 :   TaggedEqualitiesSet::const_iterator it_end = disequalitiesToNotify.end();
    3005 [ +  + ][ +  + ]:   43005513 :   for (; !d_done && it != it_end; ++it)
                 [ +  + ]
    3006                 :            :   {
    3007                 :            :     // The information about the equality that is asserted to false
    3008                 :    1647632 :     const TaggedEquality& disequalityInfo = *it;
    3009                 :            :     const TriggerTermSet& disequalityTriggerSet =
    3010                 :    1647632 :         getTriggerTermSet(disequalityInfo.d_triggerSetRef);
    3011                 :            :     TheoryIdSet commonTags =
    3012                 :    1647632 :         TheoryIdSetUtil::setIntersection(disequalityTriggerSet.d_tags, tags);
    3013 [ -  + ][ -  + ]:    1647632 :     Assert(commonTags);
                 [ -  - ]
    3014                 :            :     // This is the actual function
    3015                 :            :     const FunctionApplication& fun =
    3016                 :    1647632 :         d_applications[disequalityInfo.d_equalityId].d_original;
    3017                 :            :     // Figure out who we are comparing to in the original equality
    3018         [ +  + ]:    1647632 :     EqualityNodeId toCompare = disequalityInfo.d_lhs ? fun.d_a : fun.d_b;
    3019         [ +  + ]:    1647632 :     EqualityNodeId myCompare = disequalityInfo.d_lhs ? fun.d_b : fun.d_a;
    3020                 :    1647632 :     if (getEqualityNode(toCompare).getFind()
    3021         [ +  + ]:    1647632 :         == getEqualityNode(myCompare).getFind())
    3022                 :            :     {
    3023                 :            :       // We're propagating a != a, which means we're inconsistent, just bail and
    3024                 :            :       // let it go into a regular conflict
    3025                 :      19294 :       return !d_done;
    3026                 :            :     }
    3027                 :            :     // Go through the tags, and add the disequalities
    3028                 :            :     TheoryId currentTag;
    3029                 :    1628338 :     while (
    3030                 :    4047865 :         !d_done
    3031 [ +  + ][ +  + ]:    4047865 :         && ((currentTag = TheoryIdSetUtil::setPop(commonTags)) != THEORY_LAST))
                 [ +  + ]
    3032                 :            :     {
    3033                 :            :       // Get the tag representative
    3034                 :    2419527 :       EqualityNodeId tagRep = disequalityTriggerSet.getTrigger(currentTag);
    3035                 :    2419527 :       EqualityNodeId myRep = triggerSet.getTrigger(currentTag);
    3036                 :            :       // Propagate
    3037         [ +  + ]:    2419527 :       if (!hasPropagatedDisequality(currentTag, myRep, tagRep))
    3038                 :            :       {
    3039                 :            :         // Construct the proof if not there already
    3040         [ +  + ]:     159452 :         if (!hasPropagatedDisequality(myRep, tagRep))
    3041                 :            :         {
    3042                 :      51075 :           d_deducedDisequalityReasons.push_back(EqualityPair(myCompare, myRep));
    3043                 :      51075 :           d_deducedDisequalityReasons.push_back(
    3044                 :          0 :               EqualityPair(toCompare, tagRep));
    3045                 :      51075 :           d_deducedDisequalityReasons.push_back(
    3046                 :     102150 :               EqualityPair(disequalityInfo.d_equalityId, d_falseId));
    3047                 :            :         }
    3048                 :            :         // Store the propagation
    3049                 :     159452 :         storePropagatedDisequality(currentTag, myRep, tagRep);
    3050                 :            :         // Notify
    3051         [ +  + ]:     318904 :         if (!notifyTriggerTermEquality(
    3052                 :     318904 :                 currentTag, d_nodes[myRep], d_nodes[tagRep], false))
    3053                 :            :         {
    3054                 :         43 :           d_done = true;
    3055                 :            :         }
    3056                 :            :       }
    3057                 :            :     }
    3058                 :            :   }
    3059                 :            : 
    3060                 :   41357881 :   return !d_done;
    3061                 :            : }
    3062                 :            : 
    3063                 :   15675984 : TheoryIdSet EqualityEngine::TriggerTermSet::hasTrigger(TheoryId tag) const
    3064                 :            : {
    3065                 :   15675984 :   return TheoryIdSetUtil::setContains(tag, d_tags);
    3066                 :            : }
    3067                 :            : 
    3068                 :    6983573 : EqualityNodeId EqualityEngine::TriggerTermSet::getTrigger(TheoryId tag) const
    3069                 :            : {
    3070                 :    6983573 :   return d_triggers[TheoryIdSetUtil::setIndex(tag, d_tags)];
    3071                 :            : }
    3072                 :            : 
    3073                 :            : }  // namespace eq
    3074                 :            : }  // Namespace theory
    3075                 :            : }  // namespace cvc5::internal

Generated by: LCOV version 1.14