LCOV - code coverage report
Current view: top level - buildbot/coverage/build/src/theory/uf - eq_proof.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 587 744 78.9 %
Date: 2024-11-29 12:38:33 Functions: 7 9 77.8 %
Branches: 405 752 53.9 %

           Branch data     Line data    Source code
       1                 :            : /******************************************************************************
       2                 :            :  * Top contributors (to current version):
       3                 :            :  *   Haniel Barbosa, Hans-Joerg Schurr, Aina Niemetz
       4                 :            :  *
       5                 :            :  * This file is part of the cvc5 project.
       6                 :            :  *
       7                 :            :  * Copyright (c) 2009-2024 by the authors listed in the file AUTHORS
       8                 :            :  * in the top-level source directory and their institutional affiliations.
       9                 :            :  * All rights reserved.  See the file COPYING in the top-level source
      10                 :            :  * directory for licensing information.
      11                 :            :  * ****************************************************************************
      12                 :            :  *
      13                 :            :  * Implementation of a proof as produced by the equality engine.
      14                 :            :  */
      15                 :            : 
      16                 :            : #include "theory/uf/eq_proof.h"
      17                 :            : 
      18                 :            : #include "base/configuration.h"
      19                 :            : #include "options/uf_options.h"
      20                 :            : #include "proof/proof.h"
      21                 :            : #include "proof/proof_checker.h"
      22                 :            : #include "proof/proof_node_algorithm.h"
      23                 :            : #include "proof/proof_node_manager.h"
      24                 :            : 
      25                 :            : namespace cvc5::internal {
      26                 :            : namespace theory {
      27                 :            : namespace eq {
      28                 :            : 
      29                 :          0 : void EqProof::debug_print(const char* c, unsigned tb) const
      30                 :            : {
      31                 :          0 :   std::stringstream ss;
      32                 :          0 :   debug_print(ss, tb);
      33                 :          0 :   Trace(c) << ss.str();
      34                 :          0 : }
      35                 :            : 
      36                 :          0 : void EqProof::debug_print(std::ostream& os, unsigned tb) const
      37                 :            : {
      38         [ -  - ]:          0 :   for (unsigned i = 0; i < tb; i++)
      39                 :            :   {
      40                 :          0 :     os << "  ";
      41                 :            :   }
      42                 :          0 :   os << d_id << "(";
      43 [ -  - ][ -  - ]:          0 :   if (d_children.empty() && d_node.isNull())
                 [ -  - ]
      44                 :            :   {
      45                 :          0 :     os << ")";
      46                 :          0 :     return;
      47                 :            :   }
      48         [ -  - ]:          0 :   if (!d_node.isNull())
      49                 :            :   {
      50                 :          0 :     os << std::endl;
      51         [ -  - ]:          0 :     for (unsigned i = 0; i < tb + 1; ++i)
      52                 :            :     {
      53                 :          0 :       os << "  ";
      54                 :            :     }
      55         [ -  - ]:          0 :     os << d_node << (!d_children.empty() ? "," : "");
      56                 :            :   }
      57                 :          0 :   unsigned size = d_children.size();
      58         [ -  - ]:          0 :   for (unsigned i = 0; i < size; ++i)
      59                 :            :   {
      60                 :          0 :     os << std::endl;
      61                 :          0 :     d_children[i]->debug_print(os, tb + 1);
      62         [ -  - ]:          0 :     if (i < size - 1)
      63                 :            :     {
      64         [ -  - ]:          0 :       for (unsigned j = 0; j < tb + 1; ++j)
      65                 :            :       {
      66                 :          0 :         os << "  ";
      67                 :            :       }
      68                 :          0 :       os << ",";
      69                 :            :     }
      70                 :            :   }
      71         [ -  - ]:          0 :   if (size > 0)
      72                 :            :   {
      73         [ -  - ]:          0 :     for (unsigned i = 0; i < tb; ++i)
      74                 :            :     {
      75                 :          0 :       os << "  ";
      76                 :            :     }
      77                 :            :   }
      78                 :          0 :   os << ")" << std::endl;
      79                 :            : }
      80                 :            : 
      81                 :    1456070 : void EqProof::cleanReflPremises(std::vector<Node>& premises) const
      82                 :            : {
      83                 :    2912150 :   std::vector<Node> newPremises;
      84                 :    1456070 :   unsigned size = premises.size();
      85         [ +  + ]:    4591950 :   for (unsigned i = 0; i < size; ++i)
      86                 :            :   {
      87         [ +  + ]:    3135880 :     if (premises[i][0] == premises[i][1])
      88                 :            :     {
      89                 :     452768 :       continue;
      90                 :            :     }
      91                 :    2683110 :     newPremises.push_back(premises[i]);
      92                 :            :   }
      93         [ +  + ]:    1456070 :   if (newPremises.size() != size)
      94                 :            :   {
      95         [ +  - ]:     429672 :     Trace("eqproof-conv") << "EqProof::cleanReflPremises: removed "
      96                 :          0 :                           << (size >= newPremises.size()
      97         [ -  - ]:     214836 :                                   ? size - newPremises.size()
      98                 :          0 :                                   : 0)
      99                 :     214836 :                           << " refl premises from " << premises << "\n";
     100                 :     214836 :     premises.clear();
     101                 :     214836 :     premises.insert(premises.end(), newPremises.begin(), newPremises.end());
     102         [ +  - ]:     429672 :     Trace("eqproof-conv") << "EqProof::cleanReflPremises: new premises "
     103                 :     214836 :                           << premises << "\n";
     104                 :            :   }
     105                 :    1456070 : }
     106                 :            : 
     107                 :     605208 : bool EqProof::expandTransitivityForDisequalities(
     108                 :            :     Node conclusion,
     109                 :            :     std::vector<Node>& premises,
     110                 :            :     CDProof* p,
     111                 :            :     std::unordered_set<Node>& assumptions) const
     112                 :            : {
     113         [ +  - ]:    1210420 :   Trace("eqproof-conv")
     114                 :            :       << "EqProof::expandTransitivityForDisequalities: check if need "
     115                 :          0 :          "to expand transitivity step to conclude "
     116                 :     605208 :       << conclusion << " from premises " << premises << "\n";
     117                 :            :   // Check premises to see if any of the form (= (= t1 t2) false), modulo
     118                 :            :   // symmetry
     119                 :     605208 :   unsigned size = premises.size();
     120                 :            :   // termPos is, in (= (= t1 t2) false) or (= false (= t1 t2)), the position of
     121                 :            :   // the equality. When the i-th premise has that form, offending = i
     122                 :     605208 :   unsigned termPos = 2, offending = size;
     123         [ +  + ]:    2381210 :   for (unsigned i = 0; i < size; ++i)
     124                 :            :   {
     125 [ -  + ][ -  + ]:    1776000 :     Assert(premises[i].getKind() == Kind::EQUAL);
                 [ -  - ]
     126         [ +  + ]:    5290960 :     for (unsigned j = 0; j < 2; ++j)
     127                 :            :     {
     128 [ +  + ][ -  - ]:    7074980 :       if (premises[i][j].getKind() == Kind::CONST_BOOLEAN
     129 [ +  + ][ +  - ]:    3575270 :           && !premises[i][j].getConst<bool>()
                 [ -  - ]
     130 [ +  + ][ +  + ]:    7112760 :           && premises[i][1 - j].getKind() == Kind::EQUAL)
         [ +  + ][ +  + ]
                 [ -  - ]
     131                 :            :       {
     132                 :            :         // there is only one offending equality
     133 [ -  + ][ -  + ]:      22533 :         Assert(offending == size);
                 [ -  - ]
     134                 :      22533 :         offending = i;
     135                 :      22533 :         termPos = 1 - j;
     136                 :      22533 :         break;
     137                 :            :       }
     138                 :            :     }
     139                 :            :   }
     140                 :            :   // if no equality of the searched form, nothing to do
     141         [ +  + ]:     605208 :   if (offending == size)
     142                 :            :   {
     143         [ +  - ]:    1165350 :     Trace("eqproof-conv")
     144                 :     582675 :         << "EqProof::expandTransitivityForDisequalities: no need.\n";
     145                 :     582675 :     return false;
     146                 :            :   }
     147                 :      22533 :   NodeManager* nm = NodeManager::currentNM();
     148 [ +  + ][ -  + ]:      22533 :   Assert(termPos == 0 || termPos == 1);
         [ -  + ][ -  - ]
     149         [ +  - ]:      45066 :   Trace("eqproof-conv") << "EqProof::expandTransitivityForDisequalities: found "
     150                 :          0 :                            "offending equality at index "
     151                 :      22533 :                         << offending << " : " << premises[offending] << "\n";
     152                 :            :   // collect the premises to be used in the expansion, which are all but the
     153                 :            :   // offending one
     154                 :      45066 :   std::vector<Node> expansionPremises;
     155         [ +  + ]:      86224 :   for (unsigned i = 0; i < size; ++i)
     156                 :            :   {
     157         [ +  + ]:      63691 :     if (i != offending)
     158                 :            :     {
     159                 :      41158 :       expansionPremises.push_back(premises[i]);
     160                 :            :     }
     161                 :            :   }
     162                 :            :   // Eliminate spurious premises. Reasoning below assumes no refl steps.
     163                 :      22533 :   cleanReflPremises(expansionPremises);
     164 [ -  + ][ -  + ]:      22533 :   Assert(!expansionPremises.empty());
                 [ -  - ]
     165                 :            :   // Check if we are in the substitution case
     166                 :      45066 :   Node expansionConclusion;
     167                 :      45066 :   std::vector<Node> substPremises;
     168                 :      22533 :   bool inSubstCase = false, substConclusionInReverseOrder = false;
     169         [ +  + ]:      45066 :   if ((conclusion[0].getKind() == Kind::CONST_BOOLEAN)
     170                 :      22533 :       != (conclusion[1].getKind() == Kind::CONST_BOOLEAN))
     171                 :            :   {
     172                 :      15109 :     inSubstCase = true;
     173                 :            :     // reorder offending premise if constant is the first argument
     174         [ +  + ]:      15109 :     if (termPos == 1)
     175                 :            :     {
     176                 :      13764 :       premises[offending] =
     177                 :      27528 :           premises[offending][1].eqNode(premises[offending][0]);
     178                 :            :     }
     179                 :            :     // reorder conclusion if constant is the first argument
     180                 :      15109 :     conclusion = conclusion[1].getKind() == Kind::CONST_BOOLEAN
     181                 :      30218 :                      ? conclusion
     182                 :      15109 :                      : conclusion[1].eqNode(conclusion[0]);
     183                 :            :     // equality term in premise disequality
     184                 :      30218 :     Node premiseTermEq = premises[offending][0];
     185                 :            :     // equality term in conclusion disequality
     186                 :      30218 :     Node conclusionTermEq = conclusion[0];
     187         [ +  - ]:      30218 :     Trace("eqproof-conv")
     188                 :            :         << "EqProof::expandTransitivityForDisequalities: Substitition "
     189                 :          0 :            "case. Need to build subst from "
     190                 :      15109 :         << premiseTermEq << " to " << conclusionTermEq << "\n";
     191                 :            :     // If only one argument in the premise is substituted, premiseTermEq and
     192                 :            :     // conclusionTermEq will share one argument and the other argument change
     193                 :            :     // defines the single substitution. Otherwise both arguments are replaced,
     194                 :            :     // so there are two substitutions.
     195 [ +  + ][ +  + ]:      90654 :     std::vector<Node> subs[2];
                 [ -  - ]
     196                 :      15109 :     subs[0].push_back(premiseTermEq[0]);
     197                 :      15109 :     subs[1].push_back(premiseTermEq[1]);
     198                 :            :     // which of the arguments of premiseTermEq, if any, is equal to one argument
     199                 :            :     // of conclusionTermEq
     200                 :      15109 :     int equalArg = -1;
     201         [ +  + ]:      45327 :     for (unsigned i = 0; i < 2; ++i)
     202                 :            :     {
     203         [ +  + ]:      70493 :       for (unsigned j = 0; j < 2; ++j)
     204                 :            :       {
     205         [ +  + ]:      53790 :         if (premiseTermEq[i] == conclusionTermEq[j])
     206                 :            :         {
     207                 :      13515 :           equalArg = i;
     208                 :            :           // identity sub
     209                 :      13515 :           subs[i].push_back(conclusionTermEq[j]);
     210                 :            :           // sub that changes argument
     211                 :      13515 :           subs[1 - i].push_back(conclusionTermEq[1 - j]);
     212                 :            :           // wither e.g. (= t1 t2), with sub t1->t3, becomes (= t2 t3)
     213                 :      13515 :           substConclusionInReverseOrder = i != j;
     214                 :      13515 :           break;
     215                 :            :         }
     216                 :            :       }
     217                 :            :     }
     218                 :            :     // simple case of single substitution
     219         [ +  + ]:      15109 :     if (equalArg >= 0)
     220                 :            :     {
     221                 :            :       // case of
     222                 :            :       //   (= (= t1 t2) false) (= t1 x1) ... (= xn t3)
     223                 :            :       //  -------------------------------------------- EQP::TR
     224                 :            :       //          (= (= t3 t2) false)
     225                 :            :       // where
     226                 :            :       //
     227                 :            :       //   (= t1 x1) ... (= xn t3)           - expansion premises
     228                 :            :       //  ------------------------ TRANS
     229                 :            :       //          (= t1 t3)                  - expansion conclusion
     230                 :            :       //
     231                 :            :       // will be the expansion made to justify the substitution for t1->t3.
     232                 :      13515 :       expansionConclusion = subs[1 - equalArg][0].eqNode(subs[1 - equalArg][1]);
     233         [ +  - ]:      27030 :       Trace("eqproof-conv") << "EqProof::expandTransitivityForDisequalities: "
     234                 :          0 :                                "Need to expand premises into "
     235                 :      13515 :                             << expansionConclusion << "\n";
     236                 :            :       // add refl step for the substitition t2->t2
     237                 :      27030 :       p->addStep(subs[equalArg][0].eqNode(subs[equalArg][1]),
     238                 :            :                  ProofRule::REFL,
     239                 :            :                  {},
     240                 :      27030 :                  {subs[equalArg][0]});
     241                 :            :     }
     242                 :            :     else
     243                 :            :     {
     244                 :            :       // Hard case. We determine, and justify, the substitutions t1->t3/t4 and
     245                 :            :       // t2->t3/t4 based on the expansion premises.
     246         [ +  - ]:       3188 :       Trace("eqproof-conv") << "EqProof::expandTransitivityForDisequalities: "
     247                 :          0 :                                "Need two substitutions. Look for "
     248                 :       1594 :                             << premiseTermEq[0] << " and " << premiseTermEq[1]
     249                 :       1594 :                             << " in premises " << expansionPremises << "\n";
     250 [ -  + ][ -  - ]:       1594 :       Assert(expansionPremises.size() >= 2)
     251                 :            :           << "Less than 2 expansion premises for substituting BOTH terms in "
     252                 :          0 :              "disequality.\nDisequality: "
     253 [ -  + ][ -  - ]:       1594 :           << premises[offending]
     254                 :          0 :           << "\nExpansion premises: " << expansionPremises
     255 [ -  + ][ -  + ]:       1594 :           << "\nConclusion: " << conclusion << "\n";
                 [ -  - ]
     256                 :            :       // Easier case where we can determine the substitutions by directly
     257                 :            :       // looking at the premises, i.e. the two expansion premises are for
     258                 :            :       // example (= t1 t3) and (= t2 t4)
     259         [ +  + ]:       1594 :       if (expansionPremises.size() == 2)
     260                 :            :       {
     261                 :            :         // iterate over args to be substituted
     262         [ +  + ]:       3747 :         for (unsigned i = 0; i < 2; ++i)
     263                 :            :         {
     264                 :            :           // iterate over premises
     265         [ +  + ]:       7494 :           for (unsigned j = 0; j < 2; ++j)
     266                 :            :           {
     267                 :            :             // iterate over args in premise
     268         [ +  + ]:      11160 :             for (unsigned k = 0; k < 2; ++k)
     269                 :            :             {
     270         [ +  + ]:       8662 :               if (premiseTermEq[i] == expansionPremises[j][k])
     271                 :            :               {
     272                 :       2498 :                 subs[i].push_back(expansionPremises[j][1 - k]);
     273                 :       2498 :                 break;
     274                 :            :               }
     275                 :            :             }
     276                 :            :           }
     277 [ -  + ][ -  - ]:       2498 :           Assert(subs[i].size() == 2)
     278 [ -  + ][ -  + ]:       2498 :               << " did not find term " << subs[i][0] << "\n";
                 [ -  - ]
     279                 :            :           // check if argument to be substituted is in the same order in the
     280                 :            :           // conclusion
     281                 :            :           substConclusionInReverseOrder =
     282                 :       2498 :               premiseTermEq[i] != conclusionTermEq[i];
     283                 :            :         }
     284                 :            :       }
     285                 :            :       else
     286                 :            :       {
     287         [ +  - ]:        690 :         Trace("eqproof-conv") << "EqProof::expandTransitivityForDisequalities: "
     288                 :            :                                  "Build transitivity chains "
     289                 :          0 :                                  "for two subs among more than 2 premises: "
     290                 :        345 :                               << expansionPremises << "\n";
     291                 :            :         // Hardest case. Try building a transitivity chain for (= t1 t3). If it
     292                 :            :         // can be built, use the remaining expansion premises to build a chain
     293                 :            :         // for (= t2 t4). Otherwise build it for (= t1 t4) and then build it for
     294                 :            :         // (= t2 t3). It should always succeed.
     295                 :        345 :         subs[0].push_back(conclusionTermEq[0]);
     296                 :        345 :         subs[1].push_back(conclusionTermEq[1]);
     297         [ +  + ]:       1035 :         for (unsigned i = 0; i < 2; ++i)
     298                 :            :         {
     299                 :            :           // copy premises, since buildTransitivityChain is destructive
     300                 :            :           std::vector<Node> copy1ofExpPremises(expansionPremises.begin(),
     301                 :        690 :                                                expansionPremises.end());
     302                 :        690 :           Node transConclusion1 = subs[0][0].eqNode(subs[0][1]);
     303         [ -  + ]:        690 :           if (!buildTransitivityChain(transConclusion1, copy1ofExpPremises))
     304                 :            :           {
     305                 :          0 :             AlwaysAssert(i == 0)
     306                 :            :                 << "Couldn't find sub at all for substituting BOTH terms in "
     307                 :          0 :                    "disequality.\nDisequality: "
     308                 :          0 :                 << premises[offending]
     309                 :          0 :                 << "\nExpansion premises: " << expansionPremises
     310                 :          0 :                 << "\nConclusion: " << conclusion << "\n";
     311                 :            :             // Failed. So flip sub and try again
     312                 :          0 :             subs[0][1] = conclusionTermEq[1];
     313                 :          0 :             subs[1][1] = conclusionTermEq[0];
     314                 :          0 :             substConclusionInReverseOrder = false;
     315                 :          0 :             continue;
     316                 :            :           }
     317                 :            :           // build next chain
     318                 :            :           std::vector<Node> copy2ofExpPremises(expansionPremises.begin(),
     319                 :       1380 :                                                expansionPremises.end());
     320                 :       1380 :           Node transConclusion2 = subs[1][0].eqNode(subs[1][1]);
     321         [ -  + ]:        690 :           if (!buildTransitivityChain(transConclusion2, copy2ofExpPremises))
     322                 :            :           {
     323                 :          0 :             Unreachable() << "Found sub " << transConclusion1
     324                 :          0 :                           << " but not other sub " << transConclusion2
     325                 :          0 :                           << ".\nDisequality: " << premises[offending]
     326                 :          0 :                           << "\nExpansion premises: " << expansionPremises
     327                 :          0 :                           << "\nConclusion: " << conclusion << "\n";
     328                 :            :           }
     329         [ +  - ]:       1380 :           Trace("eqproof-conv")
     330                 :            :               << "EqProof::expandTransitivityForDisequalities: Built trans "
     331                 :            :                  "chains: "
     332                 :        690 :                  "for two subs among more than 2 premises:\n";
     333         [ +  - ]:       1380 :           Trace("eqproof-conv")
     334                 :          0 :               << "EqProof::expandTransitivityForDisequalities: "
     335                 :        690 :               << transConclusion1 << " <- " << copy1ofExpPremises << "\n";
     336         [ +  - ]:       1380 :           Trace("eqproof-conv")
     337                 :          0 :               << "EqProof::expandTransitivityForDisequalities: "
     338                 :        690 :               << transConclusion2 << " <- " << copy2ofExpPremises << "\n";
     339                 :            :           // do transitivity steps if need be to justify each substitution
     340                 :        690 :           if (copy1ofExpPremises.size() > 1
     341 [ +  + ][ +  + ]:        690 :               && !assumptions.count(transConclusion1))
                 [ +  + ]
     342                 :            :           {
     343                 :        288 :             p->addStep(transConclusion1,
     344                 :            :                        ProofRule::TRANS,
     345                 :            :                        copy1ofExpPremises,
     346                 :            :                        {},
     347                 :            :                        true);
     348                 :            :           }
     349                 :        690 :           if (copy2ofExpPremises.size() > 1
     350 [ +  + ][ +  + ]:        690 :               && !assumptions.count(transConclusion2))
                 [ +  + ]
     351                 :            :           {
     352                 :        308 :             p->addStep(transConclusion2,
     353                 :            :                        ProofRule::TRANS,
     354                 :            :                        copy2ofExpPremises,
     355                 :            :                        {},
     356                 :            :                        true);
     357                 :            :           }
     358                 :            :         }
     359                 :            :       }
     360                 :            :     }
     361         [ +  - ]:      30218 :     Trace("eqproof-conv")
     362                 :          0 :         << "EqProof::expandTransitivityForDisequalities: Built substutitions "
     363                 :          0 :         << subs[0] << " and " << subs[1] << " to map " << premiseTermEq
     364                 :      15109 :         << " -> " << conclusionTermEq << "\n";
     365                 :      30218 :     Assert(subs[0][1] == conclusion[0][0] || subs[0][1] == conclusion[0][1])
     366                 :          0 :         << "EqProof::expandTransitivityForDisequalities: First substitution "
     367 [ -  + ][ -  + ]:      15109 :         << subs[0] << " doest not map to conclusion " << conclusion << "\n";
                 [ -  - ]
     368                 :      30218 :     Assert(subs[1][1] == conclusion[0][0] || subs[1][1] == conclusion[0][1])
     369                 :          0 :         << "EqProof::expandTransitivityForDisequalities: Second substitution "
     370 [ -  + ][ -  + ]:      15109 :         << subs[1] << " doest not map to conclusion " << conclusion << "\n";
                 [ -  - ]
     371                 :            :     // In the premises for the original conclusion, the substitution of
     372                 :            :     // premiseTermEq (= t1 t2) into conclusionTermEq (= t3 t4) is stored
     373                 :            :     // reversed, i.e. as (= (= t3 t4) (= t1 t2)), since the transitivity with
     374                 :            :     // the disequality is built as as
     375                 :            :     //   (= (= t3 t4) (= t1 t2))                         (= (= t1 t2) false)
     376                 :            :     //  --------------------------------------------------------------------- TR
     377                 :            :     //                      (= (= t3 t4) false)
     378                 :      15109 :     substPremises.push_back(subs[0][1].eqNode(subs[0][0]));
     379                 :      15109 :     substPremises.push_back(subs[1][1].eqNode(subs[1][0]));
     380                 :            :   }
     381                 :            :   else
     382                 :            :   {
     383                 :            :     // In simple case the conclusion is always, modulo symmetry, false = true
     384                 :      14848 :     Assert(conclusion[0].getKind() == Kind::CONST_BOOLEAN
     385                 :            :            && conclusion[1].getKind() == Kind::CONST_BOOLEAN);
     386                 :            :     // The expansion conclusion is the same as the equality term in the
     387                 :            :     // disequality, which is going to be justified by a transitivity step from
     388                 :            :     // the expansion premises
     389                 :       7424 :     expansionConclusion = premises[offending][termPos];
     390                 :            :   }
     391                 :            :   // Unless we are in the double-substitution case, the proof has the shape
     392                 :            :   //
     393                 :            :   //                           ... ... ... ...         - expansionPremises
     394                 :            :   //                          ------------------ TRANS
     395                 :            :   //     (= (= (t t') false)    (= t'' t''')           - expansionConclusion
     396                 :            :   //  ---------------------------------------------- TRANS or PRED_TRANSFORM
     397                 :            :   //             conclusion
     398                 :            :   //
     399                 :            :   // although note that if it's a TRANS step, (= t'' t''') will be turned into a
     400                 :            :   // predicate equality and the premises are ordered.
     401                 :            :   //
     402                 :            :   // We build the transitivity step for the expansionConclusion here. It being
     403                 :            :   // non-null marks that we are not in the double-substitution case.
     404         [ +  + ]:      22533 :   if (!expansionConclusion.isNull())
     405                 :            :   {
     406         [ +  - ]:      41878 :     Trace("eqproof-conv")
     407                 :          0 :         << "EqProof::expandTransitivityForDisequalities: need to derive "
     408                 :          0 :         << expansionConclusion << " with premises " << expansionPremises
     409                 :      20939 :         << "\n";
     410                 :      41878 :     Assert(expansionPremises.size() > 1
     411                 :            :            || expansionConclusion == expansionPremises.back()
     412                 :            :            || (expansionConclusion[0] == expansionPremises.back()[1]
     413                 :            :                && expansionConclusion[1] == expansionPremises.back()[0]))
     414 [ -  + ][ -  - ]:      20939 :         << "single expansion premise " << expansionPremises.back()
     415 [ -  + ][ -  + ]:      20939 :         << " is not the same as expansionConclusion " << expansionConclusion
                 [ -  - ]
     416                 :          0 :         << " and not its symmetric\n";
     417                 :            :     // We track assumptions to avoid cyclic proofs, which can happen in EqProofs
     418                 :            :     // such as:
     419                 :            :     //
     420                 :            :     //              (= l1 "")     (= "" t)
     421                 :            :     //            ----------------------- EQP::TR
     422                 :            :     //  (= l1 "")           (= l1 t)                  (= (= "" t) false)
     423                 :            :     // ----------------------------------------------------------------- EQP::TR
     424                 :            :     //                        (= false true)
     425                 :            :     //
     426                 :            :     // which would lead to the cyclic expansion proof:
     427                 :            :     //
     428                 :            :     //       (= l1 "")             (= l1 "")   (= "" t)
     429                 :            :     //       --------- SYMM      ----------------------- TRANS
     430                 :            :     //       (= "" l1)                     (= l1 t)
     431                 :            :     //      ------------------------------------------ TRANS
     432                 :            :     //                       (= "" t)
     433 [ +  + ][ +  + ]:      20939 :     if (expansionPremises.size() > 1 && !assumptions.count(expansionConclusion))
                 [ +  + ]
     434                 :            :     {
     435                 :            :       // create transitivity step to derive expected premise
     436                 :       6640 :       buildTransitivityChain(expansionConclusion, expansionPremises);
     437         [ +  - ]:      13280 :       Trace("eqproof-conv")
     438                 :            :           << "EqProof::expandTransitivityForDisequalities: add transitivity "
     439                 :          0 :              "step for "
     440                 :          0 :           << expansionConclusion << " with premises " << expansionPremises
     441                 :       6640 :           << "\n";
     442                 :            :       // create expansion step
     443                 :       6640 :       p->addStep(
     444                 :            :           expansionConclusion, ProofRule::TRANS, expansionPremises, {}, true);
     445                 :            :     }
     446                 :            :   }
     447         [ +  - ]:      45066 :   Trace("eqproof-conv")
     448                 :          0 :       << "EqProof::expandTransitivityForDisequalities: now derive conclusion "
     449                 :      22533 :       << conclusion;
     450                 :      22533 :   Node offendingNode = premises[offending];
     451                 :      22533 :   premises.clear();
     452                 :      22533 :   premises.push_back(offendingNode);
     453         [ +  + ]:      22533 :   if (inSubstCase)
     454                 :            :   {
     455 [ +  - ][ -  - ]:      30218 :     Trace("eqproof-conv") << (substConclusionInReverseOrder ? " [inverted]"
     456                 :          0 :                                                             : "")
     457                 :          0 :                           << " via subsitution from " << premises[0]
     458                 :      15109 :                           << " and (inverted subst) " << substPremises << "\n";
     459                 :            :     //  By this point, for premise disequality (= (= t1 t2) false), we have
     460                 :            :     //  potentially already built
     461                 :            :     //
     462                 :            :     //     (= t1 x1) ... (= xn t3)      (= t2 y1) ... (= ym t4)
     463                 :            :     //    ------------------------ TR  ------------------------ TR
     464                 :            :     //     (= t1 t3)                    (= t2 t4)
     465                 :            :     //
     466                 :            :     // to justify the substitutions t1->t3 and t2->t4 (where note that if t1=t3
     467                 :            :     // or t2=4, the step will actually be a REFL one). Not do
     468                 :            :     //
     469                 :            :     //  ----------- SYMM             ----------- SYMM
     470                 :            :     //   (= t3 t1)                    (= t4 t2)
     471                 :            :     //  ---------------------------------------- CONG
     472                 :            :     //   (= (= t3 t4) (= t1 t2))                         (= (= t1 t2) false)
     473                 :            :     //  --------------------------------------------------------------------- TR
     474                 :            :     //                   (= (= t3 t4) false)
     475                 :            :     //
     476                 :            :     // where note that the SYMM steps are implicitly added by CDProof.
     477                 :            :     Node congConclusion = nm->mkNode(
     478                 :            :         Kind::EQUAL,
     479                 :      30218 :         nm->mkNode(Kind::EQUAL, substPremises[0][0], substPremises[1][0]),
     480                 :      75545 :         premises[0][0]);
     481                 :      30218 :     p->addStep(congConclusion,
     482                 :            :                ProofRule::CONG,
     483                 :            :                substPremises,
     484                 :            :                {ProofRuleChecker::mkKindNode(Kind::EQUAL)},
     485                 :      15109 :                true);
     486         [ +  - ]:      30218 :     Trace("eqproof-conv") << "EqProof::expandTransitivityForDisequalities: via "
     487                 :          0 :                              "congruence derived "
     488                 :      15109 :                           << congConclusion << "\n";
     489                 :            :     // transitivity step between that and the original premise
     490                 :      15109 :     premises.insert(premises.begin(), congConclusion);
     491                 :            :     Node transConclusion =
     492                 :      15109 :         !substConclusionInReverseOrder
     493                 :            :             ? conclusion
     494                 :      37799 :             : nm->mkNode(Kind::EQUAL, congConclusion[0], conclusion[1]);
     495                 :            :     // check to avoid cyclic proofs
     496         [ +  - ]:      15109 :     if (!assumptions.count(transConclusion))
     497                 :            :     {
     498                 :      15109 :       p->addStep(transConclusion, ProofRule::TRANS, premises, {}, true);
     499         [ +  - ]:      30218 :       Trace("eqproof-conv") << "EqProof::expandTransitivityForDisequalities: "
     500                 :          0 :                                "via transitivity derived "
     501                 :      15109 :                             << transConclusion << "\n";
     502                 :            :     }
     503                 :            :     // if order is reversed, finish the proof of conclusion with
     504                 :            :     //           (= (= t3 t4) false)
     505                 :            :     //          --------------------- MACRO_SR_PRED_TRANSFORM
     506                 :            :     //           (= (= t4 t3) false)
     507         [ +  + ]:      15109 :     if (substConclusionInReverseOrder)
     508                 :            :     {
     509                 :       7581 :       p->addStep(conclusion,
     510                 :            :                  ProofRule::MACRO_SR_PRED_TRANSFORM,
     511                 :            :                  {transConclusion},
     512                 :            :                  {conclusion},
     513                 :       5054 :                  true);
     514         [ +  - ]:       5054 :       Trace("eqproof-conv") << "EqProof::expandTransitivityForDisequalities: "
     515                 :          0 :                                "via macro transform derived "
     516                 :       2527 :                             << conclusion << "\n";
     517                 :            :     }
     518                 :            :   }
     519                 :            :   else
     520                 :            :   {
     521                 :            :     // create TRUE_INTRO step for expansionConclusion and add it to the premises
     522         [ +  - ]:      14848 :     Trace("eqproof-conv")
     523                 :            :         << " via transitivity.\nEqProof::expandTransitivityForDisequalities: "
     524                 :          0 :            "adding "
     525 [ -  + ][ -  - ]:       7424 :         << ProofRule::TRUE_INTRO << " step for " << expansionConclusion[0]
     526                 :       7424 :         << "\n";
     527                 :            :     Node newExpansionConclusion =
     528                 :       7424 :         expansionConclusion.eqNode(nm->mkConst<bool>(true));
     529                 :      14848 :     p->addStep(newExpansionConclusion,
     530                 :            :                ProofRule::TRUE_INTRO,
     531                 :            :                {expansionConclusion},
     532                 :       7424 :                {});
     533                 :       7424 :     premises.push_back(newExpansionConclusion);
     534         [ +  - ]:       7424 :     Trace("eqproof-conv") << ProofRule::TRANS << " from " << premises << "\n";
     535                 :       7424 :     buildTransitivityChain(conclusion, premises);
     536                 :            :     // create final transitivity step
     537                 :       7424 :     p->addStep(conclusion, ProofRule::TRANS, premises, {}, true);
     538                 :            :   }
     539                 :      22533 :   return true;
     540                 :            : }
     541                 :            : 
     542                 :            : // TEMPORARY NOTE: This may not be enough. Worst case scenario I need to
     543                 :            : // reproduce here a search for arbitrary chains between each of the variables in
     544                 :            : // the conclusion and a constant
     545                 :     582675 : bool EqProof::expandTransitivityForTheoryDisequalities(
     546                 :            :     Node conclusion, std::vector<Node>& premises, CDProof* p) const
     547                 :            : {
     548                 :            :   // whether conclusion is a disequality (= (= t1 t2) false), modulo symmetry
     549                 :     582675 :   unsigned termPos = -1;
     550         [ +  + ]:    1748020 :   for (unsigned i = 0; i < 2; ++i)
     551                 :            :   {
     552 [ +  + ][ -  - ]:    1165350 :     if (conclusion[i].getKind() == Kind::CONST_BOOLEAN
     553 [ +  + ][ +  - ]:    1178940 :         && !conclusion[i].getConst<bool>()
                 [ -  - ]
     554 [ +  + ][ +  + ]:    1178940 :         && conclusion[1 - i].getKind() == Kind::EQUAL)
         [ +  + ][ +  + ]
                 [ -  - ]
     555                 :            :     {
     556                 :         10 :       termPos = i - 1;
     557                 :         10 :       break;
     558                 :            :     }
     559                 :            :   }
     560                 :            :   // no disequality
     561         [ +  + ]:     582675 :   if (termPos == static_cast<unsigned>(-1))
     562                 :            :   {
     563                 :     582665 :     return false;
     564                 :            :   }
     565         [ +  - ]:         20 :   Trace("eqproof-conv")
     566                 :            :       << "EqProof::expandTransitivityForTheoryDisequalities: check if need "
     567                 :          0 :          "to expand transitivity step to conclude disequality "
     568                 :         10 :       << conclusion << " from premises " << premises << "\n";
     569                 :            : 
     570                 :            :   // Check if the premises are (= t1 c1) and (= t2 c2), modulo symmetry
     571                 :         20 :   std::vector<Node> subChildren, constChildren;
     572         [ +  + ]:         30 :   for (unsigned i = 0; i < 2; ++i)
     573                 :            :   {
     574                 :         40 :     Node term = conclusion[termPos][i];
     575         [ +  + ]:         60 :     for (const Node& premise : premises)
     576                 :            :     {
     577         [ +  + ]:         90 :       for (unsigned j = 0; j < 2; ++j)
     578                 :            :       {
     579                 :         70 :         if (premise[j] == term && premise[1 - j].isConst())
     580                 :            :         {
     581                 :         20 :           subChildren.push_back(premise[j].eqNode(premise[1 - j]));
     582                 :         20 :           constChildren.push_back(premise[1 - j]);
     583                 :         20 :           break;
     584                 :            :         }
     585                 :            :       }
     586                 :            :     }
     587                 :            :   }
     588         [ -  + ]:         10 :   if (subChildren.size() < 2)
     589                 :            :   {
     590                 :          0 :     return false;
     591                 :            :   }
     592                 :            :   // Now build
     593                 :            :   //   (= t1 c1)    (= t2 c2)
     594                 :            :   //  ------------------------- CONG   ------------------- MACRO_SR_PRED_INTRO
     595                 :            :   //   (= (= t1 t2) (= c1 c2))         (= (= c1 c2) false)
     596                 :            :   //  --------------------------------------------------------------------- TR
     597                 :            :   //                   (= (= t1 t2) false)
     598                 :         20 :   Node constApp = NodeManager::currentNM()->mkNode(Kind::EQUAL, constChildren);
     599                 :         20 :   Node constEquality = constApp.eqNode(conclusion[1 - termPos]);
     600         [ +  - ]:         20 :   Trace("eqproof-conv")
     601                 :          0 :       << "EqProof::expandTransitivityForTheoryDisequalities: adding "
     602                 :          0 :       << ProofRule::MACRO_SR_PRED_INTRO << " step for " << constApp << " = "
     603 [ -  + ][ -  - ]:         10 :       << conclusion[1 - termPos] << "\n";
     604                 :         20 :   p->addStep(
     605                 :         10 :       constEquality, ProofRule::MACRO_SR_PRED_INTRO, {}, {constEquality});
     606                 :            :   // build congruence conclusion (= (= t1 t2) (t c1 c2))
     607                 :         20 :   Node congConclusion = conclusion[termPos].eqNode(constApp);
     608         [ +  - ]:         20 :   Trace("eqproof-conv")
     609                 :          0 :       << "EqProof::expandTransitivityForTheoryDisequalities: adding  "
     610                 :         10 :       << ProofRule::CONG << " step for " << congConclusion << " from "
     611                 :         10 :       << subChildren << "\n";
     612                 :         20 :   p->addStep(congConclusion,
     613                 :            :              ProofRule::CONG,
     614                 :            :              {subChildren},
     615                 :            :              {ProofRuleChecker::mkKindNode(Kind::EQUAL)},
     616                 :         10 :              true);
     617         [ +  - ]:         20 :   Trace("eqproof-conv") << "EqProof::expandTransitivityForDisequalities: via "
     618                 :          0 :                            "congruence derived "
     619                 :         10 :                         << congConclusion << "\n";
     620                 :         40 :   std::vector<Node> transitivityChildren{congConclusion, constEquality};
     621                 :         10 :   p->addStep(conclusion, ProofRule::TRANS, {transitivityChildren}, {});
     622                 :         10 :   return true;
     623                 :            : }
     624                 :            : 
     625                 :    1807090 : bool EqProof::buildTransitivityChain(Node conclusion,
     626                 :            :                                      std::vector<Node>& premises) const
     627                 :            : {
     628         [ +  - ]:    3614180 :   Trace("eqproof-conv") << push
     629                 :          0 :                         << "EqProof::buildTransitivityChain: Build chain for "
     630                 :    1807090 :                         << conclusion << " with premises " << premises << "\n";
     631         [ +  - ]:    4664330 :   for (unsigned i = 0, size = premises.size(); i < size; ++i)
     632                 :            :   {
     633                 :    4664330 :     bool occurs = false, correctlyOrdered = false;
     634         [ +  + ]:    4664330 :     if (conclusion[0] == premises[i][0])
     635                 :            :     {
     636                 :     699827 :       occurs = correctlyOrdered = true;
     637                 :            :     }
     638         [ +  + ]:    3964500 :     else if (conclusion[0] == premises[i][1])
     639                 :            :     {
     640                 :    1107260 :       occurs = true;
     641                 :            :     }
     642         [ +  + ]:    4664330 :     if (occurs)
     643                 :            :     {
     644         [ +  - ]:    3614180 :       Trace("eqproof-conv")
     645         [ -  - ]:    1807090 :           << "EqProof::buildTransitivityChain: found " << conclusion[0] << " in"
     646 [ -  - ][ -  + ]:    1807090 :           << (correctlyOrdered ? "" : " non-") << " ordered premise "
     647                 :    1807090 :           << premises[i] << "\n";
     648 [ +  + ][ +  + ]:    1807090 :       if (conclusion[1] == premises[i][correctlyOrdered ? 1 : 0])
     649                 :            :       {
     650         [ +  - ]:    1251290 :         Trace("eqproof-conv")
     651 [ -  + ][ -  - ]:     625646 :             << "EqProof::buildTransitivityChain: found " << conclusion[1]
     652                 :          0 :             << " in same premise. Closed chain.\n"
     653                 :     625646 :             << pop;
     654                 :     625646 :         premises.clear();
     655                 :     625646 :         premises.push_back(conclusion);
     656                 :    1807090 :         return true;
     657                 :            :       }
     658                 :            :       // Build chain with remaining equalities
     659                 :    1181440 :       std::vector<Node> recursivePremises;
     660         [ +  + ]:    5242280 :       for (unsigned j = 0; j < size; ++j)
     661                 :            :       {
     662         [ +  + ]:    4060840 :         if (j != i)
     663                 :            :         {
     664                 :    2879390 :           recursivePremises.push_back(premises[j]);
     665                 :            :         }
     666                 :            :       }
     667                 :            :       Node newTarget =
     668         [ +  + ]:    2362890 :           premises[i][correctlyOrdered ? 1 : 0].eqNode(conclusion[1]);
     669         [ +  - ]:    2362890 :       Trace("eqproof-conv")
     670                 :          0 :           << "EqProof::buildTransitivityChain: search recursively for "
     671                 :    1181440 :           << newTarget << "\n";
     672         [ +  - ]:    1181440 :       if (buildTransitivityChain(newTarget, recursivePremises))
     673                 :            :       {
     674         [ +  - ]:    2362890 :         Trace("eqproof-conv")
     675                 :          0 :             << "EqProof::buildTransitivityChain: closed chain with "
     676                 :          0 :             << 1 + recursivePremises.size() << " of the original "
     677                 :    1181440 :             << premises.size() << " premises\n"
     678                 :    1181440 :             << pop;
     679                 :            :         Node premiseNode = correctlyOrdered
     680                 :     446862 :                                ? premises[i]
     681                 :    2362890 :                                : premises[i][1].eqNode(premises[i][0]);
     682                 :    1181440 :         premises.clear();
     683                 :    1181440 :         premises.push_back(premiseNode);
     684                 :            :         premises.insert(
     685                 :    1181440 :             premises.end(), recursivePremises.begin(), recursivePremises.end());
     686                 :    1181440 :         return true;
     687                 :            :       }
     688                 :            :     }
     689                 :            :   }
     690         [ -  - ]:          0 :   Trace("eqproof-conv")
     691                 :          0 :       << "EqProof::buildTransitivityChain: Could not build chain for"
     692                 :          0 :       << conclusion << " with premises " << premises << "\n";
     693         [ -  - ]:          0 :   Trace("eqproof-conv") << pop;
     694                 :          0 :   return false;
     695                 :            : }
     696                 :            : 
     697                 :    2027980 : void EqProof::reduceNestedCongruence(
     698                 :            :     unsigned i,
     699                 :            :     Node conclusion,
     700                 :            :     std::vector<std::vector<Node>>& transitivityMatrix,
     701                 :            :     CDProof* p,
     702                 :            :     std::unordered_map<Node, Node>& visited,
     703                 :            :     std::unordered_set<Node>& assumptions,
     704                 :            :     bool isNary) const
     705                 :            : {
     706         [ +  - ]:    4055970 :   Trace("eqproof-conv") << "EqProof::reduceNestedCongruence: building for " << i
     707                 :    2027980 :                         << "-th arg\n";
     708         [ +  + ]:    2027980 :   if (d_id == MERGED_THROUGH_CONGRUENCE)
     709                 :            :   {
     710 [ -  + ][ -  + ]:    1683070 :     Assert(d_children.size() == 2);
                 [ -  - ]
     711         [ +  - ]:    3366130 :     Trace("eqproof-conv") << "EqProof::reduceNestedCongruence: it's a "
     712                 :          0 :                              "congruence step. Reduce second child\n"
     713                 :    1683070 :                           << push;
     714                 :    3366130 :     transitivityMatrix[i].push_back(
     715                 :    3366130 :         d_children[1]->addToProof(p, visited, assumptions));
     716         [ +  - ]:    3366130 :     Trace("eqproof-conv")
     717                 :          0 :         << pop << "EqProof::reduceNestedCongruence: child conclusion "
     718                 :    1683070 :         << transitivityMatrix[i].back() << "\n";
     719                 :            :     // if i == 0, first child must be REFL step, standing for (= f f), which can
     720                 :            :     // be ignored in a first-order calculus
     721                 :            :     // Notice if higher-order is disabled, the following holds:
     722                 :            :     //   i > 0 || d_children[0]->d_id == MERGED_THROUGH_REFLEXIVITY
     723                 :            :     // We don't have access to whether we are higher-order in this context,
     724                 :            :     // so the above cannot be an assertion.
     725                 :            :     // recurse
     726         [ +  + ]:    1683070 :     if (i > 1)
     727                 :            :     {
     728         [ +  - ]:     842430 :       Trace("eqproof-conv")
     729                 :          0 :           << "EqProof::reduceNestedCongruence: Reduce first child\n"
     730                 :     421215 :           << push;
     731                 :     421215 :       d_children[0]->reduceNestedCongruence(i - 1,
     732                 :            :                                             conclusion,
     733                 :            :                                             transitivityMatrix,
     734                 :            :                                             p,
     735                 :            :                                             visited,
     736                 :            :                                             assumptions,
     737                 :            :                                             isNary);
     738         [ +  - ]:     421215 :       Trace("eqproof-conv") << pop;
     739                 :            :     }
     740                 :            :     // higher-order case
     741         [ +  + ]:    1261850 :     else if (d_children[0]->d_id != MERGED_THROUGH_REFLEXIVITY)
     742                 :            :     {
     743         [ +  - ]:        508 :       Trace("eqproof-conv") << "EqProof::reduceNestedCongruence: HO case. "
     744                 :        254 :                                "Processing first child\n";
     745                 :            :       // we only handle these cases
     746 [ +  + ][ -  + ]:        254 :       Assert(d_children[0]->d_id == MERGED_THROUGH_EQUALITY
         [ -  + ][ -  - ]
     747                 :            :              || d_children[0]->d_id == MERGED_THROUGH_TRANS);
     748                 :        508 :       transitivityMatrix[0].push_back(
     749                 :        508 :           d_children[0]->addToProof(p, visited, assumptions));
     750                 :            :     }
     751                 :    1683070 :     return;
     752                 :            :   }
     753 [ -  + ][ -  + ]:     344918 :   Assert(d_id == MERGED_THROUGH_TRANS)
                 [ -  - ]
     754                 :          0 :       << "id is " << static_cast<MergeReasonType>(d_id) << "\n";
     755         [ +  - ]:     689836 :   Trace("eqproof-conv") << "EqProof::reduceNestedCongruence: it's a "
     756                 :     344918 :                            "transitivity step.\n";
     757                 :     344918 :   Assert(d_node.isNull()
     758                 :            :          || d_node[0].getNumChildren() == d_node[1].getNumChildren() || isNary)
     759                 :            :       << "Non-null (internal cong) transitivity conclusion of different arity "
     760                 :          0 :          "but not marked by isNary flag\n";
     761                 :            :   // If handling n-ary kinds and got a transitivity conclusion, we process it
     762                 :            :   // with addToProof, store the result into row i, and stop. This marks an
     763                 :            :   // "adjustment" of the arity, with empty rows 0..i-1 in the matrix determining
     764                 :            :   // the adjustment in addToProof processing the congruence of the original
     765                 :            :   // conclusion. See details there.
     766 [ +  + ][ +  + ]:     344918 :   if (isNary && !d_node.isNull())
                 [ +  + ]
     767                 :            :   {
     768         [ +  - ]:        116 :     Trace("eqproof-conv") << "EqProof::reduceNestedCongruence: n-ary case, "
     769                 :          0 :                              "break recursion and indepedently process "
     770                 :          0 :                           << d_node << "\n"
     771                 :         58 :                           << push;
     772                 :         58 :     transitivityMatrix[i].push_back(addToProof(p, visited, assumptions));
     773         [ +  - ]:        116 :     Trace("eqproof-conv") << pop
     774                 :          0 :                           << "EqProof::reduceNestedCongruence: Got conclusion "
     775                 :          0 :                           << transitivityMatrix[i].back()
     776                 :         58 :                           << " from n-ary transitivity processing\n";
     777                 :         58 :     return;
     778                 :            :   }
     779                 :            :   // Regular recursive processing of each transitivity premise
     780         [ +  + ]:    1298720 :   for (unsigned j = 0, sizeTrans = d_children.size(); j < sizeTrans; ++j)
     781                 :            :   {
     782         [ +  - ]:     953855 :     if (d_children[j]->d_id == MERGED_THROUGH_CONGRUENCE)
     783                 :            :     {
     784         [ +  - ]:    1907710 :       Trace("eqproof-conv") << "EqProof::reduceNestedCongruence: Reduce " << j
     785                 :          0 :                             << "-th transitivity congruence child\n"
     786                 :     953855 :                             << push;
     787                 :     953855 :       d_children[j]->reduceNestedCongruence(
     788                 :            :           i, conclusion, transitivityMatrix, p, visited, assumptions, isNary);
     789         [ +  - ]:     953855 :       Trace("eqproof-conv") << pop;
     790                 :            :     }
     791                 :            :     else
     792                 :            :     {
     793         [ -  - ]:          0 :       Trace("eqproof-conv") << "EqProof::reduceNestedCongruence: Add " << j
     794                 :          0 :                             << "-th transitivity child to proof\n"
     795                 :          0 :                             << push;
     796                 :          0 :       transitivityMatrix[i].push_back(
     797                 :          0 :           d_children[j]->addToProof(p, visited, assumptions));
     798         [ -  - ]:          0 :       Trace("eqproof-conv") << pop;
     799                 :            :     }
     800                 :            :   }
     801                 :            : }
     802                 :            : 
     803                 :     298059 : Node EqProof::addToProof(CDProof* p) const
     804                 :            : {
     805                 :     596118 :   std::unordered_map<Node, Node> cache;
     806                 :     596118 :   std::unordered_set<Node> assumptions;
     807                 :     596118 :   Node conclusion = addToProof(p, cache, assumptions);
     808         [ +  - ]:     596118 :   Trace("eqproof-conv") << "EqProof::addToProof: root of proof: " << conclusion
     809                 :     298059 :                         << "\n";
     810         [ +  - ]:     596118 :   Trace("eqproof-conv") << "EqProof::addToProof: tracked assumptions: "
     811                 :     298059 :                         << assumptions << "\n";
     812                 :            :   // If conclusion t1 = tn is, modulo symmetry, of the form (= t true/false), in
     813                 :            :   // which t is not true/false, it must be turned into t or (not t) with
     814                 :            :   // TRUE/FALSE_ELIM.
     815                 :     298059 :   Node newConclusion = conclusion;
     816 [ -  + ][ -  + ]:     298059 :   Assert(conclusion.getKind() == Kind::EQUAL);
                 [ -  - ]
     817         [ +  + ]:     596118 :   if ((conclusion[0].getKind() == Kind::CONST_BOOLEAN)
     818                 :     298059 :       != (conclusion[1].getKind() == Kind::CONST_BOOLEAN))
     819                 :            :   {
     820         [ +  - ]:      59014 :     Trace("eqproof-conv")
     821                 :      29507 :         << "EqProof::addToProof: process root for TRUE/FALSE_ELIM\n";
     822                 :            :     // Index of constant in equality
     823                 :            :     unsigned constIndex =
     824                 :      29507 :         conclusion[0].getKind() == Kind::CONST_BOOLEAN ? 0 : 1;
     825                 :            :     // The premise for the elimination rule must have the constant as the second
     826                 :            :     // argument of the equality. If that's not the case, build it as such,
     827                 :            :     // relying on an implicit SYMM step to be added to the proof when justifying
     828                 :            :     // t / (not t).
     829                 :            :     Node elimPremise =
     830                 :      68334 :         constIndex == 1 ? conclusion : conclusion[1].eqNode(conclusion[0]);
     831                 :            :     // Determine whether TRUE_ELIM or FALSE_ELIM, depending on the constant
     832                 :            :     // value. The new conclusion, whether t or (not t), is also determined
     833                 :            :     // accordingly.
     834                 :            :     ProofRule elimRule;
     835         [ +  + ]:      29507 :     if (conclusion[constIndex].getConst<bool>())
     836                 :            :     {
     837                 :       8063 :       elimRule = ProofRule::TRUE_ELIM;
     838                 :       8063 :       newConclusion = conclusion[1 - constIndex];
     839                 :            :     }
     840                 :            :     else
     841                 :            :     {
     842                 :      21444 :       elimRule = ProofRule::FALSE_ELIM;
     843                 :      21444 :       newConclusion = conclusion[1 - constIndex].notNode();
     844                 :            :     }
     845                 :            :     // We also check if the final conclusion t / (not t) has already been
     846                 :            :     // justified, so that we can avoid a cyclic proof, which can be due to
     847                 :            :     // either t / (not t) being assumption in the original EqProof or it having
     848                 :            :     // a non-assumption proof step in the proof of (= t true/false).
     849 [ +  + ][ +  - ]:      29507 :     if (!assumptions.count(newConclusion) && !p->hasStep(newConclusion))
         [ +  + ][ +  + ]
                 [ -  - ]
     850                 :            :     {
     851         [ +  - ]:      38998 :       Trace("eqproof-conv")
     852                 :          0 :           << "EqProof::addToProof: conclude " << newConclusion << " via "
     853                 :      19499 :           << elimRule << " step for " << elimPremise << "\n";
     854                 :      38998 :       p->addStep(newConclusion, elimRule, {elimPremise}, {});
     855                 :            :     }
     856                 :            :   }
     857                 :     596118 :   return newConclusion;
     858                 :            : }
     859                 :            : 
     860                 :    3801140 : Node EqProof::addToProof(CDProof* p,
     861                 :            :                          std::unordered_map<Node, Node>& visited,
     862                 :            :                          std::unordered_set<Node>& assumptions) const
     863                 :            : {
     864                 :    3801140 :   std::unordered_map<Node, Node>::const_iterator it = visited.find(d_node);
     865         [ +  + ]:    3801140 :   if (it != visited.end())
     866                 :            :   {
     867         [ +  - ]:    1744990 :     Trace("eqproof-conv") << "EqProof::addToProof: already processed " << d_node
     868                 :     872495 :                           << ", returning " << it->second << "\n";
     869                 :     872495 :     return it->second;
     870                 :            :   }
     871         [ +  - ]:    5857280 :   Trace("eqproof-conv") << "EqProof::addToProof: adding step for " << d_id
     872                 :    2928640 :                         << " with conclusion " << d_node << "\n";
     873                 :            :   // Assumption
     874         [ +  + ]:    2928640 :   if (d_id == MERGED_THROUGH_EQUALITY)
     875                 :            :   {
     876                 :            :     // Check that no (= true/false true/false) assumptions
     877 [ +  - ][ +  - ]:    1373040 :     if (Configuration::isDebugBuild() && d_node.getKind() == Kind::EQUAL)
                 [ +  - ]
     878                 :            :     {
     879         [ +  + ]:    4119110 :       for (unsigned i = 0; i < 2; ++i)
     880                 :            :       {
     881                 :    5492150 :         Assert(d_node[i].getKind() != Kind::CONST_BOOLEAN
     882                 :            :                || d_node[1 - i].getKind() != Kind::CONST_BOOLEAN)
     883                 :          0 :             << "EqProof::addToProof: fully boolean constant assumption "
     884 [ -  + ][ -  + ]:    2746080 :             << d_node << " is disallowed\n";
                 [ -  - ]
     885                 :            :       }
     886                 :            :     }
     887                 :            :     // If conclusion is (= t true/false), we add a proof step
     888                 :            :     //          t
     889                 :            :     //  ---------------- TRUE/FALSE_INTRO
     890                 :            :     //  (= t true/false)
     891                 :            :     // according to the value of the Boolean constant
     892                 :    4119110 :     if (d_node.getKind() == Kind::EQUAL
     893 [ +  - ][ +  + ]:    4119110 :         && ((d_node[0].getKind() == Kind::CONST_BOOLEAN)
                 [ -  - ]
     894 [ +  + ][ +  - ]:    2746080 :             != (d_node[1].getKind() == Kind::CONST_BOOLEAN)))
         [ +  - ][ -  - ]
     895                 :            :     {
     896         [ +  - ]:      92244 :       Trace("eqproof-conv")
     897                 :      46122 :           << "EqProof::addToProof: add an intro step for " << d_node << "\n";
     898                 :            :       // Index of constant in equality
     899                 :      46122 :       unsigned constIndex = d_node[0].getKind() == Kind::CONST_BOOLEAN ? 0 : 1;
     900                 :            :       // The premise for the intro rule is either t or (not t), according to the
     901                 :            :       // Boolean constant.
     902                 :      92244 :       Node introPremise;
     903                 :            :       ProofRule introRule;
     904         [ +  + ]:      46122 :       if (d_node[constIndex].getConst<bool>())
     905                 :            :       {
     906                 :      14084 :         introRule = ProofRule::TRUE_INTRO;
     907                 :      14084 :         introPremise = d_node[1 - constIndex];
     908                 :            :         // Track the new assumption. If it's an equality, also its symmetric
     909                 :      14084 :         assumptions.insert(introPremise);
     910         [ -  + ]:      14084 :         if (introPremise.getKind() == Kind::EQUAL)
     911                 :            :         {
     912                 :          0 :           assumptions.insert(introPremise[1].eqNode(introPremise[0]));
     913                 :            :         }
     914                 :            :       }
     915                 :            :       else
     916                 :            :       {
     917                 :      32038 :         introRule = ProofRule::FALSE_INTRO;
     918                 :      32038 :         introPremise = d_node[1 - constIndex].notNode();
     919                 :            :         // Track the new assumption. If it's a disequality, also its symmetric
     920                 :      32038 :         assumptions.insert(introPremise);
     921         [ +  + ]:      32038 :         if (introPremise[0].getKind() == Kind::EQUAL)
     922                 :            :         {
     923                 :            :           assumptions.insert(
     924                 :      23544 :               introPremise[0][1].eqNode(introPremise[0][0]).notNode());
     925                 :            :         }
     926                 :            :       }
     927                 :            :       // The original assumption can be e.g. (= false (= t1 t2)) in which case
     928                 :            :       // the necessary proof to be built is
     929                 :            :       //     (not (= t1 t2))
     930                 :            :       //  -------------------- FALSE_INTRO
     931                 :            :       //  (= (= t1 t2) false)
     932                 :            :       //  -------------------- SYMM
     933                 :            :       //  (= false (= t1 t2))
     934                 :            :       //
     935                 :            :       // with the SYMM step happening automatically whenever the assumption is
     936                 :            :       // used in the proof p
     937                 :            :       Node introConclusion =
     938                 :      78935 :           constIndex == 1 ? d_node : d_node[1].eqNode(d_node[0]);
     939                 :      92244 :       p->addStep(introConclusion, introRule, {introPremise}, {});
     940                 :            :     }
     941                 :            :     else
     942                 :            :     {
     943                 :    2653830 :       p->addStep(d_node, ProofRule::ASSUME, {}, {d_node});
     944                 :            :     }
     945                 :            :     // If non-equality predicate, turn into one via TRUE/FALSE intro
     946                 :    2746080 :     Node conclusion = d_node;
     947         [ -  + ]:    1373040 :     if (d_node.getKind() != Kind::EQUAL)
     948                 :            :     {
     949                 :            :       // Track original assumption
     950                 :          0 :       assumptions.insert(d_node);
     951                 :            :       ProofRule intro;
     952         [ -  - ]:          0 :       if (d_node.getKind() == Kind::NOT)
     953                 :            :       {
     954                 :          0 :         intro = ProofRule::FALSE_INTRO;
     955                 :            :         conclusion =
     956                 :          0 :             d_node[0].eqNode(NodeManager::currentNM()->mkConst<bool>(false));
     957                 :            :       }
     958                 :            :       else
     959                 :            :       {
     960                 :          0 :         intro = ProofRule::TRUE_INTRO;
     961                 :            :         conclusion =
     962                 :          0 :             d_node.eqNode(NodeManager::currentNM()->mkConst<bool>(true));
     963                 :            :       }
     964         [ -  - ]:          0 :       Trace("eqproof-conv") << "EqProof::addToProof: adding " << intro
     965                 :          0 :                             << " step for " << d_node << "\n";
     966                 :          0 :       p->addStep(conclusion, intro, {d_node}, {});
     967                 :            :     }
     968                 :            :     // Keep track of assumptions to avoid cyclic proofs. Both the assumption and
     969                 :            :     // its symmetric are added
     970                 :    1373040 :     assumptions.insert(conclusion);
     971                 :    1373040 :     assumptions.insert(conclusion[1].eqNode(conclusion[0]));
     972         [ +  - ]:    2746080 :     Trace("eqproof-conv") << "EqProof::addToProof: tracking assumptions "
     973         [ -  - ]:    1373040 :                           << conclusion << ", (= " << conclusion[1] << " "
     974 [ -  + ][ -  + ]:    1373040 :                           << conclusion[0] << ")\n";
                 [ -  - ]
     975                 :    1373040 :     visited[d_node] = conclusion;
     976                 :    1373040 :     return conclusion;
     977                 :            :   }
     978                 :            :   // Refl and laborious congruence steps for (= (f t1 ... tn) (f t1 ... tn)),
     979                 :            :   // which can be safely turned into reflexivity steps. These laborious
     980                 :            :   // congruence steps are currently generated in the equality engine because of
     981                 :            :   // the suboptimal handling of n-ary operators.
     982                 :    3111200 :   if (d_id == MERGED_THROUGH_REFLEXIVITY
     983                 :    1555600 :       || (d_node.getKind() == Kind::EQUAL && d_node[0] == d_node[1]))
     984                 :            :   {
     985         [ +  - ]:     283830 :     Trace("eqproof-conv") << "EqProof::addToProof: refl step\n";
     986                 :            :     Node conclusion =
     987         [ +  - ]:     567660 :         d_node.getKind() == Kind::EQUAL ? d_node : d_node.eqNode(d_node);
     988                 :     567660 :     p->addStep(conclusion, ProofRule::REFL, {}, {conclusion[0]});
     989                 :     283830 :     visited[d_node] = conclusion;
     990                 :     283830 :     return conclusion;
     991                 :            :   }
     992                 :            :   // Equalities due to theory reasoning
     993         [ +  + ]:    1271770 :   if (d_id == MERGED_THROUGH_CONSTANTS)
     994                 :            :   {
     995                 :      27300 :     Assert(!d_node.isNull()
     996                 :            :            && ((d_node.getKind() == Kind::EQUAL && d_node[1].isConst())
     997                 :            :                || (d_node.getKind() == Kind::NOT
     998                 :            :                    && d_node[0].getKind() == Kind::EQUAL
     999                 :            :                    && d_node[0][0].isConst() && d_node[0][1].isConst())))
    1000 [ -  + ][ -  + ]:      13650 :         << ". Conclusion " << d_node << " from " << d_id
                 [ -  - ]
    1001                 :          0 :         << " was expected to be (= (f t1 ... tn) c) or (not (= c1 c2))\n";
    1002 [ -  + ][ -  - ]:      13650 :     Assert(!assumptions.count(d_node))
    1003 [ -  + ][ -  + ]:      13650 :         << "Conclusion " << d_node << " from " << d_id << " is an assumption\n";
                 [ -  - ]
    1004                 :            :     // The step has the form (not (= c1 c2)). We conclude it via
    1005                 :            :     // MACRO_SR_PRED_INTRO and turn it into an equality with false, so that the
    1006                 :            :     // rest of the reconstruction works
    1007         [ +  + ]:      13650 :     if (d_children.empty())
    1008                 :            :     {
    1009                 :            :       Node conclusion =
    1010                 :        792 :           d_node[0].eqNode(NodeManager::currentNM()->mkConst<bool>(false));
    1011                 :        528 :       p->addStep(d_node, ProofRule::MACRO_SR_PRED_INTRO, {}, {d_node});
    1012                 :        528 :       p->addStep(conclusion, ProofRule::FALSE_INTRO, {d_node}, {});
    1013                 :        264 :       visited[d_node] = conclusion;
    1014                 :        264 :       return conclusion;
    1015                 :            :     }
    1016                 :            :     // The step has the form
    1017                 :            :     //  [(= t1 c1)] ... [(= tn cn)]
    1018                 :            :     //  ------------------------
    1019                 :            :     //    (= (f t1 ... tn) c)
    1020                 :            :     // where premises equating ti to constants are present when they are not
    1021                 :            :     // already constants. Note that the premises may be in any order, e.g. with
    1022                 :            :     // the equality for the second term being justified in the first premise.
    1023                 :            :     // Moreover, they may be of the form (= ci ti).
    1024                 :            :     //
    1025                 :            :     // First recursively process premises, if any
    1026                 :      26772 :     std::vector<Node> premises;
    1027         [ +  + ]:      40467 :     for (unsigned i = 0; i < d_children.size(); ++i)
    1028                 :            :     {
    1029         [ +  - ]:      54162 :       Trace("eqproof-conv")
    1030                 :          0 :           << "EqProof::addToProof: recurse on child " << i << "\n"
    1031                 :      27081 :           << push;
    1032                 :      27081 :       premises.push_back(d_children[i]->addToProof(p, visited, assumptions));
    1033         [ +  - ]:      27081 :       Trace("eqproof-conv") << pop;
    1034                 :            :     }
    1035                 :            :     // After building the proper premises we could build a step like
    1036                 :            :     //  [(= t1 c1)] ...  [(= tn cn)]
    1037                 :            :     //  ---------------------------- MACRO_SR_PRED_INTRO
    1038                 :            :     //    (= (f t1 ... tn) c)
    1039                 :            :     // but note that since the substitution applied by MACRO_SR_PRED_INTRO is
    1040                 :            :     // *not* simultenous this could lead to issues if t_{i+1} occurred in some
    1041                 :            :     // t_{i}. So we build proofs as
    1042                 :            :     //
    1043                 :            :     //    [(= t1 c1)] ...  [(= tn cn)]
    1044                 :            :     //  ------------------------------- CONG  -------------- MACRO_SR_PRED_INTRO
    1045                 :            :     //  (= (f t1 ... tn) (f c1 ... cn))       (= (f c1 ... cn) c)
    1046                 :            :     // ---------------------------------------------------------- TRANS
    1047                 :            :     //                     (= (f t1 ... tn) c)
    1048                 :      26772 :     std::vector<Node> subChildren, constChildren;
    1049         [ +  + ]:      40467 :     for (unsigned i = 0, size = d_node[0].getNumChildren(); i < size; ++i)
    1050                 :            :     {
    1051                 :      27081 :       Node term = d_node[0][i];
    1052                 :            :       // term already is a constant, add a REFL step
    1053         [ +  + ]:      27081 :       if (term.isConst())
    1054                 :            :       {
    1055                 :      10239 :         subChildren.push_back(term.eqNode(term));
    1056                 :      20478 :         p->addStep(subChildren.back(), ProofRule::REFL, {}, {term});
    1057                 :      10239 :         constChildren.push_back(term);
    1058                 :      10239 :         continue;
    1059                 :            :       }
    1060                 :            :       // Build the equality (= ti ci) as a premise, finding the respective ci is
    1061                 :            :       // the original premises
    1062                 :      33684 :       Node constant;
    1063         [ +  - ]:      27954 :       for (const Node& premise : premises)
    1064                 :            :       {
    1065 [ -  + ][ -  + ]:      27954 :         Assert(premise.getKind() == Kind::EQUAL);
                 [ -  - ]
    1066         [ +  + ]:      27954 :         if (premise[0] == term)
    1067                 :            :         {
    1068 [ -  + ][ -  + ]:       3692 :           Assert(premise[1].isConst());
                 [ -  - ]
    1069                 :       3692 :           constant = premise[1];
    1070                 :       3692 :           break;
    1071                 :            :         }
    1072         [ +  + ]:      24262 :         if (premise[1] == term)
    1073                 :            :         {
    1074 [ -  + ][ -  + ]:      13150 :           Assert(premise[0].isConst());
                 [ -  - ]
    1075                 :      13150 :           constant = premise[0];
    1076                 :      13150 :           break;
    1077                 :            :         }
    1078                 :            :       }
    1079 [ -  + ][ -  + ]:      16842 :       Assert(!constant.isNull());
                 [ -  - ]
    1080                 :      16842 :       subChildren.push_back(term.eqNode(constant));
    1081                 :      16842 :       constChildren.push_back(constant);
    1082                 :            :     }
    1083                 :            :     // build constant application (f c1 ... cn) and equality (= (f c1 ... cn) c)
    1084                 :      13386 :     Kind k = d_node[0].getKind();
    1085                 :      26772 :     std::vector<Node> cargs;
    1086                 :      13386 :     ProofRule rule = expr::getCongRule(d_node[0], cargs);
    1087         [ -  + ]:      13386 :     if (d_node[0].getMetaKind() == kind::metakind::PARAMETERIZED)
    1088                 :            :     {
    1089                 :          0 :       constChildren.insert(constChildren.begin(), d_node[0].getOperator());
    1090                 :            :     }
    1091                 :      26772 :     Node constApp = NodeManager::currentNM()->mkNode(k, constChildren);
    1092                 :      26772 :     Node constEquality = constApp.eqNode(d_node[1]);
    1093         [ +  - ]:      26772 :     Trace("eqproof-conv") << "EqProof::addToProof: adding "
    1094                 :          0 :                           << ProofRule::MACRO_SR_PRED_INTRO << " step for "
    1095 [ -  + ][ -  - ]:      13386 :                           << constApp << " = " << d_node[1] << "\n";
    1096                 :      26772 :     p->addStep(
    1097                 :      13386 :         constEquality, ProofRule::MACRO_SR_PRED_INTRO, {}, {constEquality});
    1098                 :            :     // build congruence conclusion (= (f t1 ... tn) (f c1 ... cn))
    1099                 :      26772 :     Node congConclusion = d_node[0].eqNode(constApp);
    1100         [ +  - ]:      26772 :     Trace("eqproof-conv") << "EqProof::addToProof: adding  " << rule
    1101                 :          0 :                           << " step for " << congConclusion << " from "
    1102                 :      13386 :                           << subChildren << "\n";
    1103                 :      13386 :     p->addStep(congConclusion, rule, {subChildren}, cargs, true);
    1104         [ +  - ]:      26772 :     Trace("eqproof-conv") << "EqProof::addToProof: adding  " << ProofRule::TRANS
    1105                 :      13386 :                           << " step for original conclusion " << d_node << "\n";
    1106                 :      66930 :     std::vector<Node> transitivityChildren{congConclusion, constEquality};
    1107                 :      13386 :     p->addStep(d_node, ProofRule::TRANS, {transitivityChildren}, {});
    1108                 :      13386 :     visited[d_node] = d_node;
    1109                 :      13386 :     return d_node;
    1110                 :            :   }
    1111                 :            :   // Transtivity and disequality reasoning steps
    1112         [ +  + ]:    1258120 :   if (d_id == MERGED_THROUGH_TRANS)
    1113                 :            :   {
    1114                 :    1210420 :     Assert(d_node.getKind() == Kind::EQUAL
    1115                 :            :            || (d_node.getKind() == Kind::NOT
    1116                 :            :                && d_node[0].getKind() == Kind::EQUAL))
    1117 [ -  + ][ -  + ]:     605208 :         << "EqProof::addToProof: transitivity step conclusion " << d_node
                 [ -  - ]
    1118                 :          0 :         << " is not equality or negated equality\n";
    1119                 :            :     // If conclusion is (not (= t1 t2)) change it to (= (= t1 t2) false), which
    1120                 :            :     // is the correct conclusion of the equality reasoning step. A FALSE_ELIM
    1121                 :            :     // step to revert this is only necessary when this is the root. That step is
    1122                 :            :     // done in the non-recursive caller of this function.
    1123                 :            :     Node conclusion =
    1124                 :     605208 :         d_node.getKind() != Kind::NOT
    1125                 :     600995 :             ? d_node
    1126                 :    1214630 :             : d_node[0].eqNode(NodeManager::currentNM()->mkConst<bool>(false));
    1127                 :            :     // If the conclusion is an assumption, its derivation was spurious, so it
    1128                 :            :     // can be discarded. Moreover, reconstructing the step may lead to cyclic
    1129                 :            :     // proofs, so we *must* cut here.
    1130         [ -  + ]:     605208 :     if (assumptions.count(conclusion))
    1131                 :            :     {
    1132                 :          0 :       visited[d_node] = conclusion;
    1133                 :          0 :       return conclusion;
    1134                 :            :     }
    1135                 :            :     // Process premises recursively
    1136                 :    1210420 :     std::vector<Node> children;
    1137         [ +  + ]:    2388540 :     for (unsigned i = 0, size = d_children.size(); i < size; ++i)
    1138                 :            :     {
    1139                 :            :       // If one of the steps is a "fake congruence" one, marked by a null
    1140                 :            :       // conclusion, it must deleted. Its premises are moved down to premises of
    1141                 :            :       // the transitivity step.
    1142                 :    1783340 :       EqProof* childProof = d_children[i].get();
    1143                 :    3566670 :       if (childProof->d_id == MERGED_THROUGH_CONGRUENCE
    1144 [ +  + ][ +  + ]:    1783340 :           && childProof->d_node.isNull())
                 [ +  + ]
    1145                 :            :       {
    1146         [ +  - ]:      18562 :         Trace("eqproof-conv") << "EqProof::addToProof: child proof " << i
    1147                 :       9281 :                               << " is fake cong step. Fold it.\n";
    1148 [ -  + ][ -  + ]:       9281 :         Assert(childProof->d_children.size() == 2);
                 [ -  - ]
    1149         [ +  - ]:       9281 :         Trace("eqproof-conv") << push;
    1150         [ +  + ]:      27843 :         for (unsigned j = 0, sizeJ = childProof->d_children.size(); j < sizeJ;
    1151                 :            :              ++j)
    1152                 :            :         {
    1153         [ +  - ]:      37124 :           Trace("eqproof-conv")
    1154                 :          0 :               << "EqProof::addToProof: recurse on child " << j << "\n"
    1155                 :      18562 :               << push;
    1156                 :      18562 :           children.push_back(
    1157                 :      37124 :               childProof->d_children[j]->addToProof(p, visited, assumptions));
    1158         [ +  - ]:      18562 :           Trace("eqproof-conv") << pop;
    1159                 :            :         }
    1160         [ +  - ]:       9281 :         Trace("eqproof-conv") << pop;
    1161                 :       9281 :         continue;
    1162                 :            :       }
    1163         [ +  - ]:    3548110 :       Trace("eqproof-conv")
    1164                 :          0 :           << "EqProof::addToProof: recurse on child " << i << "\n"
    1165                 :    1774060 :           << push;
    1166                 :    1774060 :       children.push_back(childProof->addToProof(p, visited, assumptions));
    1167         [ +  - ]:    1774060 :       Trace("eqproof-conv") << pop;
    1168                 :            :     }
    1169                 :            :     // Eliminate spurious premises. Reasoning below assumes no refl steps.
    1170                 :     605208 :     cleanReflPremises(children);
    1171                 :            :     // If any premise is of the form (= (t1 t2) false), then the transitivity
    1172                 :            :     // step may be coarse-grained and needs to be expanded. If the expansion
    1173                 :            :     // happens it also finalizes the proof of conclusion.
    1174         [ +  + ]:     605208 :     if (!expandTransitivityForDisequalities(
    1175                 :            :             conclusion, children, p, assumptions))
    1176                 :            :     {
    1177 [ -  + ][ -  + ]:     582675 :       Assert(!children.empty());
                 [ -  - ]
    1178                 :            :       // similarly, if a disequality is concluded because of theory reasoning,
    1179                 :            :       // the step is coarse-grained and needs to be expanded, in which case the
    1180                 :            :       // proof is finalized in the call
    1181         [ +  + ]:     582675 :       if (!expandTransitivityForTheoryDisequalities(conclusion, children, p))
    1182                 :            :       {
    1183         [ +  - ]:    1165330 :         Trace("eqproof-conv")
    1184                 :          0 :             << "EqProof::addToProof: build chain for transitivity premises"
    1185                 :     582665 :             << children << " to conclude " << conclusion << "\n";
    1186                 :            :         // Build ordered transitivity chain from children to derive the
    1187                 :            :         // conclusion
    1188                 :     582665 :         buildTransitivityChain(conclusion, children);
    1189                 :     582708 :         Assert(
    1190                 :            :             children.size() > 1
    1191                 :            :             || (!children.empty()
    1192                 :            :                 && (children[0] == conclusion
    1193                 :            :                     || children[0][1].eqNode(children[0][0]) == conclusion)));
    1194                 :            :         // Only add transitivity step if there is more than one premise in the
    1195                 :            :         // chain. Otherwise the premise will be the conclusion itself and it'll
    1196                 :            :         // already have had a step added to it when the premises were
    1197                 :            :         // recursively processed.
    1198         [ +  + ]:     582665 :         if (children.size() > 1)
    1199                 :            :         {
    1200                 :     582622 :           p->addStep(conclusion, ProofRule::TRANS, children, {}, true);
    1201                 :            :         }
    1202                 :            :       }
    1203                 :            :     }
    1204                 :    1210420 :     Assert(p->hasStep(conclusion) || assumptions.count(conclusion))
    1205 [ -  + ][ -  + ]:     605208 :         << "Conclusion " << conclusion
                 [ -  - ]
    1206                 :          0 :         << " does not have a step in the proof neither it's an assumption.\n";
    1207                 :     605208 :     visited[d_node] = conclusion;
    1208                 :     605208 :     return conclusion;
    1209                 :            :   }
    1210 [ -  + ][ -  + ]:     652914 :   Assert(d_id == MERGED_THROUGH_CONGRUENCE);
                 [ -  - ]
    1211                 :            :   // The processing below is mainly dedicated to flattening congruence steps
    1212                 :            :   // (since EqProof assumes currying) and to prossibly reconstructing the
    1213                 :            :   // conclusion in case it involves n-ary steps.
    1214 [ -  + ][ -  - ]:     652914 :   Assert(d_node.getKind() == Kind::EQUAL)
    1215 [ -  + ][ -  + ]:     652914 :       << "EqProof::addToProof: conclusion " << d_node << " is not equality\n";
                 [ -  - ]
    1216                 :            :   // The given conclusion is taken as ground truth. If the premises do not
    1217                 :            :   // align, for example with (= (f t1) (f t2)) but a premise being (= t2 t1), we
    1218                 :            :   // use (= t1 t2) as a premise and rely on a symmetry step to justify it.
    1219                 :     652914 :   unsigned arity = d_node[0].getNumChildren();
    1220                 :     652914 :   Kind k = d_node[0].getKind();
    1221                 :     652914 :   bool isNary = NodeManager::isNAryKind(k);
    1222                 :            : 
    1223                 :            :   // N-ary operators are fun. The following proof is a valid EqProof
    1224                 :            :   //
    1225                 :            :   //   (= (f t1 t2 t3) (f t6 t5)) (= (f t6 t5) (f t5 t6))
    1226                 :            :   //   -------------------------------------------------- TRANS
    1227                 :            :   //             (= (f t1 t2 t3) (f t5 t6))                      (= t4 t7)
    1228                 :            :   //          ------------------------------------------------------------ CONG
    1229                 :            :   //          (= (f t1 t2 t3 t4) (f t5 t6 t7))
    1230                 :            :   //
    1231                 :            :   // We modify the above proof to conclude
    1232                 :            :   //
    1233                 :            :   //   (= (f (f t1 t2 t3) t4) (f (f t5 t6) t7))
    1234                 :            :   //
    1235                 :            :   // which is a valid congruence conclusion (applications of f with the same
    1236                 :            :   // arity). For the processing below to be//  performed correctly we update
    1237                 :            :   // arity to be maximal one among the two applications (4 in the above
    1238                 :            :   // example).
    1239         [ -  + ]:     652914 :   if (d_node[0].getNumChildren() != d_node[1].getNumChildren())
    1240                 :            :   {
    1241                 :          0 :     Assert(isNary) << "We only handle congruences of apps with different "
    1242                 :          0 :                       "number of children for theory n-ary operators";
    1243                 :          0 :     arity =
    1244                 :          0 :         d_node[1].getNumChildren() < arity ? arity : d_node[1].getNumChildren();
    1245         [ -  - ]:          0 :     Trace("eqproof-conv")
    1246                 :          0 :         << "EqProof::addToProof: Mismatching arities in cong conclusion "
    1247                 :          0 :         << d_node << ". Use tentative arity " << arity << "\n";
    1248                 :            :   }
    1249                 :            :   // For a congruence proof of (= (f a0 ... an-1) (g b0 ... bn-1)), build a
    1250                 :            :   // transitivity matrix of n rows where the first row contains a transitivity
    1251                 :            :   // chain justifying (= f g) and the next rows (= ai bi)
    1252                 :    1305830 :   std::vector<std::vector<Node>> transitivityChildren;
    1253         [ +  + ]:    2379330 :   for (unsigned i = 0; i < arity + 1; ++i)
    1254                 :            :   {
    1255                 :    1726420 :     transitivityChildren.push_back(std::vector<Node>());
    1256                 :            :   }
    1257                 :     652914 :   reduceNestedCongruence(
    1258                 :     652914 :       arity, d_node, transitivityChildren, p, visited, assumptions, isNary);
    1259                 :            :   // Congruences over n-ary operators may require changing the conclusion (as in
    1260                 :            :   // the above example). This is handled in a general manner below according to
    1261                 :            :   // whether the transitivity matrix computed by reduceNestedCongruence contains
    1262                 :            :   // empty rows
    1263                 :    1305830 :   Node conclusion = d_node;
    1264                 :     652914 :   NodeManager* nm = NodeManager::currentNM();
    1265         [ +  + ]:     652914 :   if (isNary)
    1266                 :            :   {
    1267                 :     577863 :     unsigned emptyRows = 0;
    1268         [ +  + ]:    1551540 :     for (unsigned i = 1; i <= arity; ++i)
    1269                 :            :     {
    1270         [ +  + ]:     973679 :       if (transitivityChildren[i].empty())
    1271                 :            :       {
    1272                 :         58 :         emptyRows++;
    1273                 :            :       }
    1274                 :            :     }
    1275                 :            :     // Given two n-ary applications f1:(f a0 ... an-1), f2:(f b0 ... bm-1), of
    1276                 :            :     // arities n and m, arity = max(n,m), the number emptyRows establishes the
    1277                 :            :     // sizes of the prefixes of f1 of f2 that have been equated via a
    1278                 :            :     // transitivity step. The prefixes necessarily have different sizes. The
    1279                 :            :     // suffixes have the same sizes. The new conclusion will be of the form
    1280                 :            :     //     (= (f (f a0 ... ak1) ... an-1) (f (f b0 ... bk2) ... bm-1))
    1281                 :            :     // where
    1282                 :            :     //  k1 = emptyRows + 1 - (arity - n)
    1283                 :            :     //  k2 = emptyRows + 1 - (arity - m)
    1284                 :            :     //  k1 != k2
    1285                 :            :     //  n - k1 == m - k2
    1286                 :            :     // Note that by construction the equality between the first emptyRows + 1
    1287                 :            :     // arguments of each application is justified by the transitivity step in
    1288                 :            :     // the row emptyRows + 1 in the matrix.
    1289                 :            :     //
    1290                 :            :     // All of the above is with the very first row in the matrix, reserved for
    1291                 :            :     // justifying the equality between the functions, which is not necessary in
    1292                 :            :     // the n-ary case, notwithstanding.
    1293         [ +  + ]:     577863 :     if (emptyRows > 0)
    1294                 :            :     {
    1295         [ +  - ]:        116 :       Trace("eqproof-conv")
    1296                 :          0 :           << "EqProof::addToProof: Found " << emptyRows
    1297                 :         58 :           << " empty rows. Rebuild conclusion " << d_node << "\n";
    1298                 :            :       // New transitivity matrix is as before except that the empty rows in the
    1299                 :            :       // beginning are eliminated, as the new arity is the maximal arity among
    1300                 :            :       // the applications minus the number of empty rows.
    1301                 :            :       std::vector<std::vector<Node>> newTransitivityChildren{
    1302                 :         58 :           transitivityChildren.begin() + 1 + emptyRows,
    1303                 :        174 :           transitivityChildren.end()};
    1304                 :         58 :       transitivityChildren.clear();
    1305                 :         58 :       transitivityChildren.push_back(std::vector<Node>());
    1306                 :         58 :       transitivityChildren.insert(transitivityChildren.end(),
    1307                 :            :                                   newTransitivityChildren.begin(),
    1308                 :        116 :                                   newTransitivityChildren.end());
    1309                 :            :       unsigned arityPrefix1 =
    1310                 :         58 :           emptyRows + 1 - (arity - d_node[0].getNumChildren());
    1311 [ -  + ][ -  - ]:        116 :       Assert(arityPrefix1 < d_node[0].getNumChildren())
    1312                 :          0 :           << "arityPrefix1 " << arityPrefix1 << " not smaller than "
    1313                 :         58 :           << d_node[0] << "'s arity " << d_node[0].getNumChildren() << "\n";
    1314                 :            :       unsigned arityPrefix2 =
    1315                 :         58 :           emptyRows + 1 - (arity - d_node[1].getNumChildren());
    1316 [ -  + ][ -  - ]:        116 :       Assert(arityPrefix2 < d_node[1].getNumChildren())
    1317                 :          0 :           << "arityPrefix2 " << arityPrefix2 << " not smaller than "
    1318                 :         58 :           << d_node[1] << "'s arity " << d_node[1].getNumChildren() << "\n";
    1319         [ +  - ]:        116 :       Trace("eqproof-conv") << "EqProof::addToProof: New internal "
    1320                 :          0 :                                "applications with arities "
    1321                 :         58 :                             << arityPrefix1 << ", " << arityPrefix2 << ":\n";
    1322                 :            :       std::vector<Node> childrenPrefix1{d_node[0].begin(),
    1323                 :        174 :                                         d_node[0].begin() + arityPrefix1};
    1324                 :            :       std::vector<Node> childrenPrefix2{d_node[1].begin(),
    1325                 :        174 :                                         d_node[1].begin() + arityPrefix2};
    1326                 :        116 :       Node newFirstChild1 = nm->mkNode(k, childrenPrefix1);
    1327                 :        116 :       Node newFirstChild2 = nm->mkNode(k, childrenPrefix2);
    1328         [ +  - ]:        116 :       Trace("eqproof-conv")
    1329                 :         58 :           << "EqProof::addToProof:\t " << newFirstChild1 << "\n";
    1330         [ +  - ]:        116 :       Trace("eqproof-conv")
    1331                 :         58 :           << "EqProof::addToProof:\t " << newFirstChild2 << "\n";
    1332                 :        232 :       std::vector<Node> newChildren1{newFirstChild1};
    1333                 :         58 :       newChildren1.insert(newChildren1.end(),
    1334                 :         58 :                           d_node[0].begin() + arityPrefix1,
    1335                 :        174 :                           d_node[0].end());
    1336                 :        174 :       std::vector<Node> newChildren2{newFirstChild2};
    1337                 :         58 :       newChildren2.insert(newChildren2.end(),
    1338                 :         58 :                           d_node[1].begin() + arityPrefix2,
    1339                 :        174 :                           d_node[1].end());
    1340                 :        174 :       conclusion = nm->mkNode(Kind::EQUAL,
    1341                 :        116 :                               nm->mkNode(k, newChildren1),
    1342                 :        174 :                               nm->mkNode(k, newChildren2));
    1343                 :            :       // update arity
    1344 [ -  + ][ -  + ]:         58 :       Assert((arity - emptyRows) == conclusion[0].getNumChildren());
                 [ -  - ]
    1345                 :         58 :       arity = arity - emptyRows;
    1346         [ +  - ]:        116 :       Trace("eqproof-conv")
    1347                 :         58 :           << "EqProof::addToProof: New conclusion " << conclusion << "\n";
    1348                 :            :     }
    1349                 :            :   }
    1350         [ -  + ]:     652914 :   if (TraceIsOn("eqproof-conv"))
    1351                 :            :   {
    1352         [ -  - ]:          0 :     Trace("eqproof-conv")
    1353                 :          0 :         << "EqProof::addToProof: premises from reduced cong of " << conclusion
    1354                 :          0 :         << ":\n";
    1355         [ -  - ]:          0 :     for (unsigned i = 0; i <= arity; ++i)
    1356                 :            :     {
    1357         [ -  - ]:          0 :       Trace("eqproof-conv") << "EqProof::addToProof:\t" << i
    1358                 :          0 :                             << "-th arg: " << transitivityChildren[i] << "\n";
    1359                 :            :     }
    1360                 :            :   }
    1361                 :    1305830 :   std::vector<Node> children(arity + 1);
    1362                 :            :   // Process transitivity matrix to (possibly) generate transitivity steps for
    1363                 :            :   // congruence premises (= ai bi)
    1364         [ +  + ]:    2379280 :   for (unsigned i = 0; i <= arity; ++i)
    1365                 :            :   {
    1366                 :    1726360 :     Node transConclusion;
    1367                 :            :     // We special case the operator case because there is only ever the need to
    1368                 :            :     // do something when in some HO case
    1369         [ +  + ]:    1726360 :     if (i == 0)
    1370                 :            :     {
    1371                 :            :       // no justification for equality between functions, skip
    1372         [ +  + ]:     652914 :       if (transitivityChildren[0].empty())
    1373                 :            :       {
    1374                 :     652660 :         continue;
    1375                 :            :       }
    1376                 :            :       // HO case
    1377 [ -  + ][ -  + ]:        254 :       Assert(k == Kind::APPLY_UF) << "Congruence with different functions only "
                 [ -  - ]
    1378                 :          0 :                                      "allowed for uninterpreted functions.\n";
    1379                 :            :       transConclusion =
    1380                 :        254 :           conclusion[0].getOperator().eqNode(conclusion[1].getOperator());
    1381                 :            :     }
    1382                 :            :     else
    1383                 :            :     {
    1384                 :    1073450 :       transConclusion = conclusion[0][i - 1].eqNode(conclusion[1][i - 1]);
    1385                 :            :     }
    1386                 :    1073700 :     children[i] = transConclusion;
    1387 [ -  + ][ -  - ]:    1073700 :     Assert(!transitivityChildren[i].empty())
    1388                 :          0 :         << "EqProof::addToProof: did not add any justification for " << i
    1389 [ -  + ][ -  + ]:    1073700 :         << "-th arg of congruence " << conclusion << "\n";
                 [ -  - ]
    1390                 :            :     // If the transitivity conclusion is a reflexivity step, just add it. Note
    1391                 :            :     // that this can happen even with the respective transitivityChildren row
    1392                 :            :     // containing several equalities in the case of (= ai bi) being the same
    1393                 :            :     // n-ary application that was justified by a congruence step, which can
    1394                 :            :     // happen in the current equality engine.
    1395         [ +  + ]:    1073700 :     if (transConclusion[0] == transConclusion[1])
    1396                 :            :     {
    1397                 :     490738 :       p->addStep(transConclusion, ProofRule::REFL, {}, {transConclusion[0]});
    1398                 :     245369 :       continue;
    1399                 :            :     }
    1400                 :            :     // Remove spurious refl steps from the premises for (= ai bi)
    1401                 :     828333 :     cleanReflPremises(transitivityChildren[i]);
    1402                 :    1656670 :     Assert(transitivityChildren[i].size() > 1 || transitivityChildren[i].empty()
    1403                 :            :            || CDProof::isSame(transitivityChildren[i][0], transConclusion))
    1404                 :          0 :         << "EqProof::addToProof: premises " << transitivityChildren[i] << "for "
    1405 [ -  + ][ -  + ]:     828333 :         << i << "-th cong premise " << transConclusion << " don't justify it\n";
                 [ -  - ]
    1406                 :     828333 :     unsigned sizeTrans = transitivityChildren[i].size();
    1407                 :            :     // If no transitivity premise left or if (= ai bi) is an assumption (which
    1408                 :            :     // might lead to a cycle with a transtivity step), nothing else to do.
    1409 [ +  - ][ +  + ]:     828333 :     if (sizeTrans == 0 || assumptions.count(transConclusion) > 0)
                 [ +  + ]
    1410                 :            :     {
    1411                 :     411321 :       continue;
    1412                 :            :     }
    1413                 :            :     // If the transitivity conclusion, or its symmetric, occurs in the
    1414                 :            :     // transitivity premises, nothing to do, as it is already justified and
    1415                 :            :     // doing so again would lead to a cycle.
    1416                 :     417012 :     bool occurs = false;
    1417 [ +  + ][ +  + ]:     865570 :     for (unsigned j = 0; j < sizeTrans && !occurs; ++j)
    1418                 :            :     {
    1419         [ +  + ]:     448558 :       if (CDProof::isSame(transitivityChildren[i][j], transConclusion))
    1420                 :            :       {
    1421                 :     389475 :         occurs = true;
    1422                 :            :       }
    1423                 :            :     }
    1424         [ +  + ]:     417012 :     if (!occurs)
    1425                 :            :     {
    1426                 :            :       // Build transitivity step
    1427                 :      27537 :       buildTransitivityChain(transConclusion, transitivityChildren[i]);
    1428         [ +  - ]:      55074 :       Trace("eqproof-conv")
    1429                 :          0 :           << "EqProof::addToProof: adding trans step for cong premise "
    1430                 :          0 :           << transConclusion << " with children " << transitivityChildren[i]
    1431                 :      27537 :           << "\n";
    1432                 :      55074 :       p->addStep(
    1433                 :      27537 :           transConclusion, ProofRule::TRANS, transitivityChildren[i], {}, true);
    1434                 :            :     }
    1435                 :            :   }
    1436                 :            :   // first-order case
    1437         [ +  + ]:     652914 :   if (children[0].isNull())
    1438                 :            :   {
    1439                 :            :     // remove placehold for function equality case
    1440                 :     652660 :     children.erase(children.begin());
    1441                 :            :     // Get node of the function operator over which congruence is being
    1442                 :            :     // applied.
    1443                 :     652660 :     std::vector<Node> args;
    1444                 :     652660 :     ProofRule r = expr::getCongRule(d_node[0], args);
    1445                 :            :     // Add congruence step
    1446         [ -  + ]:     652660 :     if (TraceIsOn("eqproof-conv"))
    1447                 :            :     {
    1448         [ -  - ]:          0 :       Trace("eqproof-conv")
    1449                 :          0 :           << "EqProof::addToProof: build cong step of " << conclusion;
    1450         [ -  - ]:          0 :       if (!args.empty())
    1451                 :            :       {
    1452         [ -  - ]:          0 :         Trace("eqproof-conv") << " with op " << args[0];
    1453                 :            :       }
    1454         [ -  - ]:          0 :       Trace("eqproof-conv") << " and children " << children << "\n";
    1455                 :            :     }
    1456                 :     652660 :     p->addStep(conclusion, r, children, args, true);
    1457                 :            :   }
    1458                 :            :   // higher-order case
    1459                 :            :   else
    1460                 :            :   {
    1461                 :            :     // Add congruence step
    1462         [ +  - ]:        508 :     Trace("eqproof-conv") << "EqProof::addToProof: build HO-cong step of "
    1463                 :          0 :                           << conclusion << " with children " << children
    1464                 :        254 :                           << "\n";
    1465                 :        508 :     p->addStep(conclusion,
    1466                 :            :                ProofRule::HO_CONG,
    1467                 :            :                children,
    1468                 :            :                {ProofRuleChecker::mkKindNode(Kind::APPLY_UF)},
    1469                 :        254 :                true);
    1470                 :            :   }
    1471                 :            :   // If the conclusion of the congruence step changed due to the n-ary handling,
    1472                 :            :   // we obtained for example (= (f (f t1 t2 t3) t4) (f (f t5 t6) t7)), which is
    1473                 :            :   // flattened into the original conclusion (= (f t1 t2 t3 t4) (f t5 t6 t7)) via
    1474                 :            :   // rewriting
    1475         [ +  + ]:     652914 :   if (!CDProof::isSame(conclusion, d_node))
    1476                 :            :   {
    1477         [ +  - ]:        116 :     Trace("eqproof-conv") << "EqProof::addToProof: try to flatten via a"
    1478                 :         58 :                           << ProofRule::MACRO_SR_PRED_TRANSFORM
    1479                 :          0 :                           << " step the rebuilt conclusion " << conclusion
    1480                 :         58 :                           << " into " << d_node << "\n";
    1481                 :            :     Node res = p->getManager()->getChecker()->checkDebug(
    1482                 :            :         ProofRule::MACRO_SR_PRED_TRANSFORM,
    1483                 :            :         {conclusion},
    1484                 :         58 :         {d_node},
    1485                 :          0 :         Node::null(),
    1486                 :        406 :         "eqproof-conv");
    1487                 :            :     // If rewriting was not able to flatten the rebuilt conclusion into the
    1488                 :            :     // original one, we give up and use a TRUST_FLATTENING_REWRITE step,
    1489                 :            :     // generating a proof for the original conclusion d_node such as
    1490                 :            :     //
    1491                 :            :     //     Converted EqProof
    1492                 :            :     //  ----------------------      ------------------- TRUST_FLATTENING_REWRITE
    1493                 :            :     //     conclusion               conclusion = d_node
    1494                 :            :     // ------------------------------------------------------- EQ_RESOLVE
    1495                 :            :     //                       d_node
    1496                 :            :     //
    1497                 :            :     //
    1498                 :            :     //  If rewriting was able to do it, however, we just add the macro step.
    1499         [ +  + ]:         58 :     if (res.isNull())
    1500                 :            :     {
    1501         [ +  - ]:         30 :       Trace("eqproof-conv")
    1502                 :         15 :           << "EqProof::addToProof: adding a trust flattening rewrite step\n";
    1503                 :         15 :       Node bridgeEq = conclusion.eqNode(d_node);
    1504                 :         15 :       p->addTrustedStep(bridgeEq, TrustId::FLATTENING_REWRITE, {}, {});
    1505 [ +  + ][ -  - ]:         45 :       p->addStep(d_node, ProofRule::EQ_RESOLVE, {conclusion, bridgeEq}, {});
    1506                 :            :     }
    1507                 :            :     else
    1508                 :            :     {
    1509                 :        129 :       p->addStep(d_node,
    1510                 :            :                  ProofRule::MACRO_SR_PRED_TRANSFORM,
    1511                 :            :                  {conclusion},
    1512                 :         43 :                  {d_node},
    1513                 :         86 :                  true);
    1514                 :            :     }
    1515                 :            :   }
    1516                 :     652914 :   visited[d_node] = d_node;
    1517                 :     652914 :   return d_node;
    1518                 :            : }
    1519                 :            : 
    1520                 :            : }  // namespace eq
    1521                 :            : }  // Namespace theory
    1522                 :            : }  // namespace cvc5::internal

Generated by: LCOV version 1.14