LCOV - code coverage report
Current view: top level - buildbot/coverage/build/src/theory/quantifiers - extended_rewrite.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1055 1135 93.0 %
Date: 2026-02-27 11:41:18 Functions: 23 23 100.0 %
Branches: 907 1207 75.1 %

           Branch data     Line data    Source code
       1                 :            : /******************************************************************************
       2                 :            :  * This file is part of the cvc5 project.
       3                 :            :  *
       4                 :            :  * Copyright (c) 2009-2026 by the authors listed in the file AUTHORS
       5                 :            :  * in the top-level source directory and their institutional affiliations.
       6                 :            :  * All rights reserved.  See the file COPYING in the top-level source
       7                 :            :  * directory for licensing information.
       8                 :            :  * ****************************************************************************
       9                 :            :  *
      10                 :            :  * Implementation of extended rewriting techniques.
      11                 :            :  */
      12                 :            : 
      13                 :            : #include "theory/quantifiers/extended_rewrite.h"
      14                 :            : 
      15                 :            : #include <sstream>
      16                 :            : 
      17                 :            : #include "theory/arith/arith_msum.h"
      18                 :            : #include "theory/bv/theory_bv_utils.h"
      19                 :            : #include "theory/datatypes/datatypes_rewriter.h"
      20                 :            : #include "theory/quantifiers/term_util.h"
      21                 :            : #include "theory/rewriter.h"
      22                 :            : #include "theory/strings/arith_entail.h"
      23                 :            : #include "theory/strings/sequences_rewriter.h"
      24                 :            : #include "theory/strings/word.h"
      25                 :            : #include "theory/strings/theory_strings_utils.h"
      26                 :            : #include "theory/theory.h"
      27                 :            : 
      28                 :            : using namespace cvc5::internal::kind;
      29                 :            : using namespace std;
      30                 :            : 
      31                 :            : namespace cvc5::internal {
      32                 :            : namespace theory {
      33                 :            : namespace quantifiers {
      34                 :            : 
      35                 :            : struct ExtRewriteAttributeId
      36                 :            : {
      37                 :            : };
      38                 :            : typedef expr::Attribute<ExtRewriteAttributeId, Node> ExtRewriteAttribute;
      39                 :            : 
      40                 :            : struct ExtRewriteAggAttributeId
      41                 :            : {
      42                 :            : };
      43                 :            : typedef expr::Attribute<ExtRewriteAggAttributeId, Node> ExtRewriteAggAttribute;
      44                 :            : 
      45                 :     570210 : ExtendedRewriter::ExtendedRewriter(NodeManager* nm, Rewriter& rew, bool aggr)
      46                 :     570210 :     : d_nm(nm), d_rew(rew), d_aggr(aggr)
      47                 :            : {
      48                 :     570210 :   d_true = d_nm->mkConst(true);
      49                 :     570210 :   d_false = d_nm->mkConst(false);
      50                 :     570210 :   d_intZero = d_nm->mkConstInt(Rational(0));
      51                 :     570210 : }
      52                 :            : 
      53                 :     568982 : void ExtendedRewriter::setCache(Node n, Node ret) const
      54                 :            : {
      55         [ +  + ]:     568982 :   if (d_aggr)
      56                 :            :   {
      57                 :            :     ExtRewriteAggAttribute erga;
      58                 :     562782 :     n.setAttribute(erga, ret);
      59                 :            :   }
      60                 :            :   else
      61                 :            :   {
      62                 :            :     ExtRewriteAttribute era;
      63                 :       6200 :     n.setAttribute(era, ret);
      64                 :            :   }
      65                 :     568982 : }
      66                 :            : 
      67                 :    1187489 : Node ExtendedRewriter::getCache(Node n) const
      68                 :            : {
      69         [ +  + ]:    1187489 :   if (d_aggr)
      70                 :            :   {
      71         [ +  + ]:    1173299 :     if (n.hasAttribute(ExtRewriteAggAttribute()))
      72                 :            :     {
      73                 :    1775450 :       return n.getAttribute(ExtRewriteAggAttribute());
      74                 :            :     }
      75                 :            :   }
      76                 :            :   else
      77                 :            :   {
      78         [ +  + ]:      14190 :     if (n.hasAttribute(ExtRewriteAttribute()))
      79                 :            :     {
      80                 :      22180 :       return n.getAttribute(ExtRewriteAttribute());
      81                 :            :     }
      82                 :            :   }
      83                 :     288674 :   return Node::null();
      84                 :            : }
      85                 :            : 
      86                 :     583985 : bool ExtendedRewriter::addToChildren(Node nc,
      87                 :            :                                      std::vector<Node>& children,
      88                 :            :                                      bool dropDup) const
      89                 :            : {
      90                 :            :   // If the operator is non-additive, do not consider duplicates
      91                 :     583985 :   if (dropDup
      92 [ +  + ][ +  + ]:     583985 :       && std::find(children.begin(), children.end(), nc) != children.end())
                 [ +  + ]
      93                 :            :   {
      94                 :       7262 :     return false;
      95                 :            :   }
      96                 :     576723 :   children.push_back(nc);
      97                 :     576723 :   return true;
      98                 :            : }
      99                 :            : 
     100                 :    1187489 : Node ExtendedRewriter::extendedRewrite(Node n) const
     101                 :            : {
     102         [ +  - ]:    1187489 :   Trace("q-ext-rewrite-debug") << "extendedRewrite: " << n << std::endl;
     103                 :    1187489 :   n = d_rew.rewrite(n);
     104                 :            : 
     105                 :            :   // has it already been computed?
     106                 :    1187489 :   Node ncache = getCache(n);
     107         [ +  + ]:    1187489 :   if (!ncache.isNull())
     108                 :            :   {
     109                 :     898815 :     return ncache;
     110                 :            :   }
     111                 :            : 
     112                 :     288674 :   Node ret = n;
     113                 :     288674 :   NodeManager* nm = d_nm;
     114                 :            : 
     115                 :            :   //--------------------pre-rewrite
     116         [ +  + ]:     288674 :   if (d_aggr)
     117                 :            :   {
     118                 :     285574 :     Node pre_new_ret;
     119         [ +  + ]:     285574 :     if (ret.getKind() == Kind::IMPLIES)
     120                 :            :     {
     121                 :        390 :       pre_new_ret = nm->mkNode(Kind::OR, ret[0].negate(), ret[1]);
     122                 :        390 :       debugExtendedRewrite(ret, pre_new_ret, "IMPLIES elim");
     123                 :            :     }
     124         [ +  + ]:     285184 :     else if (ret.getKind() == Kind::XOR)
     125                 :            :     {
     126                 :       1882 :       pre_new_ret = nm->mkNode(Kind::EQUAL, ret[0].negate(), ret[1]);
     127                 :       1882 :       debugExtendedRewrite(ret, pre_new_ret, "XOR elim");
     128                 :            :     }
     129         [ +  + ]:     283302 :     else if (ret.getKind() == Kind::NOT)
     130                 :            :     {
     131                 :      25439 :       pre_new_ret = extendedRewriteNnf(ret);
     132                 :      25439 :       debugExtendedRewrite(ret, pre_new_ret, "NNF");
     133                 :            :     }
     134         [ +  + ]:     285574 :     if (!pre_new_ret.isNull())
     135                 :            :     {
     136                 :       8366 :       ret = extendedRewrite(pre_new_ret);
     137                 :            : 
     138         [ +  - ]:      16732 :       Trace("q-ext-rewrite-debug")
     139                 :       8366 :           << "...ext-pre-rewrite : " << n << " -> " << pre_new_ret << std::endl;
     140                 :       8366 :       setCache(n, ret);
     141                 :       8366 :       return ret;
     142                 :            :     }
     143         [ +  + ]:     285574 :   }
     144                 :            :   //--------------------end pre-rewrite
     145                 :            : 
     146                 :            :   //--------------------rewrite children
     147         [ +  + ]:     280308 :   if (n.getNumChildren() > 0)
     148                 :            :   {
     149                 :     246946 :     std::vector<Node> children;
     150         [ +  + ]:     246946 :     if (n.getMetaKind() == metakind::PARAMETERIZED)
     151                 :            :     {
     152                 :       5260 :       children.push_back(n.getOperator());
     153                 :            :     }
     154                 :     246946 :     Kind k = n.getKind();
     155                 :     246946 :     bool childChanged = false;
     156                 :     246946 :     bool isNonAdditive = TermUtil::isNonAdditive(k);
     157                 :            :     // We flatten associative operators below, which requires k to be n-ary.
     158                 :     246946 :     bool isAssoc = TermUtil::isAssoc(k, true);
     159         [ +  + ]:     824986 :     for (unsigned i = 0; i < n.getNumChildren(); i++)
     160                 :            :     {
     161                 :     578040 :       Node nc = extendedRewrite(n[i]);
     162 [ +  + ][ +  + ]:     578040 :       childChanged = nc != n[i] || childChanged;
         [ +  - ][ -  - ]
     163 [ +  + ][ +  + ]:     578040 :       if (isAssoc && nc.getKind() == n.getKind())
                 [ +  + ]
     164                 :            :       {
     165         [ +  + ]:      12943 :         for (const Node& ncc : nc)
     166                 :            :         {
     167         [ +  + ]:       9444 :           if (!addToChildren(ncc, children, isNonAdditive))
     168                 :            :           {
     169                 :       2986 :             childChanged = true;
     170                 :            :           }
     171                 :       9444 :         }
     172                 :            :       }
     173         [ +  + ]:     574541 :       else if (!addToChildren(nc, children, isNonAdditive))
     174                 :            :       {
     175                 :       4276 :         childChanged = true;
     176                 :            :       }
     177                 :     578040 :     }
     178 [ -  + ][ -  + ]:     246946 :     Assert(!children.empty());
                 [ -  - ]
     179                 :            :     // Some commutative operators have rewriters that are agnostic to order,
     180                 :            :     // thus, we sort here.
     181 [ +  + ][ +  + ]:     246946 :     if (TermUtil::isComm(k) && (d_aggr || children.size() <= 5))
         [ +  + ][ +  + ]
     182                 :            :     {
     183                 :     145922 :       childChanged = true;
     184                 :     145922 :       std::sort(children.begin(), children.end());
     185                 :            :     }
     186         [ +  + ]:     246946 :     if (childChanged)
     187                 :            :     {
     188 [ +  + ][ +  + ]:     157996 :       if (isNonAdditive && children.size() == 1)
                 [ +  + ]
     189                 :            :       {
     190                 :            :         // we may have subsumed children down to one
     191                 :         70 :         ret = children[0];
     192                 :            :       }
     193                 :     157926 :       else if (isAssoc
     194 [ +  + ][ +  + ]:     157926 :                && children.size() > kind::metakind::getMaxArityForKind(k))
                 [ +  + ]
     195                 :            :       {
     196 [ -  + ][ -  + ]:          2 :         Assert(kind::metakind::getMaxArityForKind(k) >= 2);
                 [ -  - ]
     197                 :            :         // kind may require binary construction
     198                 :          2 :         ret = children[0];
     199         [ +  + ]:          6 :         for (unsigned i = 1, nchild = children.size(); i < nchild; i++)
     200                 :            :         {
     201                 :          4 :           ret = nm->mkNode(k, ret, children[i]);
     202                 :            :         }
     203                 :            :       }
     204                 :            :       else
     205                 :            :       {
     206                 :     157924 :         ret = nm->mkNode(k, children);
     207                 :            :       }
     208                 :            :     }
     209                 :     246946 :   }
     210                 :     280308 :   ret = d_rew.rewrite(ret);
     211                 :            :   //--------------------end rewrite children
     212                 :            : 
     213                 :            :   // now, do extended rewrite
     214         [ +  - ]:     560616 :   Trace("q-ext-rewrite-debug") << "Do extended rewrite on : " << ret
     215                 :     280308 :                                << " (from " << n << ")" << std::endl;
     216                 :     280308 :   Node new_ret;
     217                 :            : 
     218                 :            :   //---------------------- theory-independent post-rewriting
     219         [ +  + ]:     280308 :   if (ret.getKind() == Kind::ITE)
     220                 :            :   {
     221                 :      21807 :     new_ret = extendedRewriteIte(Kind::ITE, ret);
     222                 :            :   }
     223 [ +  + ][ +  + ]:     258501 :   else if (ret.getKind() == Kind::AND || ret.getKind() == Kind::OR)
                 [ +  + ]
     224                 :            :   {
     225                 :      73928 :     new_ret = extendedRewriteAndOr(ret);
     226                 :            :   }
     227         [ +  + ]:     184573 :   else if (ret.getKind() == Kind::EQUAL)
     228                 :            :   {
     229                 :      57430 :     new_ret = extendedRewriteEqChain(
     230                 :      28715 :         Kind::EQUAL, Kind::AND, Kind::OR, Kind::NOT, ret);
     231         [ +  + ]:      28715 :     if (!new_ret.isNull())
     232                 :            :     {
     233                 :       2043 :       debugExtendedRewrite(ret, new_ret, "Bool eq-chain simplify");
     234                 :            :     }
     235                 :            :     else
     236                 :            :     {
     237                 :      26672 :       TypeNode tret = ret[0].getType();
     238         [ +  + ]:      26672 :       if (tret.isInteger())
     239                 :            :       {
     240                 :      13853 :         strings::ArithEntail ae(nm, &d_rew);
     241                 :      13853 :         new_ret = ae.rewritePredViaEntailment(ret);
     242         [ +  + ]:      13853 :         if (!new_ret.isNull())
     243                 :            :         {
     244                 :         60 :           debugExtendedRewrite(ret, new_ret, "String EQUAL len entailment");
     245                 :            :         }
     246                 :      13853 :       }
     247         [ +  + ]:      12819 :       else if (tret.isStringLike())
     248                 :            :       {
     249                 :       2021 :         new_ret = extendedRewriteStrings(ret);
     250                 :            :       }
     251                 :      26672 :     }
     252                 :            :   }
     253         [ +  + ]:     155858 :   else if (ret.getKind() == Kind::GEQ)
     254                 :            :   {
     255         [ +  + ]:      16729 :     if (ret[0].getType().isInteger())
     256                 :            :     {
     257                 :      16530 :       strings::ArithEntail ae(nm, &d_rew);
     258                 :      16530 :       new_ret = ae.rewritePredViaEntailment(ret);
     259         [ +  + ]:      16530 :       if (!new_ret.isNull())
     260                 :            :       {
     261                 :         38 :         debugExtendedRewrite(ret, new_ret, "String GEQ len entailment");
     262                 :            :       }
     263                 :      16530 :     }
     264                 :            :   }
     265 [ +  + ][ +  - ]:     280308 :   Assert(new_ret.isNull() || new_ret != ret);
         [ -  + ][ -  + ]
                 [ -  - ]
     266 [ +  + ][ +  + ]:     280308 :   if (new_ret.isNull() && ret.getKind() != Kind::ITE)
                 [ +  + ]
     267                 :            :   {
     268                 :            :     // simple ITE pulling
     269                 :     242250 :     new_ret = extendedRewritePullIte(Kind::ITE, ret);
     270                 :            :   }
     271                 :            :   //----------------------end theory-independent post-rewriting
     272                 :            : 
     273                 :            :   //----------------------theory-specific post-rewriting
     274         [ +  + ]:     280308 :   if (new_ret.isNull())
     275                 :            :   {
     276                 :            :     TheoryId tid;
     277         [ +  + ]:     249707 :     if (ret.getKind() == Kind::ITE)
     278                 :            :     {
     279                 :      18707 :       tid = Theory::theoryOf(ret.getType());
     280                 :            :     }
     281                 :            :     else
     282                 :            :     {
     283                 :     231000 :       tid = Theory::theoryOf(ret);
     284                 :            :     }
     285         [ +  - ]:     499414 :     Trace("q-ext-rewrite-debug") << "theoryOf( " << ret << " )= " << tid
     286                 :     249707 :                                  << std::endl;
     287    [ +  + ][ + ]:     249707 :     switch (tid)
     288                 :            :     {
     289                 :      16561 :       case THEORY_STRINGS: new_ret = extendedRewriteStrings(ret); break;
     290                 :        330 :       case THEORY_SETS: new_ret = extendedRewriteSets(ret); break;
     291                 :     232816 :       default: break;
     292                 :            :     }
     293                 :            :   }
     294                 :            :   //----------------------end theory-specific post-rewriting
     295                 :            : 
     296                 :            :   //----------------------aggressive rewrites
     297 [ +  + ][ +  + ]:     280308 :   if (new_ret.isNull() && d_aggr)
                 [ +  + ]
     298                 :            :   {
     299                 :     246857 :     new_ret = extendedRewriteAggr(ret);
     300                 :            :   }
     301                 :            :   //----------------------end aggressive rewrites
     302                 :            : 
     303                 :     280308 :   setCache(n, ret);
     304         [ +  + ]:     280308 :   if (!new_ret.isNull())
     305                 :            :   {
     306                 :      30721 :     ret = extendedRewrite(new_ret);
     307                 :            :   }
     308         [ +  - ]:     560616 :   Trace("q-ext-rewrite-debug") << "...ext-rewrite : " << n << " -> " << ret
     309                 :     280308 :                                << std::endl;
     310         [ -  + ]:     280308 :   if (TraceIsOn("q-ext-rewrite-nf"))
     311                 :            :   {
     312         [ -  - ]:          0 :     if (n == ret)
     313                 :            :     {
     314         [ -  - ]:          0 :       Trace("q-ext-rewrite-nf") << "ext-rew normal form : " << n << std::endl;
     315                 :            :     }
     316                 :            :   }
     317                 :     280308 :   setCache(n, ret);
     318                 :     280308 :   return ret;
     319                 :    1187489 : }
     320                 :            : 
     321                 :     246857 : Node ExtendedRewriter::extendedRewriteAggr(Node n) const
     322                 :            : {
     323                 :     246857 :   Node new_ret;
     324         [ +  - ]:     493714 :   Trace("q-ext-rewrite-debug2")
     325                 :     246857 :       << "Do aggressive rewrites on " << n << std::endl;
     326                 :     246857 :   bool polarity = n.getKind() != Kind::NOT;
     327         [ +  + ]:     246857 :   Node ret_atom = n.getKind() == Kind::NOT ? n[0] : n;
     328                 :     272940 :   if ((ret_atom.getKind() == Kind::EQUAL && ret_atom[0].getType().isRealOrInt())
     329 [ +  + ][ +  + ]:     272940 :       || ret_atom.getKind() == Kind::GEQ)
                 [ +  + ]
     330                 :            :   {
     331                 :            :     // ITE term removal in polynomials
     332                 :            :     // e.g. ite( x=0, x, y ) = x+1 ---> ( x=0 ^ y = x+1 )
     333         [ +  - ]:      70726 :     Trace("q-ext-rewrite-debug2")
     334                 :      35363 :         << "Compute monomial sum " << ret_atom << std::endl;
     335                 :            :     // compute monomial sum
     336                 :      35363 :     std::map<Node, Node> msum;
     337         [ +  - ]:      35363 :     if (ArithMSum::getMonomialSumLit(ret_atom, msum))
     338                 :            :     {
     339         [ +  + ]:     108653 :       for (std::map<Node, Node>::iterator itm = msum.begin(); itm != msum.end();
     340                 :      73290 :            ++itm)
     341                 :            :       {
     342                 :      73354 :         Node v = itm->first;
     343         [ +  - ]:     146708 :         Trace("q-ext-rewrite-debug2")
     344                 :      73354 :             << itm->first << " * " << itm->second << std::endl;
     345         [ +  + ]:      73354 :         if (v.getKind() == Kind::ITE)
     346                 :            :         {
     347                 :       1370 :           Node veq;
     348                 :       1370 :           int res = ArithMSum::isolate(v, msum, veq, ret_atom.getKind());
     349         [ +  - ]:       1370 :           if (res != 0)
     350                 :            :           {
     351         [ +  - ]:       2740 :             Trace("q-ext-rewrite-debug")
     352                 :       1370 :                 << "  have ITE relation, solved form : " << veq << std::endl;
     353                 :            :             // try pulling ITE
     354                 :       1370 :             new_ret = extendedRewritePullIte(Kind::ITE, veq);
     355         [ +  + ]:       1370 :             if (!new_ret.isNull())
     356                 :            :             {
     357         [ -  + ]:         64 :               if (!polarity)
     358                 :            :               {
     359                 :          0 :                 new_ret = new_ret.negate();
     360                 :            :               }
     361                 :         64 :               break;
     362                 :            :             }
     363                 :            :           }
     364                 :            :           else
     365                 :            :           {
     366         [ -  - ]:          0 :             Trace("q-ext-rewrite-debug")
     367                 :          0 :                 << "  failed to isolate " << v << " in " << n << std::endl;
     368                 :            :           }
     369         [ +  + ]:       1370 :         }
     370         [ +  + ]:      73354 :       }
     371                 :            :     }
     372                 :            :     else
     373                 :            :     {
     374         [ -  - ]:          0 :       Trace("q-ext-rewrite-debug")
     375                 :          0 :           << "  failed to get monomial sum of " << n << std::endl;
     376                 :            :     }
     377                 :      35363 :   }
     378                 :            :   // TODO (#1706) : conditional rewriting, condition merging
     379                 :     493714 :   return new_ret;
     380                 :     246857 : }
     381                 :            : 
     382                 :      29949 : Node ExtendedRewriter::extendedRewriteIte(Kind itek, Node n, bool full) const
     383                 :            : {
     384 [ -  + ][ -  + ]:      29949 :   Assert(n.getKind() == itek);
                 [ -  - ]
     385 [ -  + ][ -  + ]:      29949 :   Assert(n[1] != n[2]);
                 [ -  - ]
     386                 :            : 
     387                 :      29949 :   NodeManager* nm = d_nm;
     388                 :            : 
     389         [ +  - ]:      29949 :   Trace("ext-rew-ite") << "Rewrite ITE : " << n << std::endl;
     390                 :            : 
     391                 :      29949 :   Node flip_cond;
     392         [ -  + ]:      29949 :   if (n[0].getKind() == Kind::NOT)
     393                 :            :   {
     394                 :          0 :     flip_cond = n[0][0];
     395                 :            :   }
     396         [ +  + ]:      29949 :   else if (n[0].getKind() == Kind::OR)
     397                 :            :   {
     398                 :            :     // a | b ---> ~( ~a & ~b )
     399                 :        332 :     flip_cond = TermUtil::simpleNegate(n[0]);
     400                 :            :   }
     401         [ +  + ]:      29949 :   if (!flip_cond.isNull())
     402                 :            :   {
     403                 :        664 :     Node new_ret = nm->mkNode(Kind::ITE, flip_cond, n[2], n[1]);
     404                 :            :     // only print debug trace if full=true
     405         [ +  - ]:        332 :     if (full)
     406                 :            :     {
     407                 :        332 :       debugExtendedRewrite(n, new_ret, "ITE flip");
     408                 :            :     }
     409                 :        332 :     return new_ret;
     410                 :        332 :   }
     411                 :            :   // Boolean true/false return
     412                 :      29617 :   TypeNode tn = n.getType();
     413         [ +  + ]:      29617 :   if (tn.isBoolean())
     414                 :            :   {
     415         [ +  + ]:      37638 :     for (unsigned i = 1; i <= 2; i++)
     416                 :            :     {
     417         [ -  + ]:      25092 :       if (n[i].isConst())
     418                 :            :       {
     419                 :          0 :         Node cond = i == 1 ? n[0] : n[0].negate();
     420         [ -  - ]:          0 :         Node other = n[i == 1 ? 2 : 1];
     421                 :          0 :         Kind retk = Kind::AND;
     422         [ -  - ]:          0 :         if (n[i].getConst<bool>())
     423                 :            :         {
     424                 :          0 :           retk = Kind::OR;
     425                 :            :         }
     426                 :            :         else
     427                 :            :         {
     428                 :          0 :           cond = cond.negate();
     429                 :            :         }
     430                 :          0 :         Node new_ret = nm->mkNode(retk, cond, other);
     431         [ -  - ]:          0 :         if (full)
     432                 :            :         {
     433                 :            :           // ite( A, true, B ) ---> A V B
     434                 :            :           // ite( A, false, B ) ---> ~A /\ B
     435                 :            :           // ite( A, B,  true ) ---> ~A V B
     436                 :            :           // ite( A, B, false ) ---> A /\ B
     437                 :          0 :           debugExtendedRewrite(n, new_ret, "ITE const return");
     438                 :            :         }
     439                 :          0 :         return new_ret;
     440                 :          0 :       }
     441                 :            :     }
     442                 :            :   }
     443                 :            : 
     444                 :            :   // get entailed equalities in the condition
     445                 :      29617 :   std::vector<Node> eq_conds;
     446                 :      29617 :   Kind ck = n[0].getKind();
     447         [ +  + ]:      29617 :   if (ck == Kind::EQUAL)
     448                 :            :   {
     449                 :      10999 :     eq_conds.push_back(n[0]);
     450                 :            :   }
     451         [ +  + ]:      18618 :   else if (ck == Kind::AND)
     452                 :            :   {
     453         [ +  + ]:      24710 :     for (const Node& cn : n[0])
     454                 :            :     {
     455         [ +  + ]:      19602 :       if (cn.getKind() == Kind::EQUAL)
     456                 :            :       {
     457                 :       2160 :         eq_conds.push_back(cn);
     458                 :            :       }
     459                 :      24710 :     }
     460                 :            :   }
     461                 :            : 
     462                 :      29617 :   Node new_ret;
     463                 :      29617 :   Node b;
     464                 :      29617 :   Node e;
     465                 :      29617 :   Node t1 = n[1];
     466                 :      29617 :   Node t2 = n[2];
     467                 :      29617 :   std::stringstream ss_reason;
     468                 :            : 
     469         [ +  + ]:      42690 :   for (const Node& eq : eq_conds)
     470                 :            :   {
     471                 :            :     // simple invariant ITE
     472         [ +  + ]:      39350 :     for (unsigned i = 0; i <= 1; i++)
     473                 :            :     {
     474                 :            :       // ite( x = y ^ C, y, x ) ---> x
     475                 :            :       // this is subsumed by the rewrites below
     476                 :      26277 :       if (t2 == eq[i] && t1 == eq[1 - i])
     477                 :            :       {
     478                 :         86 :         new_ret = t2;
     479                 :         86 :         ss_reason << "ITE simple rev subs";
     480                 :         86 :         break;
     481                 :            :       }
     482                 :            :     }
     483         [ +  + ]:      13159 :     if (!new_ret.isNull())
     484                 :            :     {
     485                 :         86 :       break;
     486                 :            :     }
     487                 :            :   }
     488         [ +  + ]:      29617 :   if (new_ret.isNull())
     489                 :            :   {
     490                 :            :     // merging branches
     491         [ +  + ]:      87479 :     for (unsigned i = 1; i <= 2; i++)
     492                 :            :     {
     493         [ +  + ]:      58640 :       if (n[i].getKind() == Kind::ITE)
     494                 :            :       {
     495                 :       8684 :         Node no = n[3 - i];
     496         [ +  + ]:      25098 :         for (unsigned j = 1; j <= 2; j++)
     497                 :            :         {
     498         [ +  + ]:      17106 :           if (n[i][j] == no)
     499                 :            :           {
     500                 :            :             // e.g.
     501                 :            :             // ite( C1, ite( C2, t1, t2 ), t1 ) ----> ite( C1 ^ ~C2, t2, t1 )
     502 [ +  + ][ +  + ]:        692 :             Node nc1 = i == 2 ? n[0].negate() : n[0];
                 [ -  - ]
     503                 :       1384 :             Node nc2 = j == 1 ? n[i][0].negate() : n[i][0];
     504                 :       1384 :             Node new_cond = nm->mkNode(Kind::AND, nc1, nc2);
     505                 :        692 :             new_ret = nm->mkNode(Kind::ITE, new_cond, n[i][3 - j], no);
     506                 :        692 :             ss_reason << "ITE merge branch";
     507                 :        692 :             break;
     508                 :        692 :           }
     509                 :            :         }
     510                 :       8684 :       }
     511         [ +  + ]:      58640 :       if (!new_ret.isNull())
     512                 :            :       {
     513                 :        692 :         break;
     514                 :            :       }
     515                 :            :     }
     516                 :            :   }
     517                 :            : 
     518 [ +  + ][ +  + ]:      29617 :   if (new_ret.isNull() && d_aggr)
                 [ +  + ]
     519                 :            :   {
     520                 :            :     // If x is less than t based on an ordering, then we use { x -> t } as a
     521                 :            :     // substitution to the children of ite( x = t ^ C, s, t ) below.
     522                 :      28833 :     Subs subs;
     523                 :      28833 :     inferSubstitution(n[0], subs, true);
     524                 :            : 
     525         [ +  - ]:      28833 :     if (!subs.empty())
     526                 :            :     {
     527                 :            :       // reverse substitution to opposite child
     528                 :            :       // r{ x -> t } = s  implies  ite( x=t ^ C, s, r ) ---> r
     529                 :            :       // We can use ordinary substitute since the result of the substitution
     530                 :            :       // is not being returned. In other words, nn is only being used to query
     531                 :            :       // whether the second branch is a generalization of the first.
     532                 :      28833 :       Node nn = subs.apply(t2);
     533         [ +  + ]:      28833 :       if (nn != t2)
     534                 :            :       {
     535                 :       9315 :         nn = d_rew.rewrite(nn);
     536         [ +  + ]:       9315 :         if (nn == t1)
     537                 :            :         {
     538                 :        110 :           new_ret = t2;
     539                 :        110 :           ss_reason << "ITE rev subs";
     540                 :            :         }
     541                 :            :       }
     542                 :            : 
     543                 :            :       // ite( x=t ^ C, s, r ) ---> ite( x=t ^ C, s{ x -> t }, r )
     544                 :            :       // must use partial substitute here, to avoid substitution into witness
     545                 :      28833 :       std::map<Kind, bool> rkinds;
     546                 :      28833 :       nn = partialSubstitute(t1, subs, rkinds);
     547                 :      28833 :       nn = d_rew.rewrite(nn);
     548         [ +  + ]:      28833 :       if (nn != t1)
     549                 :            :       {
     550                 :            :         // If full=false, then we've duplicated a term u in the children of n.
     551                 :            :         // For example, when ITE pulling, we have n is of the form:
     552                 :            :         //   ite( C, f( u, t1 ), f( u, t2 ) )
     553                 :            :         // We must show that at least one copy of u dissappears in this case.
     554         [ +  + ]:       5496 :         if (nn == t2)
     555                 :            :         {
     556                 :        152 :           new_ret = nn;
     557                 :        152 :           ss_reason << "ITE subs invariant";
     558                 :            :         }
     559 [ +  + ][ +  + ]:       5344 :         else if (full || nn.isConst())
                 [ +  + ]
     560                 :            :         {
     561                 :       1360 :           new_ret = nm->mkNode(itek, n[0], nn, t2);
     562                 :       1360 :           ss_reason << "ITE subs";
     563                 :            :         }
     564                 :            :       }
     565                 :      28833 :     }
     566         [ +  + ]:      28833 :     if (new_ret.isNull())
     567                 :            :     {
     568                 :            :       // ite( C, t, s ) ----> ite( C, t, s { C -> false } )
     569                 :            :       // use partial substitute to avoid substitution into witness
     570                 :      27211 :       std::map<Node, Node> assign;
     571                 :      27211 :       assign[n[0]] = d_false;
     572                 :      27211 :       std::map<Kind, bool> rkinds;
     573                 :      27211 :       Node nn = partialSubstitute(t2, assign, rkinds);
     574         [ +  + ]:      27211 :       if (nn != t2)
     575                 :            :       {
     576                 :       3592 :         nn = d_rew.rewrite(nn);
     577         [ +  + ]:       3592 :         if (nn == t1)
     578                 :            :         {
     579                 :         68 :           new_ret = nn;
     580                 :         68 :           ss_reason << "ITE subs invariant false";
     581                 :            :         }
     582 [ +  + ][ -  + ]:       3524 :         else if (full || nn.isConst())
                 [ +  + ]
     583                 :            :         {
     584                 :        438 :           new_ret = nm->mkNode(itek, n[0], t1, nn);
     585                 :        438 :           ss_reason << "ITE subs false";
     586                 :            :         }
     587                 :            :       }
     588                 :      27211 :     }
     589                 :      28833 :   }
     590                 :            : 
     591                 :            :   // only print debug trace if full=true
     592 [ +  + ][ +  + ]:      29617 :   if (!new_ret.isNull() && full)
                 [ +  + ]
     593                 :            :   {
     594                 :       2768 :     debugExtendedRewrite(n, new_ret, ss_reason.str().c_str());
     595                 :            :   }
     596                 :            : 
     597                 :      29617 :   return new_ret;
     598                 :      29949 : }
     599                 :            : 
     600                 :      73928 : Node ExtendedRewriter::extendedRewriteAndOr(Node n) const
     601                 :            : {
     602                 :            :   // all the below rewrites are aggressive
     603         [ +  + ]:      73928 :   if (!d_aggr)
     604                 :            :   {
     605                 :         66 :     return Node::null();
     606                 :            :   }
     607                 :      73862 :   Node new_ret;
     608                 :            :   // we allow substitutions to recurse over any kind, except WITNESS which is
     609                 :            :   // managed by partialSubstitute.
     610                 :      73862 :   std::map<Kind, bool> bcp_kinds;
     611                 :      73862 :   new_ret = extendedRewriteBcp(Kind::AND, Kind::OR, Kind::NOT, bcp_kinds, n);
     612         [ +  + ]:      73862 :   if (!new_ret.isNull())
     613                 :            :   {
     614                 :       3032 :     debugExtendedRewrite(n, new_ret, "Bool bcp");
     615                 :       3032 :     return new_ret;
     616                 :            :   }
     617                 :            :   // factoring
     618                 :      70830 :   new_ret = extendedRewriteFactoring(Kind::AND, Kind::OR, n);
     619         [ +  + ]:      70830 :   if (!new_ret.isNull())
     620                 :            :   {
     621                 :        959 :     debugExtendedRewrite(n, new_ret, "Bool factoring");
     622                 :        959 :     return new_ret;
     623                 :            :   }
     624                 :            : 
     625                 :            :   // equality resolution
     626                 :     139742 :   new_ret = extendedRewriteEqRes(
     627                 :      69871 :       Kind::AND, Kind::OR, Kind::EQUAL, Kind::NOT, bcp_kinds, n, false);
     628                 :      69871 :   debugExtendedRewrite(n, new_ret, "Bool eq res");
     629                 :      69871 :   return new_ret;
     630                 :      73862 : }
     631                 :            : 
     632                 :     243620 : Node ExtendedRewriter::extendedRewritePullIte(Kind itek, Node n) const
     633                 :            : {
     634 [ -  + ][ -  + ]:     243620 :   Assert(n.getKind() != Kind::ITE);
                 [ -  - ]
     635         [ +  + ]:     243620 :   if (n.isClosure())
     636                 :            :   {
     637                 :            :     // don't pull ITE out of quantifiers
     638                 :       2185 :     return n;
     639                 :            :   }
     640                 :     241435 :   NodeManager* nm = d_nm;
     641                 :     241435 :   TypeNode tn = n.getType();
     642                 :     241435 :   std::vector<Node> children;
     643                 :     241435 :   bool hasOp = (n.getMetaKind() == metakind::PARAMETERIZED);
     644         [ +  + ]:     241435 :   if (hasOp)
     645                 :            :   {
     646                 :       5403 :     children.push_back(n.getOperator());
     647                 :            :   }
     648                 :     241435 :   unsigned nchildren = n.getNumChildren();
     649         [ +  + ]:     704212 :   for (unsigned i = 0; i < nchildren; i++)
     650                 :            :   {
     651                 :     462777 :     children.push_back(n[i]);
     652                 :            :   }
     653                 :     241435 :   std::map<unsigned, std::map<unsigned, Node> > ite_c;
     654         [ +  + ]:     689368 :   for (unsigned i = 0; i < nchildren; i++)
     655                 :            :   {
     656                 :            :     // these rewrites in this loop are currently classified as not aggressive,
     657                 :            :     // although in previous versions they were classified as aggressive. These
     658                 :            :     // are shown to help in some Kind2 problems.
     659         [ +  + ]:     456924 :     if (n[i].getKind() == itek)
     660                 :            :     {
     661         [ +  + ]:      17163 :       unsigned ii = hasOp ? i + 1 : i;
     662         [ +  + ]:      51489 :       for (unsigned j = 0; j < 2; j++)
     663                 :            :       {
     664                 :      34326 :         children[ii] = n[i][j + 1];
     665                 :      34326 :         Node pull = nm->mkNode(n.getKind(), children);
     666                 :      34326 :         Node pullr = d_rew.rewrite(pull);
     667                 :      34326 :         children[ii] = n[i];
     668                 :      34326 :         ite_c[i][j] = pullr;
     669                 :      34326 :       }
     670         [ +  + ]:      17163 :       if (ite_c[i][0] == ite_c[i][1])
     671                 :            :       {
     672                 :            :         // ITE dual invariance
     673                 :            :         // f( t1..s1..tn ) ---> t  and  f( t1..s2..tn ) ---> t implies
     674                 :            :         // f( t1..ite( A, s1, s2 )..tn ) ---> t
     675                 :       1043 :         debugExtendedRewrite(n, ite_c[i][0], "ITE dual invariant");
     676                 :       2086 :         return ite_c[i][0];
     677                 :            :       }
     678                 :      27446 :       if (nchildren == 2 && (n[1 - i].isVar() || n[1 - i].isConst())
     679                 :      27446 :           && !n[1 - i].getType().isBoolean() && tn.isBoolean())
     680                 :            :       {
     681                 :            :         // always pull variable or constant with binary (theory) predicate
     682                 :            :         // e.g. P( x, ite( A, t1, t2 ) ) ---> ite( A, P( x, t1 ), P( x, t2 ) )
     683                 :      14420 :         Node new_ret = nm->mkNode(Kind::ITE, n[i][0], ite_c[i][0], ite_c[i][1]);
     684                 :       7210 :         debugExtendedRewrite(n, new_ret, "ITE pull var predicate");
     685                 :       7210 :         return new_ret;
     686                 :       7210 :       }
     687         [ +  + ]:      25560 :       for (unsigned j = 0; j < 2; j++)
     688                 :            :       {
     689                 :      17388 :         Node pullr = ite_c[i][j];
     690                 :      17388 :         if (pullr.isConst() || pullr == n[i][j + 1])
     691                 :            :         {
     692                 :            :           // ITE single child elimination
     693                 :            :           // f( t1..s1..tn ) ---> t  where t is a constant or s1 itself
     694                 :            :           // implies
     695                 :            :           // f( t1..ite( A, s1, s2 )..tn ) ---> ite( A, t, f( t1..s2..tn ) )
     696                 :        738 :           Node new_ret;
     697 [ +  + ][ +  - ]:        738 :           if (tn.isBoolean() && pullr.isConst())
                 [ +  + ]
     698                 :            :           {
     699                 :            :             // remove false/true child immediately
     700                 :        100 :             bool pol = pullr.getConst<bool>();
     701                 :        100 :             std::vector<Node> new_children;
     702                 :        100 :             new_children.push_back((j == 0) == pol ? n[i][0]
     703                 :            :                                                     : n[i][0].negate());
     704                 :        100 :             new_children.push_back(ite_c[i][1 - j]);
     705         [ +  + ]:        100 :             new_ret = nm->mkNode(pol ? Kind::OR : Kind::AND, new_children);
     706                 :        100 :             debugExtendedRewrite(n, new_ret, "ITE Bool single elim");
     707                 :        100 :           }
     708                 :            :           else
     709                 :            :           {
     710                 :        638 :             new_ret = nm->mkNode(itek, n[i][0], ite_c[i][0], ite_c[i][1]);
     711                 :        638 :             debugExtendedRewrite(n, new_ret, "ITE single elim");
     712                 :            :           }
     713                 :        738 :           return new_ret;
     714                 :        738 :         }
     715         [ +  + ]:      17388 :       }
     716                 :            :     }
     717                 :            :   }
     718         [ +  + ]:     232444 :   if (d_aggr)
     719                 :            :   {
     720         [ +  + ]:     237648 :     for (std::pair<const unsigned, std::map<unsigned, Node> >& ip : ite_c)
     721                 :            :     {
     722                 :       8142 :       Node nite = n[ip.first];
     723 [ -  + ][ -  + ]:       8142 :       Assert(nite.getKind() == itek);
                 [ -  - ]
     724                 :            :       // now, simply pull the ITE and try ITE rewrites
     725                 :      16284 :       Node pull_ite = nm->mkNode(itek, nite[0], ip.second[0], ip.second[1]);
     726                 :       8142 :       pull_ite = d_rew.rewrite(pull_ite);
     727         [ +  - ]:       8142 :       if (pull_ite.getKind() == Kind::ITE)
     728                 :            :       {
     729                 :       8142 :         Node new_pull_ite = extendedRewriteIte(itek, pull_ite, false);
     730         [ +  + ]:       8142 :         if (!new_pull_ite.isNull())
     731                 :            :         {
     732                 :        138 :           debugExtendedRewrite(n, new_pull_ite, "ITE pull rewrite");
     733                 :        138 :           return new_pull_ite;
     734                 :            :         }
     735         [ +  + ]:       8142 :       }
     736                 :            :       else
     737                 :            :       {
     738                 :            :         // A general rewrite could eliminate the ITE by pulling.
     739                 :            :         // An example is:
     740                 :            :         //   ~( ite( C, ~x, ~ite( C, y, x ) ) ) --->
     741                 :            :         //   ite( C, ~~x, ite( C, y, x ) ) --->
     742                 :            :         //   x
     743                 :            :         // where ~ is bitvector negation.
     744                 :          0 :         debugExtendedRewrite(n, pull_ite, "ITE pull basic elim");
     745                 :          0 :         return pull_ite;
     746                 :            :       }
     747 [ +  + ][ +  + ]:       8280 :     }
     748                 :            :   }
     749                 :            : 
     750                 :     232306 :   return Node::null();
     751                 :     241435 : }
     752                 :            : 
     753                 :      25439 : Node ExtendedRewriter::extendedRewriteNnf(Node ret) const
     754                 :            : {
     755 [ -  + ][ -  + ]:      25439 :   Assert(ret.getKind() == Kind::NOT);
                 [ -  - ]
     756                 :            : 
     757                 :      25439 :   Kind nk = ret[0].getKind();
     758                 :      25439 :   bool neg_ch = false;
     759                 :      25439 :   bool neg_ch_1 = false;
     760 [ +  + ][ +  + ]:      25439 :   if (nk == Kind::AND || nk == Kind::OR)
     761                 :            :   {
     762                 :       4590 :     neg_ch = true;
     763         [ +  + ]:       4590 :     nk = nk == Kind::AND ? Kind::OR : Kind::AND;
     764                 :            :   }
     765         [ +  + ]:      20849 :   else if (nk == Kind::IMPLIES)
     766                 :            :   {
     767                 :         20 :     neg_ch = true;
     768                 :         20 :     neg_ch_1 = true;
     769                 :         20 :     nk = Kind::AND;
     770                 :            :   }
     771         [ +  + ]:      20829 :   else if (nk == Kind::ITE)
     772                 :            :   {
     773                 :       1031 :     neg_ch = true;
     774                 :       1031 :     neg_ch_1 = true;
     775                 :            :   }
     776         [ +  + ]:      19798 :   else if (nk == Kind::XOR)
     777                 :            :   {
     778                 :         60 :     nk = Kind::EQUAL;
     779                 :            :   }
     780                 :      19738 :   else if (nk == Kind::EQUAL && ret[0][0].getType().isBoolean())
     781                 :            :   {
     782                 :        393 :     neg_ch_1 = true;
     783                 :            :   }
     784                 :            :   else
     785                 :            :   {
     786                 :      19345 :     return Node::null();
     787                 :            :   }
     788                 :            : 
     789                 :       6094 :   std::vector<Node> new_children;
     790         [ +  + ]:      26076 :   for (unsigned i = 0, nchild = ret[0].getNumChildren(); i < nchild; i++)
     791                 :            :   {
     792                 :      19982 :     Node c = ret[0][i];
     793 [ +  + ][ +  + ]:      19982 :     c = (i == 0 ? neg_ch_1 : false) != neg_ch ? c.negate() : c;
                 [ +  + ]
     794                 :      19982 :     new_children.push_back(c);
     795                 :      19982 :   }
     796                 :       6094 :   return d_nm->mkNode(nk, new_children);
     797                 :       6094 : }
     798                 :            : 
     799                 :      73862 : Node ExtendedRewriter::extendedRewriteBcp(Kind andk,
     800                 :            :                                           Kind ork,
     801                 :            :                                           Kind notk,
     802                 :            :                                           std::map<Kind, bool>& bcp_kinds,
     803                 :            :                                           Node ret) const
     804                 :            : {
     805                 :      73862 :   Kind k = ret.getKind();
     806 [ +  + ][ +  - ]:      73862 :   Assert(k == andk || k == ork);
         [ -  + ][ -  + ]
                 [ -  - ]
     807         [ +  - ]:      73862 :   Trace("ext-rew-bcp") << "BCP: **** INPUT: " << ret << std::endl;
     808                 :            : 
     809                 :      73862 :   NodeManager* nm = d_nm;
     810                 :            : 
     811                 :      73862 :   TypeNode tn = ret.getType();
     812                 :      73862 :   Node truen = TermUtil::mkTypeMaxValue(tn);
     813                 :      73862 :   Node falsen = TermUtil::mkTypeValue(tn, 0);
     814                 :            : 
     815                 :            :   // terms to process
     816                 :      73862 :   std::vector<Node> to_process;
     817         [ +  + ]:     269519 :   for (const Node& cn : ret)
     818                 :            :   {
     819                 :     195657 :     to_process.push_back(cn);
     820                 :     195657 :   }
     821                 :            :   // the processing terms
     822                 :      73862 :   std::vector<Node> clauses;
     823                 :            :   // the terms we have propagated information to
     824                 :      73862 :   std::unordered_set<Node> prop_clauses;
     825                 :            :   // the assignment
     826                 :      73862 :   std::map<Node, Node> assign;
     827                 :      73862 :   std::vector<Node> avars;
     828                 :      73862 :   std::vector<Node> asubs;
     829                 :            : 
     830         [ +  + ]:      73862 :   Kind ok = k == andk ? ork : andk;
     831                 :            :   // global polarity : when k=ork, everything is negated
     832                 :      73862 :   bool gpol = k == andk;
     833                 :            : 
     834                 :            :   do
     835                 :            :   {
     836                 :            :     // process the current nodes
     837         [ +  + ]:     152198 :     while (!to_process.empty())
     838                 :            :     {
     839                 :      76632 :       std::vector<Node> new_to_process;
     840         [ +  + ]:     274969 :       for (const Node& cn : to_process)
     841                 :            :       {
     842         [ +  - ]:     199089 :         Trace("ext-rew-bcp-debug") << "process " << cn << std::endl;
     843                 :     199089 :         Kind cnk = cn.getKind();
     844                 :     199089 :         bool pol = cnk != notk;
     845         [ +  + ]:     199089 :         Node cln = cnk == notk ? cn[0] : cn;
     846 [ -  + ][ -  + ]:     199089 :         Assert(cln.getKind() != notk);
                 [ -  - ]
     847 [ +  + ][ +  + ]:     199089 :         if ((pol && cln.getKind() == k) || (!pol && cln.getKind() == ok))
         [ +  + ][ +  + ]
                 [ +  + ]
     848                 :            :         {
     849                 :            :           // flatten
     850         [ +  + ]:       1146 :           for (const Node& ccln : cln)
     851                 :            :           {
     852 [ +  + ][ +  + ]:        822 :             Node lccln = pol ? ccln : TermUtil::mkNegate(notk, ccln);
                 [ -  - ]
     853                 :        822 :             new_to_process.push_back(lccln);
     854                 :        822 :           }
     855                 :            :         }
     856                 :            :         else
     857                 :            :         {
     858                 :            :           // add it to the assignment
     859         [ +  + ]:     198765 :           Node val = gpol == pol ? truen : falsen;
     860                 :     198765 :           std::map<Node, Node>::iterator it = assign.find(cln);
     861         [ +  - ]:     397530 :           Trace("ext-rew-bcp") << "BCP: assign " << cln << " -> " << val
     862                 :     198765 :                                << std::endl;
     863         [ +  + ]:     198765 :           if (it != assign.end())
     864                 :            :           {
     865         [ +  + ]:        830 :             if (val != it->second)
     866                 :            :             {
     867         [ +  - ]:        752 :               Trace("ext-rew-bcp") << "BCP: conflict!" << std::endl;
     868                 :            :               // a conflicting assignment: we are done
     869         [ +  + ]:        752 :               return gpol ? falsen : truen;
     870                 :            :             }
     871                 :            :           }
     872                 :            :           else
     873                 :            :           {
     874                 :     197935 :             assign[cln] = val;
     875                 :     197935 :             avars.push_back(cln);
     876                 :     197935 :             asubs.push_back(val);
     877                 :            :           }
     878                 :            : 
     879                 :            :           // also, treat it as clause if possible
     880                 :     198013 :           if (cln.getNumChildren() > 0
     881 [ +  + ][ -  + ]:     198013 :               && (bcp_kinds.empty()
     882 [ -  - ][ +  + ]:     198013 :                   || bcp_kinds.find(cln.getKind()) != bcp_kinds.end()))
     883                 :            :           {
     884                 :     173218 :             if (std::find(clauses.begin(), clauses.end(), cn) == clauses.end()
     885 [ +  + ][ +  - ]:     173218 :                 && prop_clauses.find(cn) == prop_clauses.end())
                 [ +  + ]
     886                 :            :             {
     887         [ +  - ]:     173178 :               Trace("ext-rew-bcp") << "BCP: new clause: " << cn << std::endl;
     888                 :     173178 :               clauses.push_back(cn);
     889                 :            :             }
     890                 :            :           }
     891         [ +  + ]:     198765 :         }
     892         [ +  + ]:     199089 :       }
     893                 :      75880 :       to_process.clear();
     894                 :     151760 :       to_process.insert(
     895                 :      75880 :           to_process.end(), new_to_process.begin(), new_to_process.end());
     896         [ +  + ]:      76632 :     }
     897                 :            : 
     898                 :            :     // apply substitution to all subterms of clauses
     899                 :      75566 :     std::vector<Node> new_clauses;
     900         [ +  + ]:     252041 :     for (const Node& c : clauses)
     901                 :            :     {
     902                 :     176475 :       bool cpol = c.getKind() != notk;
     903         [ +  + ]:     176475 :       Node ca = c.getKind() == notk ? c[0] : c;
     904                 :     176475 :       bool childChanged = false;
     905                 :     176475 :       std::vector<Node> ccs_children;
     906         [ +  + ]:     583945 :       for (const Node& cc : ca)
     907                 :            :       {
     908                 :            :         // always use partial substitute, to avoid substitution in witness
     909         [ +  - ]:     407470 :         Trace("ext-rew-bcp-debug") << "...do partial substitute" << std::endl;
     910                 :            :         // substitution is only applicable to compatible kinds in bcp_kinds
     911                 :     407470 :         Node ccs = partialSubstitute(cc, assign, bcp_kinds);
     912 [ +  + ][ +  + ]:     407470 :         childChanged = childChanged || ccs != cc;
     913                 :     407470 :         ccs_children.push_back(ccs);
     914                 :     407470 :       }
     915         [ +  + ]:     176475 :       if (childChanged)
     916                 :            :       {
     917         [ -  + ]:       3022 :         if (ca.getMetaKind() == metakind::PARAMETERIZED)
     918                 :            :         {
     919                 :          0 :           ccs_children.insert(ccs_children.begin(), ca.getOperator());
     920                 :            :         }
     921                 :       3022 :         Node ccs = nm->mkNode(ca.getKind(), ccs_children);
     922 [ +  + ][ +  + ]:       3022 :         ccs = cpol ? ccs : TermUtil::mkNegate(notk, ccs);
                 [ -  - ]
     923         [ +  - ]:       6044 :         Trace("ext-rew-bcp") << "BCP: propagated " << c << " -> " << ccs
     924                 :       3022 :                              << std::endl;
     925                 :       3022 :         ccs = d_rew.rewrite(ccs);
     926         [ +  - ]:       3022 :         Trace("ext-rew-bcp") << "BCP: rewritten to " << ccs << std::endl;
     927                 :       3022 :         to_process.push_back(ccs);
     928                 :            :         // store this as a node that propagation touched. This marks c so that
     929                 :            :         // it will not be included in the final construction.
     930                 :       3022 :         prop_clauses.insert(ca);
     931                 :       3022 :       }
     932                 :            :       else
     933                 :            :       {
     934                 :     173453 :         new_clauses.push_back(c);
     935                 :            :       }
     936                 :     176475 :     }
     937                 :      75566 :     clauses.clear();
     938                 :      75566 :     clauses.insert(clauses.end(), new_clauses.begin(), new_clauses.end());
     939         [ +  + ]:      75566 :   } while (!to_process.empty());
     940                 :            : 
     941                 :            :   // remake the node
     942         [ +  + ]:      73110 :   if (!prop_clauses.empty())
     943                 :            :   {
     944                 :       2280 :     std::vector<Node> children;
     945         [ +  + ]:      14276 :     for (std::pair<const Node, Node>& l : assign)
     946                 :            :     {
     947                 :      11996 :       Node a = l.first;
     948                 :            :       // if propagation did not touch a
     949         [ +  + ]:      11996 :       if (prop_clauses.find(a) == prop_clauses.end())
     950                 :            :       {
     951 [ +  + ][ +  - ]:       8978 :         Assert(l.second == truen || l.second == falsen);
         [ -  + ][ -  + ]
                 [ -  - ]
     952 [ +  + ][ +  + ]:       8978 :         Node ln = (l.second == truen) == gpol ? a : TermUtil::mkNegate(notk, a);
                 [ -  - ]
     953                 :       8978 :         children.push_back(ln);
     954                 :       8978 :       }
     955                 :      11996 :     }
     956         [ +  + ]:       2280 :     Node new_ret = children.size() == 1 ? children[0] : nm->mkNode(k, children);
     957         [ +  - ]:       2280 :     Trace("ext-rew-bcp") << "BCP: **** OUTPUT: " << new_ret << std::endl;
     958                 :       2280 :     return new_ret;
     959                 :       2280 :   }
     960                 :            : 
     961                 :      70830 :   return Node::null();
     962                 :      73862 : }
     963                 :            : 
     964                 :      70830 : Node ExtendedRewriter::extendedRewriteFactoring(Kind andk,
     965                 :            :                                                 Kind ork,
     966                 :            :                                                 Node n) const
     967                 :            : {
     968         [ +  - ]:      70830 :   Trace("ext-rew-factoring") << "Factoring: *** INPUT: " << n << std::endl;
     969                 :      70830 :   NodeManager* nm = d_nm;
     970                 :            : 
     971                 :      70830 :   Kind nk = n.getKind();
     972 [ +  + ][ +  - ]:      70830 :   Assert(nk == andk || nk == ork);
         [ -  + ][ -  + ]
                 [ -  - ]
     973         [ +  + ]:      70830 :   Kind onk = nk == andk ? ork : andk;
     974                 :            :   // count the number of times atoms occur
     975                 :      70830 :   std::map<Node, std::vector<Node> > lit_to_cl;
     976                 :      70830 :   std::map<Node, std::vector<Node> > cl_to_lits;
     977         [ +  + ]:     255610 :   for (const Node& nc : n)
     978                 :            :   {
     979                 :     184780 :     Kind nck = nc.getKind();
     980         [ +  + ]:     184780 :     if (nck == onk)
     981                 :            :     {
     982         [ +  + ]:      73560 :       for (const Node& ncl : nc)
     983                 :            :       {
     984                 :      57521 :         if (std::find(lit_to_cl[ncl].begin(), lit_to_cl[ncl].end(), nc)
     985         [ +  - ]:     115042 :             == lit_to_cl[ncl].end())
     986                 :            :         {
     987                 :      57521 :           lit_to_cl[ncl].push_back(nc);
     988                 :      57521 :           cl_to_lits[nc].push_back(ncl);
     989                 :            :         }
     990                 :      57521 :       }
     991                 :            :     }
     992                 :            :     else
     993                 :            :     {
     994                 :     168741 :       lit_to_cl[nc].push_back(nc);
     995                 :     168741 :       cl_to_lits[nc].push_back(nc);
     996                 :            :     }
     997                 :     184780 :   }
     998                 :            :   // get the maximum shared literal to factor
     999                 :      70830 :   unsigned max_size = 0;
    1000                 :      70830 :   Node flit;
    1001         [ +  + ]:     289563 :   for (const std::pair<const Node, std::vector<Node> >& ltc : lit_to_cl)
    1002                 :            :   {
    1003         [ +  + ]:     218733 :     if (ltc.second.size() > max_size)
    1004                 :            :     {
    1005                 :      71459 :       max_size = ltc.second.size();
    1006                 :      71459 :       flit = ltc.first;
    1007                 :            :     }
    1008                 :            :   }
    1009         [ +  + ]:      70830 :   if (max_size > 1)
    1010                 :            :   {
    1011                 :            :     // do the factoring
    1012                 :        959 :     std::vector<Node> children;
    1013                 :        959 :     std::vector<Node> fchildren;
    1014                 :        959 :     std::map<Node, std::vector<Node> >::iterator itl = lit_to_cl.find(flit);
    1015                 :        959 :     std::vector<Node>& cls = itl->second;
    1016         [ +  + ]:       4371 :     for (const Node& nc : n)
    1017                 :            :     {
    1018         [ +  + ]:       3412 :       if (std::find(cls.begin(), cls.end(), nc) == cls.end())
    1019                 :            :       {
    1020                 :        852 :         children.push_back(nc);
    1021                 :            :       }
    1022                 :            :       else
    1023                 :            :       {
    1024                 :            :         // rebuild
    1025                 :       2560 :         std::vector<Node>& lits = cl_to_lits[nc];
    1026                 :            :         std::vector<Node>::iterator itlfl =
    1027                 :       2560 :             std::find(lits.begin(), lits.end(), flit);
    1028 [ -  + ][ -  + ]:       2560 :         Assert(itlfl != lits.end());
                 [ -  - ]
    1029                 :       2560 :         lits.erase(itlfl);
    1030                 :            :         // rebuild
    1031         [ +  - ]:       2560 :         if (!lits.empty())
    1032                 :            :         {
    1033         [ +  + ]:       2560 :           Node new_cl = lits.size() == 1 ? lits[0] : nm->mkNode(onk, lits);
    1034                 :       2560 :           fchildren.push_back(new_cl);
    1035                 :       2560 :         }
    1036                 :            :       }
    1037                 :       3412 :     }
    1038                 :            :     // rebuild the factored children
    1039 [ -  + ][ -  + ]:        959 :     Assert(!fchildren.empty());
                 [ -  - ]
    1040         [ -  + ]:        959 :     Node fcn = fchildren.size() == 1 ? fchildren[0] : nm->mkNode(nk, fchildren);
    1041                 :        959 :     children.push_back(nm->mkNode(onk, flit, fcn));
    1042         [ +  + ]:        959 :     Node ret = children.size() == 1 ? children[0] : nm->mkNode(nk, children);
    1043         [ +  - ]:        959 :     Trace("ext-rew-factoring") << "Factoring: *** OUTPUT: " << ret << std::endl;
    1044                 :        959 :     return ret;
    1045                 :        959 :   }
    1046                 :            :   else
    1047                 :            :   {
    1048         [ +  - ]:      69871 :     Trace("ext-rew-factoring") << "Factoring: no change" << std::endl;
    1049                 :            :   }
    1050                 :      69871 :   return Node::null();
    1051                 :      70830 : }
    1052                 :            : 
    1053                 :      69871 : Node ExtendedRewriter::extendedRewriteEqRes(Kind andk,
    1054                 :            :                                             Kind ork,
    1055                 :            :                                             Kind eqk,
    1056                 :            :                                             Kind notk,
    1057                 :            :                                             std::map<Kind, bool>& bcp_kinds,
    1058                 :            :                                             Node n,
    1059                 :            :                                             bool isXor) const
    1060                 :            : {
    1061 [ +  + ][ +  - ]:      69871 :   Assert(n.getKind() == andk || n.getKind() == ork);
         [ -  + ][ -  + ]
                 [ -  - ]
    1062         [ +  - ]:      69871 :   Trace("ext-rew-eqres") << "Eq res: **** INPUT: " << n << std::endl;
    1063                 :            : 
    1064                 :      69871 :   NodeManager* nm = d_nm;
    1065                 :      69871 :   Kind nk = n.getKind();
    1066                 :      69871 :   bool gpol = (nk == andk);
    1067         [ +  + ]:     231690 :   for (unsigned i = 0, nchild = n.getNumChildren(); i < nchild; i++)
    1068                 :            :   {
    1069                 :     171609 :     Node lit = n[i];
    1070         [ +  + ]:     171609 :     if (lit.getKind() == eqk)
    1071                 :            :     {
    1072                 :            :       // eq is the equality we are basing a substitution on
    1073                 :      50100 :       Node eq;
    1074         [ +  + ]:      50100 :       if (gpol == isXor)
    1075                 :            :       {
    1076                 :            :         // can only turn disequality into equality if types are the same
    1077         [ +  + ]:      22413 :         if (lit[1].getType() == lit.getType())
    1078                 :            :         {
    1079                 :            :           // t != s ---> ~t = s
    1080                 :        381 :           if (lit[1].getKind() == notk && lit[0].getKind() != notk)
    1081                 :            :           {
    1082                 :        420 :             eq = nm->mkNode(
    1083                 :        630 :                 Kind::EQUAL, lit[0], TermUtil::mkNegate(notk, lit[1]));
    1084                 :            :           }
    1085                 :            :           else
    1086                 :            :           {
    1087                 :        684 :             eq = nm->mkNode(
    1088                 :        513 :                 Kind::EQUAL, TermUtil::mkNegate(notk, lit[0]), lit[1]);
    1089                 :            :           }
    1090                 :            :         }
    1091                 :            :       }
    1092                 :            :       else
    1093                 :            :       {
    1094                 :      27687 :         eq = eqk == Kind::EQUAL ? lit : nm->mkNode(Kind::EQUAL, lit[0], lit[1]);
    1095                 :            :       }
    1096         [ +  + ]:      50100 :       if (!eq.isNull())
    1097                 :            :       {
    1098                 :            :         // see if it corresponds to a substitution
    1099                 :      28068 :         Subs subs;
    1100         [ +  + ]:      28068 :         if (inferSubstitution(eq, subs))
    1101                 :            :         {
    1102 [ -  + ][ -  + ]:      22122 :           Assert(subs.size() == 1);
                 [ -  - ]
    1103                 :      22122 :           std::vector<Node> children;
    1104                 :      22122 :           bool childrenChanged = false;
    1105                 :            :           // apply to all other children
    1106         [ +  + ]:      99154 :           for (unsigned j = 0; j < nchild; j++)
    1107                 :            :           {
    1108                 :      77032 :             Node ccs = n[j];
    1109         [ +  + ]:      77032 :             if (i != j)
    1110                 :            :             {
    1111                 :            :               // Substitution is only applicable to compatible kinds. We always
    1112                 :            :               // use the partialSubstitute method to avoid substitution into
    1113                 :            :               // witness terms.
    1114                 :      54910 :               ccs = partialSubstitute(ccs, subs, bcp_kinds);
    1115 [ +  + ][ +  + ]:      54910 :               childrenChanged = childrenChanged || n[j] != ccs;
         [ +  + ][ -  - ]
    1116                 :            :             }
    1117                 :      77032 :             children.push_back(ccs);
    1118                 :      77032 :           }
    1119         [ +  + ]:      22122 :           if (childrenChanged)
    1120                 :            :           {
    1121                 :       9790 :             return nm->mkNode(nk, children);
    1122                 :            :           }
    1123         [ +  + ]:      22122 :         }
    1124         [ +  + ]:      28068 :       }
    1125         [ +  + ]:      50100 :     }
    1126         [ +  + ]:     171609 :   }
    1127                 :            : 
    1128                 :      60081 :   return Node::null();
    1129                 :            : }
    1130                 :            : 
    1131                 :            : /** sort pairs by their second (unsigned) argument */
    1132                 :      57555 : static bool sortPairSecond(const std::pair<Node, unsigned>& a,
    1133                 :            :                            const std::pair<Node, unsigned>& b)
    1134                 :            : {
    1135                 :      57555 :   return (a.second < b.second);
    1136                 :            : }
    1137                 :            : 
    1138                 :            : /** A simple subsumption trie used to compute pairwise list subsets */
    1139                 :            : class SimpSubsumeTrie
    1140                 :            : {
    1141                 :            :  public:
    1142                 :            :   /** the children of this node */
    1143                 :            :   std::map<Node, SimpSubsumeTrie> d_children;
    1144                 :            :   /** the term at this node */
    1145                 :            :   Node d_data;
    1146                 :            :   /** add term to the trie
    1147                 :            :    *
    1148                 :            :    * This adds term c to this trie, whose atom list is alist. This adds terms
    1149                 :            :    * s to subsumes such that the atom list of s is a subset of the atom list
    1150                 :            :    * of c. For example, say:
    1151                 :            :    *   c1.alist = { A }
    1152                 :            :    *   c2.alist = { C }
    1153                 :            :    *   c3.alist = { B, C }
    1154                 :            :    *   c4.alist = { A, B, D }
    1155                 :            :    *   c5.alist = { A, B, C }
    1156                 :            :    * If these terms are added in the order c1, c2, c3, c4, c5, then:
    1157                 :            :    *   addTerm c1 results in subsumes = {}
    1158                 :            :    *   addTerm c2 results in subsumes = {}
    1159                 :            :    *   addTerm c3 results in subsumes = { c2 }
    1160                 :            :    *   addTerm c4 results in subsumes = { c1 }
    1161                 :            :    *   addTerm c5 results in subsumes = { c1, c2, c3 }
    1162                 :            :    * Notice that the intended use case of this trie is to add term t before t'
    1163                 :            :    * only when size( t.alist ) <= size( t'.alist ).
    1164                 :            :    *
    1165                 :            :    * The last two arguments describe the state of the path [t0...tn] we
    1166                 :            :    * have followed in the trie during the recursive call.
    1167                 :            :    * If doAdd = true,
    1168                 :            :    *   then n+1 = index and alist[1]...alist[n] = t1...tn. If index=alist.size()
    1169                 :            :    *   we add c as the current node of this trie.
    1170                 :            :    * If doAdd = false,
    1171                 :            :    *   then t1...tn occur in alist.
    1172                 :            :    */
    1173                 :     113670 :   void addTerm(Node c,
    1174                 :            :                std::vector<Node>& alist,
    1175                 :            :                std::vector<Node>& subsumes,
    1176                 :            :                unsigned index = 0,
    1177                 :            :                bool doAdd = true)
    1178                 :            :   {
    1179         [ +  + ]:     113670 :     if (!d_data.isNull())
    1180                 :            :     {
    1181                 :         64 :       subsumes.push_back(d_data);
    1182                 :            :     }
    1183         [ +  + ]:     113670 :     if (doAdd)
    1184                 :            :     {
    1185         [ +  + ]:     113536 :       if (index == alist.size())
    1186                 :            :       {
    1187                 :      55786 :         d_data = c;
    1188                 :      55786 :         return;
    1189                 :            :       }
    1190                 :            :     }
    1191                 :            :     // try all children where we have this atom
    1192         [ +  + ]:      86369 :     for (std::pair<const Node, SimpSubsumeTrie>& cp : d_children)
    1193                 :            :     {
    1194         [ +  + ]:      28485 :       if (std::find(alist.begin(), alist.end(), cp.first) != alist.end())
    1195                 :            :       {
    1196                 :        134 :         cp.second.addTerm(c, alist, subsumes, 0, false);
    1197                 :            :       }
    1198                 :            :     }
    1199         [ +  + ]:      57884 :     if (doAdd)
    1200                 :            :     {
    1201                 :      57750 :       d_children[alist[index]].addTerm(c, alist, subsumes, index + 1, doAdd);
    1202                 :            :     }
    1203                 :            :   }
    1204                 :            : };
    1205                 :            : 
    1206                 :      28715 : Node ExtendedRewriter::extendedRewriteEqChain(
    1207                 :            :     Kind eqk, Kind andk, Kind ork, Kind notk, Node ret, bool isXor) const
    1208                 :            : {
    1209 [ -  + ][ -  + ]:      28715 :   Assert(ret.getKind() == eqk);
                 [ -  - ]
    1210                 :            : 
    1211                 :            :   // this rewrite is aggressive; it in fact has the precondition that other
    1212                 :            :   // aggressive rewrites (including BCP) have been applied.
    1213         [ +  + ]:      28715 :   if (!d_aggr)
    1214                 :            :   {
    1215                 :        359 :     return Node::null();
    1216                 :            :   }
    1217                 :            : 
    1218                 :      28356 :   NodeManager* nm = d_nm;
    1219                 :            : 
    1220                 :      28356 :   TypeNode tn = ret[0].getType();
    1221                 :            : 
    1222                 :            :   // sort/cancelling for Boolean EQUAL/XOR-chains
    1223         [ +  - ]:      28356 :   Trace("ext-rew-eqchain") << "Eq-Chain : " << ret << std::endl;
    1224                 :            : 
    1225                 :            :   // get the children on either side
    1226                 :      28356 :   bool gpol = true;
    1227                 :      28356 :   std::vector<Node> children;
    1228         [ +  + ]:      85068 :   for (unsigned r = 0, size = ret.getNumChildren(); r < size; r++)
    1229                 :            :   {
    1230                 :      56712 :     Node curr = ret[r];
    1231                 :            :     // assume, if necessary, right associative
    1232                 :      57782 :     while (curr.getKind() == eqk && curr[0].getType() == tn)
    1233                 :            :     {
    1234                 :       1070 :       children.push_back(curr[0]);
    1235                 :       1070 :       curr = curr[1];
    1236                 :            :     }
    1237                 :      56712 :     children.push_back(curr);
    1238                 :      56712 :   }
    1239                 :            : 
    1240                 :      28356 :   std::map<Node, bool> cstatus;
    1241                 :            :   // add children to status
    1242         [ +  + ]:      86138 :   for (const Node& c : children)
    1243                 :            :   {
    1244                 :      57782 :     Node a = c;
    1245         [ +  + ]:      57782 :     if (a.getKind() == notk)
    1246                 :            :     {
    1247                 :       2015 :       gpol = !gpol;
    1248                 :       2015 :       a = a[0];
    1249                 :            :     }
    1250         [ +  - ]:      57782 :     Trace("ext-rew-eqchain") << "...child : " << a << std::endl;
    1251                 :      57782 :     std::map<Node, bool>::iterator itc = cstatus.find(a);
    1252         [ +  + ]:      57782 :     if (itc == cstatus.end())
    1253                 :            :     {
    1254                 :      57464 :       cstatus[a] = true;
    1255                 :            :     }
    1256                 :            :     else
    1257                 :            :     {
    1258                 :            :       // cancels
    1259                 :        318 :       cstatus.erase(a);
    1260         [ -  + ]:        318 :       if (isXor)
    1261                 :            :       {
    1262                 :          0 :         gpol = !gpol;
    1263                 :            :       }
    1264                 :            :     }
    1265                 :      57782 :   }
    1266         [ +  - ]:      28356 :   Trace("ext-rew-eqchain") << "Global polarity : " << gpol << std::endl;
    1267                 :            : 
    1268         [ -  + ]:      28356 :   if (cstatus.empty())
    1269                 :            :   {
    1270                 :          0 :     return TermUtil::mkTypeConst(ret.getType(), gpol);
    1271                 :            :   }
    1272                 :            : 
    1273                 :      28356 :   children.clear();
    1274                 :            : 
    1275                 :            :   // compute the atoms of each child
    1276         [ +  - ]:      28356 :   Trace("ext-rew-eqchain") << "eqchain-simplify: begin\n";
    1277         [ +  - ]:      28356 :   Trace("ext-rew-eqchain") << "  eqchain-simplify: get atoms...\n";
    1278                 :      28356 :   std::map<Node, std::map<Node, bool> > atoms;
    1279                 :      28356 :   std::map<Node, std::vector<Node> > alist;
    1280                 :      28356 :   std::vector<std::pair<Node, unsigned> > atom_count;
    1281         [ +  + ]:      85502 :   for (std::pair<const Node, bool>& cp : cstatus)
    1282                 :            :   {
    1283         [ -  + ]:      57146 :     if (!cp.second)
    1284                 :            :     {
    1285                 :            :       // already eliminated
    1286                 :          0 :       continue;
    1287                 :            :     }
    1288                 :      57146 :     Node c = cp.first;
    1289                 :      57146 :     Kind ck = c.getKind();
    1290         [ +  - ]:      57146 :     Trace("ext-rew-eqchain") << "  process c = " << c << std::endl;
    1291 [ +  + ][ +  + ]:      57146 :     if (ck == andk || ck == ork)
    1292                 :            :     {
    1293         [ +  + ]:       6143 :       for (unsigned j = 0, nchild = c.getNumChildren(); j < nchild; j++)
    1294                 :            :       {
    1295                 :       4555 :         Node cl = c[j];
    1296                 :       4555 :         bool pol = cl.getKind() != notk;
    1297         [ +  + ]:       4555 :         Node ca = pol ? cl : cl[0];
    1298         [ +  + ]:       4555 :         bool newVal = (ck == andk ? !pol : pol);
    1299         [ +  - ]:       9110 :         Trace("ext-rew-eqchain")
    1300                 :       4555 :             << "  atoms(" << c << ", " << ca << ") = " << newVal << std::endl;
    1301 [ -  + ][ -  + ]:       4555 :         Assert(atoms[c].find(ca) == atoms[c].end());
                 [ -  - ]
    1302                 :            :         // polarity is flipped when we are AND
    1303                 :       4555 :         atoms[c][ca] = newVal;
    1304                 :       4555 :         alist[c].push_back(ca);
    1305                 :            : 
    1306                 :            :         // if this already exists as a child of the equality chain, eliminate.
    1307                 :            :         // this catches cases like ( x & y ) = ( ( x & y ) | z ), where we
    1308                 :            :         // consider ( x & y ) a unit, whereas below it is expanded to
    1309                 :            :         // ~( ~x | ~y ).
    1310                 :       4555 :         std::map<Node, bool>::iterator itc = cstatus.find(ca);
    1311 [ +  + ][ +  - ]:       4555 :         if (itc != cstatus.end() && itc->second)
                 [ +  + ]
    1312                 :            :         {
    1313                 :            :           // cancel it
    1314                 :        680 :           cstatus[ca] = false;
    1315                 :        680 :           cstatus[c] = false;
    1316                 :            :           // make new child
    1317                 :            :           // x = ( y | ~x ) ---> y & x
    1318                 :            :           // x = ( y | x ) ---> ~y | x
    1319                 :            :           // x = ( y & x ) ---> y | ~x
    1320                 :            :           // x = ( y & ~x ) ---> ~y & ~x
    1321                 :        680 :           std::vector<Node> new_children;
    1322         [ +  + ]:       2080 :           for (unsigned k = 0, nchildc = c.getNumChildren(); k < nchildc; k++)
    1323                 :            :           {
    1324         [ +  + ]:       1400 :             if (j != k)
    1325                 :            :             {
    1326                 :        720 :               new_children.push_back(c[k]);
    1327                 :            :             }
    1328                 :            :           }
    1329         [ +  + ]:       4080 :           Node nc[2];
    1330                 :        680 :           nc[0] = c[j];
    1331         [ +  + ]:       1360 :           nc[1] = new_children.size() == 1 ? new_children[0]
    1332                 :        680 :                                            : nm->mkNode(ck, new_children);
    1333                 :            :           // negate the proper child
    1334                 :        680 :           unsigned nindex = (ck == andk) == pol ? 0 : 1;
    1335                 :        680 :           nc[nindex] = TermUtil::mkNegate(notk, nc[nindex]);
    1336         [ +  + ]:        680 :           Kind nk = pol ? ork : andk;
    1337                 :            :           // store as new child
    1338                 :        680 :           children.push_back(nm->mkNode(nk, nc[0], nc[1]));
    1339         [ -  + ]:        680 :           if (isXor)
    1340                 :            :           {
    1341                 :          0 :             gpol = !gpol;
    1342                 :            :           }
    1343                 :        680 :           break;
    1344 [ +  + ][ -  - ]:       2720 :         }
    1345 [ +  + ][ +  + ]:       5235 :       }
    1346                 :       2268 :     }
    1347                 :            :     else
    1348                 :            :     {
    1349                 :      54878 :       bool pol = ck != notk;
    1350         [ +  - ]:      54878 :       Node ca = pol ? c : c[0];
    1351                 :      54878 :       atoms[c][ca] = pol;
    1352         [ +  - ]:     109756 :       Trace("ext-rew-eqchain")
    1353                 :      54878 :           << "  atoms(" << c << ", " << ca << ") = " << pol << std::endl;
    1354                 :      54878 :       alist[c].push_back(ca);
    1355                 :      54878 :     }
    1356                 :      57146 :     atom_count.push_back(std::pair<Node, unsigned>(c, alist[c].size()));
    1357                 :      57146 :   }
    1358                 :            :   // sort the atoms in each atom list
    1359                 :      28356 :   for (std::map<Node, std::vector<Node> >::iterator it = alist.begin();
    1360         [ +  + ]:      85502 :        it != alist.end();
    1361                 :      57146 :        ++it)
    1362                 :            :   {
    1363                 :      57146 :     std::sort(it->second.begin(), it->second.end());
    1364                 :            :   }
    1365                 :            :   // check subsumptions
    1366                 :            :   // sort by #atoms
    1367                 :      28356 :   std::sort(atom_count.begin(), atom_count.end(), sortPairSecond);
    1368         [ -  + ]:      28356 :   if (TraceIsOn("ext-rew-eqchain"))
    1369                 :            :   {
    1370         [ -  - ]:          0 :     for (const std::pair<Node, unsigned>& ac : atom_count)
    1371                 :            :     {
    1372         [ -  - ]:          0 :       Trace("ext-rew-eqchain") << "  eqchain-simplify: " << ac.first << " has "
    1373                 :          0 :                                << ac.second << " atoms." << std::endl;
    1374                 :            :     }
    1375         [ -  - ]:          0 :     Trace("ext-rew-eqchain") << "  eqchain-simplify: compute subsumptions...\n";
    1376                 :            :   }
    1377                 :      28356 :   SimpSubsumeTrie sst;
    1378         [ +  + ]:      85502 :   for (std::pair<const Node, bool>& cp : cstatus)
    1379                 :            :   {
    1380         [ +  + ]:      57146 :     if (!cp.second)
    1381                 :            :     {
    1382                 :            :       // already eliminated
    1383                 :       1360 :       continue;
    1384                 :            :     }
    1385                 :      55786 :     Node c = cp.first;
    1386                 :      55786 :     std::map<Node, std::map<Node, bool> >::iterator itc = atoms.find(c);
    1387 [ -  + ][ -  + ]:      55786 :     Assert(itc != atoms.end());
                 [ -  - ]
    1388         [ +  - ]:     111572 :     Trace("ext-rew-eqchain") << "  - add term " << c << " with atom list "
    1389                 :      55786 :                              << alist[c] << "...\n";
    1390                 :      55786 :     std::vector<Node> subsumes;
    1391                 :      55786 :     sst.addTerm(c, alist[c], subsumes);
    1392         [ +  + ]:      55786 :     for (const Node& cc : subsumes)
    1393                 :            :     {
    1394         [ -  + ]:         20 :       if (!cstatus[cc])
    1395                 :            :       {
    1396                 :            :         // subsumes a child that was already eliminated
    1397                 :          0 :         continue;
    1398                 :            :       }
    1399         [ +  - ]:         40 :       Trace("ext-rew-eqchain") << "  eqchain-simplify: " << c << " subsumes "
    1400                 :         20 :                                << cc << std::endl;
    1401                 :            :       // for each of the atoms in cc
    1402                 :         20 :       std::map<Node, std::map<Node, bool> >::iterator itcc = atoms.find(cc);
    1403 [ -  + ][ -  + ]:         20 :       Assert(itcc != atoms.end());
                 [ -  - ]
    1404                 :         20 :       std::vector<Node> common_children;
    1405                 :         20 :       std::vector<Node> diff_children;
    1406         [ +  + ]:         64 :       for (const std::pair<const Node, bool>& ap : itcc->second)
    1407                 :            :       {
    1408                 :            :         // compare the polarity
    1409                 :         44 :         Node a = ap.first;
    1410                 :         44 :         bool polcc = ap.second;
    1411 [ -  + ][ -  + ]:         44 :         Assert(itc->second.find(a) != itc->second.end());
                 [ -  - ]
    1412                 :         44 :         bool polc = itc->second[a];
    1413         [ +  - ]:         88 :         Trace("ext-rew-eqchain") << "    eqchain-simplify: atom " << a
    1414                 :          0 :                                  << " has polarities : " << polc << " " << polcc
    1415                 :         44 :                                  << "\n";
    1416 [ +  + ][ +  + ]:         44 :         Node lit = polc ? a : TermUtil::mkNegate(notk, a);
                 [ -  - ]
    1417         [ +  + ]:         44 :         if (polc != polcc)
    1418                 :            :         {
    1419                 :         24 :           diff_children.push_back(lit);
    1420                 :            :         }
    1421                 :            :         else
    1422                 :            :         {
    1423                 :         20 :           common_children.push_back(lit);
    1424                 :            :         }
    1425                 :         44 :       }
    1426                 :         20 :       std::vector<Node> rem_children;
    1427         [ +  + ]:         64 :       for (const std::pair<const Node, bool>& ap : itc->second)
    1428                 :            :       {
    1429                 :         44 :         Node a = ap.first;
    1430         [ -  + ]:         44 :         if (atoms[cc].find(a) == atoms[cc].end())
    1431                 :            :         {
    1432                 :          0 :           bool polc = ap.second;
    1433                 :          0 :           rem_children.push_back(polc ? a : TermUtil::mkNegate(notk, a));
    1434                 :            :         }
    1435                 :         44 :       }
    1436         [ +  - ]:         40 :       Trace("ext-rew-eqchain")
    1437                 :          0 :           << "    #common/diff/rem: " << common_children.size() << "/"
    1438                 :         20 :           << diff_children.size() << "/" << rem_children.size() << "\n";
    1439                 :         20 :       bool do_rewrite = false;
    1440         [ +  - ]:         32 :       if (common_children.empty() && itc->second.size() == itcc->second.size()
    1441 [ +  + ][ +  - ]:         32 :           && itcc->second.size() == 2)
                 [ +  + ]
    1442                 :            :       {
    1443                 :            :         // x | y = ~x | ~y ---> ~( x = y )
    1444                 :         12 :         do_rewrite = true;
    1445                 :         12 :         children.push_back(diff_children[0]);
    1446                 :         12 :         children.push_back(diff_children[1]);
    1447                 :         12 :         gpol = !gpol;
    1448         [ +  - ]:         12 :         Trace("ext-rew-eqchain") << "    apply 2-child all-diff\n";
    1449                 :            :       }
    1450 [ -  + ][ -  - ]:          8 :       else if (common_children.empty() && diff_children.size() == 1)
                 [ -  + ]
    1451                 :            :       {
    1452                 :          0 :         do_rewrite = true;
    1453                 :            :         // x = ( ~x | y ) ---> ~( ~x | ~y )
    1454                 :          0 :         Node remn = rem_children.size() == 1 ? rem_children[0]
    1455         [ -  - ]:          0 :                                              : nm->mkNode(ork, rem_children);
    1456                 :          0 :         remn = TermUtil::mkNegate(notk, remn);
    1457                 :          0 :         children.push_back(nm->mkNode(ork, diff_children[0], remn));
    1458         [ -  - ]:          0 :         if (!isXor)
    1459                 :            :         {
    1460                 :          0 :           gpol = !gpol;
    1461                 :            :         }
    1462         [ -  - ]:          0 :         Trace("ext-rew-eqchain") << "    apply unit resolution\n";
    1463                 :          0 :       }
    1464                 :          8 :       else if (diff_children.size() == 1
    1465 [ -  + ][ -  - ]:          8 :                && itc->second.size() == itcc->second.size())
                 [ -  + ]
    1466                 :            :       {
    1467                 :            :         // ( x | y | z ) = ( x | ~y | z ) ---> ( x | z )
    1468                 :          0 :         do_rewrite = true;
    1469                 :          0 :         Assert(!common_children.empty());
    1470                 :          0 :         Node comn = common_children.size() == 1
    1471                 :          0 :                         ? common_children[0]
    1472         [ -  - ]:          0 :                         : nm->mkNode(ork, common_children);
    1473                 :          0 :         children.push_back(comn);
    1474         [ -  - ]:          0 :         if (isXor)
    1475                 :            :         {
    1476                 :          0 :           gpol = !gpol;
    1477                 :            :         }
    1478         [ -  - ]:          0 :         Trace("ext-rew-eqchain") << "    apply resolution\n";
    1479                 :          0 :       }
    1480         [ +  - ]:          8 :       else if (diff_children.empty())
    1481                 :            :       {
    1482                 :          8 :         do_rewrite = true;
    1483         [ +  - ]:          8 :         if (rem_children.empty())
    1484                 :            :         {
    1485                 :            :           // x | y = x | y ---> true
    1486                 :            :           // this can happen if we have ( ~x & ~y ) = ( x | y )
    1487                 :          8 :           children.push_back(TermUtil::mkTypeMaxValue(tn));
    1488         [ -  + ]:          8 :           if (isXor)
    1489                 :            :           {
    1490                 :          0 :             gpol = !gpol;
    1491                 :            :           }
    1492         [ +  - ]:          8 :           Trace("ext-rew-eqchain") << "    apply cancel\n";
    1493                 :            :         }
    1494                 :            :         else
    1495                 :            :         {
    1496                 :            :           // x | y = ( x | y | z ) ---> ( x | y | ~z )
    1497                 :          0 :           Node remn = rem_children.size() == 1 ? rem_children[0]
    1498         [ -  - ]:          0 :                                                : nm->mkNode(ork, rem_children);
    1499                 :          0 :           remn = TermUtil::mkNegate(notk, remn);
    1500                 :          0 :           Node comn = common_children.size() == 1
    1501                 :          0 :                           ? common_children[0]
    1502         [ -  - ]:          0 :                           : nm->mkNode(ork, common_children);
    1503                 :          0 :           children.push_back(nm->mkNode(ork, comn, remn));
    1504         [ -  - ]:          0 :           if (isXor)
    1505                 :            :           {
    1506                 :          0 :             gpol = !gpol;
    1507                 :            :           }
    1508         [ -  - ]:          0 :           Trace("ext-rew-eqchain") << "    apply subsume\n";
    1509                 :          0 :         }
    1510                 :            :       }
    1511         [ +  - ]:         20 :       if (do_rewrite)
    1512                 :            :       {
    1513                 :            :         // eliminate the children, reverse polarity as needed
    1514         [ +  + ]:         60 :         for (unsigned r = 0; r < 2; r++)
    1515                 :            :         {
    1516         [ +  + ]:         40 :           Node c_rem = r == 0 ? c : cc;
    1517                 :         40 :           cstatus[c_rem] = false;
    1518         [ +  + ]:         40 :           if (c_rem.getKind() == andk)
    1519                 :            :           {
    1520                 :         20 :             gpol = !gpol;
    1521                 :            :           }
    1522                 :         40 :         }
    1523                 :         20 :         break;
    1524                 :            :       }
    1525 [ -  + ][ -  + ]:         60 :     }
                 [ -  + ]
    1526                 :      55786 :   }
    1527         [ +  - ]:      28356 :   Trace("ext-rew-eqchain") << "eqchain-simplify: finish" << std::endl;
    1528                 :            : 
    1529                 :            :   // sorted right associative chain
    1530                 :      28356 :   bool has_nvar = false;
    1531                 :      28356 :   unsigned nvar_index = 0;
    1532         [ +  + ]:      85502 :   for (std::pair<const Node, bool>& cp : cstatus)
    1533                 :            :   {
    1534         [ +  + ]:      57146 :     if (cp.second)
    1535                 :            :     {
    1536         [ +  + ]:      55746 :       if (!cp.first.isVar())
    1537                 :            :       {
    1538                 :      38633 :         has_nvar = true;
    1539                 :      38633 :         nvar_index = children.size();
    1540                 :            :       }
    1541                 :      55746 :       children.push_back(cp.first);
    1542                 :            :     }
    1543                 :            :   }
    1544                 :      28356 :   std::sort(children.begin(), children.end());
    1545                 :            : 
    1546                 :      28356 :   Node new_ret;
    1547         [ +  + ]:      28356 :   if (!gpol)
    1548                 :            :   {
    1549                 :            :     // negate the constant child if it exists
    1550         [ +  + ]:       1777 :     unsigned nindex = has_nvar ? nvar_index : 0;
    1551                 :       1777 :     children[nindex] = TermUtil::mkNegate(notk, children[nindex]);
    1552                 :            :   }
    1553                 :      28356 :   new_ret = children.back();
    1554                 :      28356 :   unsigned index = children.size() - 1;
    1555         [ +  + ]:      56458 :   while (index > 0)
    1556                 :            :   {
    1557                 :      28102 :     index--;
    1558                 :      28102 :     new_ret = nm->mkNode(eqk, children[index], new_ret);
    1559                 :            :   }
    1560                 :      28356 :   new_ret = d_rew.rewrite(new_ret);
    1561         [ +  + ]:      28356 :   if (new_ret != ret)
    1562                 :            :   {
    1563                 :       2043 :     return new_ret;
    1564                 :            :   }
    1565                 :      26313 :   return Node::null();
    1566                 :      28356 : }
    1567                 :            : 
    1568                 :     518424 : Node ExtendedRewriter::partialSubstitute(
    1569                 :            :     Node n,
    1570                 :            :     const std::map<Node, Node>& assign,
    1571                 :            :     const std::map<Kind, bool>& rkinds) const
    1572                 :            : {
    1573                 :     518424 :   std::unordered_map<TNode, Node> visited;
    1574                 :     518424 :   std::unordered_map<TNode, Node>::iterator it;
    1575                 :     518424 :   std::map<Node, Node>::const_iterator ita;
    1576                 :     518424 :   std::vector<TNode> visit;
    1577                 :     518424 :   TNode cur;
    1578                 :     518424 :   visit.push_back(n);
    1579                 :            :   do
    1580                 :            :   {
    1581                 :    6316701 :     cur = visit.back();
    1582                 :    6316701 :     visit.pop_back();
    1583                 :    6316701 :     it = visited.find(cur);
    1584                 :            : 
    1585         [ +  + ]:    6316701 :     if (it == visited.end())
    1586                 :            :     {
    1587                 :    2645829 :       ita = assign.find(cur);
    1588         [ +  + ]:    2645829 :       if (ita != assign.end())
    1589                 :            :       {
    1590                 :      26665 :         visited[cur] = ita->second;
    1591                 :            :       }
    1592                 :            :       else
    1593                 :            :       {
    1594                 :            :         // If rkinds is non-empty, then can only recurse on its kinds.
    1595                 :            :         // We also always disallow substitution into witness. Notice that
    1596                 :            :         // we disallow witness here, due to unsoundness when applying contextual
    1597                 :            :         // substitutions over witness terms (see #4620).
    1598                 :    2619164 :         Kind k = cur.getKind();
    1599                 :    5238328 :         if (k != Kind::WITNESS
    1600 [ +  - ][ -  + ]:    2619164 :             && (rkinds.empty() || rkinds.find(k) != rkinds.end()))
         [ -  - ][ +  - ]
    1601                 :            :         {
    1602                 :    2619164 :           visited[cur] = Node::null();
    1603                 :    2619164 :           visit.push_back(cur);
    1604         [ +  + ]:    5798277 :           for (const Node& cn : cur)
    1605                 :            :           {
    1606                 :    3179113 :             visit.push_back(cn);
    1607                 :    3179113 :           }
    1608                 :            :         }
    1609                 :            :         else
    1610                 :            :         {
    1611                 :          0 :           visited[cur] = cur;
    1612                 :            :         }
    1613                 :            :       }
    1614                 :            :     }
    1615         [ +  + ]:    3670872 :     else if (it->second.isNull())
    1616                 :            :     {
    1617                 :    2619164 :       Node ret = cur;
    1618                 :    2619164 :       bool childChanged = false;
    1619                 :    2619164 :       std::vector<Node> children;
    1620         [ +  + ]:    2619164 :       if (cur.getMetaKind() == metakind::PARAMETERIZED)
    1621                 :            :       {
    1622                 :      15402 :         children.push_back(cur.getOperator());
    1623                 :            :       }
    1624         [ +  + ]:    5798277 :       for (const Node& cn : cur)
    1625                 :            :       {
    1626                 :    3179113 :         it = visited.find(cn);
    1627 [ -  + ][ -  + ]:    3179113 :         Assert(it != visited.end());
                 [ -  - ]
    1628 [ -  + ][ -  + ]:    3179113 :         Assert(!it->second.isNull());
                 [ -  - ]
    1629 [ +  + ][ +  + ]:    3179113 :         childChanged = childChanged || cn != it->second;
    1630                 :    3179113 :         children.push_back(it->second);
    1631                 :    3179113 :       }
    1632         [ +  + ]:    2619164 :       if (childChanged)
    1633                 :            :       {
    1634                 :      91040 :         ret = d_nm->mkNode(cur.getKind(), children);
    1635                 :            :       }
    1636                 :    2619164 :       visited[cur] = ret;
    1637                 :    2619164 :     }
    1638         [ +  + ]:    6316701 :   } while (!visit.empty());
    1639 [ -  + ][ -  + ]:     518424 :   Assert(visited.find(n) != visited.end());
                 [ -  - ]
    1640 [ -  + ][ -  + ]:     518424 :   Assert(!visited.find(n)->second.isNull());
                 [ -  - ]
    1641                 :    1036848 :   return visited[n];
    1642                 :     518424 : }
    1643                 :            : 
    1644                 :      83743 : Node ExtendedRewriter::partialSubstitute(
    1645                 :            :     Node n, const Subs& subs, const std::map<Kind, bool>& rkinds) const
    1646                 :            : {
    1647                 :      83743 :   std::map<Node, Node> assign;
    1648         [ +  + ]:     181328 :   for (size_t i = 0, nvars = subs.size(); i < nvars; i++)
    1649                 :            :   {
    1650                 :      97585 :     assign[subs.d_vars[i]] = subs.d_subs[i];
    1651                 :            :   }
    1652                 :     167486 :   return partialSubstitute(n, assign, rkinds);
    1653                 :      83743 : }
    1654                 :            : 
    1655                 :      40871 : Node ExtendedRewriter::solveEquality(Node n) const
    1656                 :            : {
    1657                 :            :   // TODO (#1706) : implement
    1658 [ -  + ][ -  + ]:      40871 :   Assert(n.getKind() == Kind::EQUAL);
                 [ -  - ]
    1659                 :            : 
    1660                 :      40871 :   return Node::null();
    1661                 :            : }
    1662                 :            : 
    1663                 :      75603 : bool ExtendedRewriter::inferSubstitution(Node n, Subs& subs, bool usePred) const
    1664                 :            : {
    1665         [ +  + ]:      75603 :   if (n.getKind() == Kind::AND)
    1666                 :            :   {
    1667                 :       4860 :     bool ret = false;
    1668         [ +  + ]:      23562 :     for (const Node& nc : n)
    1669                 :            :     {
    1670                 :      18702 :       bool cret = inferSubstitution(nc, subs, usePred);
    1671 [ +  + ][ +  - ]:      18702 :       ret = ret || cret;
    1672                 :      18702 :     }
    1673                 :       4860 :     return ret;
    1674                 :            :   }
    1675         [ +  + ]:      70743 :   if (n.getKind() == Kind::EQUAL)
    1676                 :            :   {
    1677                 :            :     // see if it can be put into form x = y
    1678                 :      40871 :     Node slv_eq = solveEquality(n);
    1679         [ -  + ]:      40871 :     if (!slv_eq.isNull())
    1680                 :            :     {
    1681                 :          0 :       n = slv_eq;
    1682                 :            :     }
    1683         [ +  + ]:     245226 :     Node v[2];
    1684         [ +  + ]:      85884 :     for (unsigned i = 0; i < 2; i++)
    1685                 :            :     {
    1686         [ +  + ]:      76419 :       if (n[i].isConst())
    1687                 :            :       {
    1688                 :      31406 :         subs.add(n[1 - i], n[i]);
    1689                 :      31406 :         return true;
    1690                 :            :       }
    1691         [ +  + ]:      45013 :       if (n[i].isVar())
    1692                 :            :       {
    1693                 :      29773 :         v[i] = n[i];
    1694                 :            :       }
    1695                 :      15240 :       else if (TermUtil::isNegate(n[i].getKind()) && n[i][0].isVar())
    1696                 :            :       {
    1697                 :        300 :         v[i] = n[i][0];
    1698                 :            :       }
    1699                 :            :     }
    1700         [ +  + ]:      23131 :     for (unsigned i = 0; i < 2; i++)
    1701                 :            :     {
    1702                 :      16443 :       TNode r1 = v[i];
    1703                 :      16443 :       Node r2 = v[1 - i];
    1704 [ +  + ][ +  + ]:      16443 :       if (r1.isVar() && ((r2.isVar() && r1 < r2) || r2.isConst()))
         [ +  + ][ -  + ]
                 [ +  + ]
    1705                 :            :       {
    1706                 :       2777 :         r2 = n[1 - i];
    1707         [ +  + ]:       2777 :         if (v[i] != n[i])
    1708                 :            :         {
    1709 [ -  + ][ -  + ]:        212 :           Assert(TermUtil::isNegate(n[i].getKind()));
                 [ -  - ]
    1710                 :        212 :           r2 = TermUtil::mkNegate(n[i].getKind(), r2);
    1711                 :            :         }
    1712         [ +  - ]:       2777 :         if (!subs.contains(r1))
    1713                 :            :         {
    1714                 :       2777 :           subs.add(r1, r2);
    1715                 :       2777 :           return true;
    1716                 :            :         }
    1717                 :            :       }
    1718 [ +  + ][ +  + ]:      19220 :     }
    1719 [ +  + ][ +  + ]:     163484 :   }
                 [ -  - ]
    1720         [ +  + ]:      36560 :   if (usePred)
    1721                 :            :   {
    1722                 :      30614 :     bool negated = n.getKind() == Kind::NOT;
    1723         [ +  + ]:      30614 :     Node var = negated ? n[0] : n;
    1724                 :      30614 :     Node s = d_nm->mkConst(!negated);
    1725                 :      30614 :     subs.add(var, s);
    1726                 :      30614 :     return true;
    1727                 :      30614 :   }
    1728                 :       5946 :   return false;
    1729                 :            : }
    1730                 :            : 
    1731                 :      18582 : Node ExtendedRewriter::extendedRewriteStrings(const Node& node) const
    1732                 :            : {
    1733         [ +  - ]:      37164 :   Trace("q-ext-rewrite-debug")
    1734                 :      18582 :       << "Extended rewrite strings : " << node << std::endl;
    1735                 :            : 
    1736                 :            :   // allow recursive approximations
    1737                 :      18582 :   strings::ArithEntail ae(d_nm, &d_rew, true);
    1738                 :      18582 :   strings::StringsEntail se(&d_rew, ae);
    1739                 :      18582 :   strings::SequencesRewriter sr(d_nm, ae, se, nullptr);
    1740                 :            : 
    1741                 :      18582 :   Kind k = node.getKind();
    1742         [ +  + ]:      18582 :   if (k == Kind::EQUAL)
    1743                 :            :   {
    1744                 :            :     // we invoke the extended equality rewriter, which does standard
    1745                 :            :     // rewrites, which notice are only invoked at preprocessing
    1746                 :            :     // and not during Rewriter::rewrite.
    1747                 :       3713 :     Node ret = sr.rewriteEqualityExt(node);
    1748         [ +  + ]:       3713 :     if (ret != node)
    1749                 :            :     {
    1750                 :        328 :       debugExtendedRewrite(node, ret, "STR_EXT_EQ_REWRITE");
    1751                 :        328 :       return ret;
    1752                 :            :     }
    1753                 :            : 
    1754                 :            :     // ------- length entailment
    1755                 :       6770 :     Node len0 = d_nm->mkNode(Kind::STRING_LENGTH, node[0]);
    1756                 :       6770 :     Node len1 = d_nm->mkNode(Kind::STRING_LENGTH, node[1]);
    1757                 :       3385 :     Node len_eq = len0.eqNode(len1);
    1758                 :       3385 :     len_eq = d_rew.rewrite(len_eq);
    1759         [ -  + ]:       3385 :     if (len_eq == d_false)
    1760                 :            :     {
    1761                 :          0 :       debugExtendedRewrite(node, d_false, "String EQUAL len entailment");
    1762                 :          0 :       return d_false;
    1763                 :            :     }
    1764                 :            : 
    1765                 :       3385 :     TypeNode stype = node[0].getType();
    1766         [ +  + ]:      20310 :     std::vector<Node> c[2];
    1767         [ +  + ]:      10155 :     for (unsigned i = 0; i < 2; i++)
    1768                 :            :     {
    1769                 :       6770 :       strings::utils::getConcat(node[i], c[i]);
    1770                 :            :     }
    1771                 :            : 
    1772                 :            :     // ------- homogeneous constants
    1773         [ +  + ]:      10154 :     for (unsigned i = 0; i < 2; i++)
    1774                 :            :     {
    1775                 :       6770 :       Node cn = se.checkHomogeneousString(node[i]);
    1776 [ +  + ][ +  + ]:       6770 :       if (!cn.isNull() && !strings::Word::isEmpty(cn))
         [ +  + ][ +  + ]
                 [ -  - ]
    1777                 :            :       {
    1778 [ -  + ][ -  + ]:       1531 :         Assert(cn.isConst());
                 [ -  - ]
    1779 [ -  + ][ -  + ]:       1531 :         Assert(strings::Word::getLength(cn) == 1);
                 [ -  - ]
    1780                 :            : 
    1781                 :            :         // The operands of the concat on each side of the equality without
    1782                 :            :         // constant strings
    1783         [ +  + ]:       9186 :         std::vector<Node> trimmed[2];
    1784                 :            :         // Counts the number of `cn`s on each side
    1785                 :       1531 :         size_t numCns[2] = {0, 0};
    1786         [ +  + ]:       4593 :         for (size_t j = 0; j < 2; j++)
    1787                 :            :         {
    1788                 :            :           // Sort the operands of the concats on both sides of the equality
    1789                 :            :           // (since both sides may only contain one char, the order does not
    1790                 :            :           // matter)
    1791                 :       3062 :           std::sort(c[j].begin(), c[j].end());
    1792         [ +  + ]:       6139 :           for (const Node& cc : c[j])
    1793                 :            :           {
    1794         [ +  + ]:       3077 :             if (cc.isConst())
    1795                 :            :             {
    1796                 :            :               // Count the number of `cn`s in the string constant and make
    1797                 :            :               // sure that all chars are `cn`s
    1798                 :       1500 :               std::vector<Node> veccc = strings::Word::getChars(cc);
    1799         [ +  + ]:       3429 :               for (const Node& cv : veccc)
    1800                 :            :               {
    1801         [ -  + ]:       1929 :                 if (cv != cn)
    1802                 :            :                 {
    1803                 :            :                   // This conflict case should mostly should be taken care of by
    1804                 :            :                   // multiset reasoning in the strings rewriter, but we
    1805                 :            :                   // recognize this conflict just in case.
    1806                 :          0 :                   debugExtendedRewrite(node, d_false, "STR_EQ_CONST_NHOMOG");
    1807                 :          0 :                   return d_false;
    1808                 :            :                 }
    1809                 :       1929 :                 numCns[j]++;
    1810                 :            :               }
    1811         [ +  - ]:       1500 :             }
    1812                 :            :             else
    1813                 :            :             {
    1814                 :       1577 :               trimmed[j].push_back(cc);
    1815                 :            :             }
    1816                 :            :           }
    1817                 :            :         }
    1818                 :            : 
    1819                 :            :         // We have to remove the same number of `cn`s from both sides, so the
    1820                 :            :         // side with less `cn`s determines how many we can remove
    1821                 :       1531 :         size_t trimmedConst = std::min(numCns[0], numCns[1]);
    1822         [ +  + ]:       4593 :         for (size_t j = 0; j < 2; j++)
    1823                 :            :         {
    1824                 :       3062 :           size_t diff = numCns[j] - trimmedConst;
    1825         [ +  + ]:       3062 :           if (diff != 0)
    1826                 :            :           {
    1827                 :            :             // Add a constant string to the side with more `cn`s to restore
    1828                 :            :             // the difference in number of `cn`s
    1829                 :       1495 :             std::vector<Node> vec(diff, cn);
    1830                 :       1495 :             trimmed[j].push_back(strings::Word::mkWordFlatten(vec));
    1831                 :       1495 :           }
    1832                 :            :         }
    1833                 :            : 
    1834                 :       1531 :         Node lhs = strings::utils::mkConcat(trimmed[i], stype);
    1835                 :       1531 :         Node ss = strings::utils::mkConcat(trimmed[1 - i], stype);
    1836                 :       1531 :         if (lhs != node[i] || ss != node[1 - i])
    1837                 :            :         {
    1838                 :            :           // e.g.
    1839                 :            :           //  "AA" = y ++ x ---> "AA" = x ++ y if x < y
    1840                 :            :           //  "AAA" = y ++ "A" ++ z ---> "AA" = y ++ z
    1841                 :            :           //
    1842                 :            :           // We generally don't apply the extended equality rewriter if the
    1843                 :            :           // original node was an equality but we may be able to do additional
    1844                 :            :           // rewriting here.
    1845                 :          1 :           Node new_ret = lhs.eqNode(ss);
    1846                 :          1 :           debugExtendedRewrite(node, new_ret, "STR_EQ_CONST_NHOMOG");
    1847                 :          1 :           return new_ret;
    1848                 :          1 :         }
    1849 [ +  + ][ +  + ]:       6125 :       }
         [ +  + ][ -  - ]
    1850         [ +  + ]:       6770 :     }
    1851 [ +  + ][ +  + ]:      13872 :   }
         [ +  + ][ +  + ]
         [ +  + ][ +  + ]
                 [ -  - ]
    1852         [ +  + ]:      14869 :   else if (k == Kind::STRING_CONCAT)
    1853                 :            :   {
    1854                 :            :     // Sort adjacent operands in str.++ that all result in the same string or
    1855                 :            :     // the empty string.
    1856                 :            :     //
    1857                 :            :     // E.g.: (str.++ ... (str.replace "A" x "") "A" (str.substr "A" 0 z) ...)
    1858                 :            :     // --> (str.++ ... [sort those 3 arguments] ... )
    1859                 :        613 :     std::vector<Node> vec(node.begin(), node.end());
    1860                 :        613 :     size_t lastIdx = 0;
    1861                 :        613 :     Node lastX;
    1862         [ +  + ]:       1965 :     for (size_t i = 0, nsize = vec.size(); i < nsize; i++)
    1863                 :            :     {
    1864                 :       1352 :       Node s = se.getStringOrEmpty(vec[i]);
    1865                 :       1352 :       bool nextX = false;
    1866         [ +  + ]:       1352 :       if (s != lastX)
    1867                 :            :       {
    1868                 :       1313 :         nextX = true;
    1869                 :            :       }
    1870         [ +  + ]:       1352 :       if (nextX)
    1871                 :            :       {
    1872                 :       1313 :         std::sort(vec.begin() + lastIdx, vec.begin() + i);
    1873                 :       1313 :         lastX = s;
    1874                 :       1313 :         lastIdx = i;
    1875                 :            :       }
    1876                 :       1352 :     }
    1877                 :        613 :     std::sort(vec.begin() + lastIdx, vec.end());
    1878                 :        613 :     TypeNode tn = node.getType();
    1879                 :        613 :     Node retNode = strings::utils::mkConcat(vec, tn);
    1880         [ +  + ]:        613 :     if (retNode != node)
    1881                 :            :     {
    1882                 :          6 :       debugExtendedRewrite(node, retNode, "CONCAT_NORM_SORT");
    1883                 :          6 :       return retNode;
    1884                 :            :     }
    1885 [ +  + ][ +  + ]:        631 :   }
         [ +  + ][ +  + ]
    1886         [ +  + ]:      14256 :   else if (k == Kind::STRING_SUBSTR)
    1887                 :            :   {
    1888                 :       2338 :     NodeManager* nm = d_nm;
    1889                 :       4676 :     Node tot_len = d_rew.rewrite(nm->mkNode(Kind::STRING_LENGTH, node[0]));
    1890                 :            :     // (str.substr s x y) --> "" if x < len(s) |= 0 >= y
    1891                 :       4676 :     Node n1_lt_tot_len = d_rew.rewrite(nm->mkNode(Kind::LT, node[1], tot_len));
    1892         [ +  + ]:       2338 :     if (ae.checkWithAssumption(n1_lt_tot_len, d_intZero, node[2], false))
    1893                 :            :     {
    1894                 :          2 :       Node ret = strings::Word::mkEmptyWord(node.getType());
    1895                 :          2 :       debugExtendedRewrite(node, ret, "SS_START_ENTAILS_ZERO_LEN");
    1896                 :          2 :       return ret;
    1897                 :          2 :     }
    1898                 :            : 
    1899                 :            :     // (str.substr s x y) --> "" if 0 < y |= x >= str.len(s)
    1900                 :       4672 :     Node non_zero_len = d_rew.rewrite(nm->mkNode(Kind::LT, d_intZero, node[2]));
    1901         [ +  + ]:       2336 :     if (ae.checkWithAssumption(non_zero_len, node[1], tot_len, false))
    1902                 :            :     {
    1903                 :          3 :       Node ret = strings::Word::mkEmptyWord(node.getType());
    1904                 :          3 :       debugExtendedRewrite(node, ret, "SS_NON_ZERO_LEN_ENTAILS_OOB");
    1905                 :          3 :       return ret;
    1906                 :          3 :     }
    1907                 :            :     // (str.substr s x y) --> "" if x >= 0 |= 0 >= str.len(s)
    1908                 :            :     Node geq_zero_start =
    1909                 :       4666 :         d_rew.rewrite(nm->mkNode(Kind::GEQ, node[1], d_intZero));
    1910         [ +  + ]:       2333 :     if (ae.checkWithAssumption(geq_zero_start, d_intZero, tot_len, false))
    1911                 :            :     {
    1912                 :          1 :       Node ret = strings::Word::mkEmptyWord(node.getType());
    1913                 :          1 :       debugExtendedRewrite(node, ret, "SS_GEQ_ZERO_START_ENTAILS_EMP_S");
    1914                 :          1 :       return ret;
    1915                 :          1 :     }
    1916 [ +  + ][ +  + ]:       2349 :   }
         [ +  + ][ +  + ]
    1917         [ +  + ]:      11918 :   else if (k == Kind::STRING_REPLACE)
    1918                 :            :   {
    1919         [ +  + ]:        153 :     if (node[0] == node[2])
    1920                 :            :     {
    1921                 :            :       // (str.replace x y x) ---> (str.replace x (str.++ y1 ... yn) x)
    1922                 :            :       // if 1 >= (str.len x) and (= y "") ---> (= y1 "") ... (= yn "")
    1923         [ +  + ]:         14 :       if (se.checkLengthOne(node[0]))
    1924                 :            :       {
    1925                 :          3 :         TypeNode stype = node.getType();
    1926                 :          3 :         Node empty = strings::Word::mkEmptyWord(stype);
    1927                 :          3 :         Node rn1 = d_rew.rewrite(
    1928                 :          6 :             d_rew.rewriteEqualityExt(d_nm->mkNode(Kind::EQUAL, node[1], empty)));
    1929         [ +  - ]:          3 :         if (rn1 != node[1])
    1930                 :            :         {
    1931                 :          3 :           std::vector<Node> emptyNodes;
    1932                 :            :           bool allEmptyEqs;
    1933                 :          3 :           std::tie(allEmptyEqs, emptyNodes) = strings::utils::collectEmptyEqs(rn1);
    1934                 :            : 
    1935         [ +  + ]:          3 :           if (allEmptyEqs)
    1936                 :            :           {
    1937                 :          2 :             Node nn1 = strings::utils::mkConcat(emptyNodes, stype);
    1938         [ +  + ]:          2 :             if (node[1] != nn1)
    1939                 :            :             {
    1940                 :          2 :               Node ret = d_nm->mkNode(Kind::STRING_REPLACE, node[0], nn1, node[2]);
    1941                 :          1 :               debugExtendedRewrite(node, ret, "RPL_X_Y_X_SIMP");
    1942                 :          1 :               return ret;
    1943                 :          1 :             }
    1944         [ +  + ]:          2 :           }
    1945         [ +  + ]:          3 :         }
    1946 [ +  + ][ +  + ]:          5 :       }
                 [ +  + ]
    1947                 :            :     }
    1948                 :        304 :     Node cmp_con = d_nm->mkNode(Kind::STRING_CONTAINS, node[0], node[1]);
    1949                 :            :     // note we make a full recursive call to extended rewrite here, which should
    1950                 :            :     // be fine since the term we are rewriting is simpler than the current one.
    1951                 :        152 :     Node cmp_conr = extendedRewrite(cmp_con);
    1952 [ +  + ][ +  + ]:        152 :     if (cmp_conr.getKind() == Kind::EQUAL || cmp_conr.getKind() == Kind::AND)
                 [ +  + ]
    1953                 :            :     {
    1954                 :         19 :       TypeNode stype = node.getType();
    1955                 :            :       // Rewriting the str.contains may return equalities of the form (= x "").
    1956                 :            :       // In that case, we can substitute the variables appearing in those
    1957                 :            :       // equalities with the empty string in the third argument of the
    1958                 :            :       // str.replace. For example:
    1959                 :            :       //
    1960                 :            :       // (str.replace x (str.++ x y) y) --> (str.replace x (str.++ x y) "")
    1961                 :            :       //
    1962                 :            :       // This can be done because str.replace changes x iff (str.++ x y) is in x
    1963                 :            :       // but that means that y must be empty in that case. Thus, we can
    1964                 :            :       // substitute y with "" in the third argument. Note that the third argument
    1965                 :            :       // does not matter when the str.replace does not apply.
    1966                 :            :       //
    1967                 :         19 :       Node empty = strings::Word::mkEmptyWord(stype);
    1968                 :         19 :       std::vector<Node> emptyNodes;
    1969                 :            :       bool allEmptyEqs;
    1970                 :         19 :       std::tie(allEmptyEqs, emptyNodes) = strings::utils::collectEmptyEqs(cmp_conr);
    1971         [ +  + ]:         19 :       if (emptyNodes.size() > 0)
    1972                 :            :       {
    1973                 :            :         // Perform the substitutions
    1974                 :         36 :         std::vector<TNode> substs(emptyNodes.size(), TNode(empty));
    1975                 :            :         Node nn2 = node[2].substitute(
    1976                 :         18 :             emptyNodes.begin(), emptyNodes.end(), substs.begin(), substs.end());
    1977                 :            : 
    1978                 :            :         // If the contains rewrites to a conjunction of empty-string equalities
    1979                 :            :         // and we are doing the replacement in an empty string, we can rewrite
    1980                 :            :         // the string-to-replace with a concatenation of all the terms that must
    1981                 :            :         // be empty:
    1982                 :            :         //
    1983                 :            :         // (str.replace "" y z) ---> (str.replace "" (str.++ y1 ... yn)  z)
    1984                 :            :         // if (str.contains "" y) ---> (and (= y1 "") ... (= yn ""))
    1985 [ +  + ][ +  + ]:         18 :         if (node[0] == empty && allEmptyEqs)
         [ +  - ][ +  + ]
                 [ -  - ]
    1986                 :            :         {
    1987                 :         12 :           std::vector<Node> emptyNodesList(emptyNodes.begin(), emptyNodes.end());
    1988                 :         12 :           Node nn1 = strings::utils::mkConcat(emptyNodesList, stype);
    1989                 :         12 :           if (nn1 != node[1] || nn2 != node[2])
    1990                 :            :           {
    1991                 :          8 :             Node res = d_nm->mkNode(Kind::STRING_REPLACE, node[0], nn1, nn2);
    1992                 :          4 :             debugExtendedRewrite(node, res, "RPL_EMP_CNTS_SUBSTS");
    1993                 :          4 :             return res;
    1994                 :          4 :           }
    1995 [ +  + ][ +  + ]:         16 :         }
    1996                 :            : 
    1997         [ +  + ]:         14 :         if (nn2 != node[2])
    1998                 :            :         {
    1999                 :          8 :           Node res = d_nm->mkNode(Kind::STRING_REPLACE, node[0], node[1], nn2);
    2000                 :          4 :           debugExtendedRewrite(node, res, "RPL_CNTS_SUBSTS");
    2001                 :          4 :           return res;
    2002                 :          4 :         }
    2003 [ +  + ][ +  + ]:         26 :       }
    2004 [ +  + ][ +  + ]:         35 :     }
                 [ +  + ]
    2005 [ +  + ][ +  + ]:        160 :   }
    2006         [ +  + ]:      11765 :   else if (k == Kind::STRING_CONTAINS)
    2007                 :            :   {
    2008         [ +  + ]:       5104 :     if (node[0].getKind() == Kind::STRING_REPLACE)
    2009                 :            :     {
    2010                 :         12 :       TypeNode stype = node[0].getType();
    2011                 :         12 :       Node empty = strings::Word::mkEmptyWord(stype);
    2012                 :         12 :       if (node[1].isConst() && node[0][1].isConst() && node[0][2].isConst())
    2013                 :            :       {
    2014                 :         12 :         if (node[1] != empty && node[0][1] != empty && node[0][2] != empty
    2015                 :         10 :             && !strings::Word::hasBidirectionalOverlap(node[1], node[0][1])
    2016                 :         12 :             && !strings::Word::hasBidirectionalOverlap(node[1], node[0][2]))
    2017                 :            :         {
    2018                 :            :           // (str.contains (str.replace x c1 c2) c3) ---> (str.contains x c3)
    2019                 :            :           // if there is no overlap between c1 and c3 and none between c2 and c3
    2020                 :          2 :           Node ret = d_nm->mkNode(Kind::STRING_CONTAINS, node[0][0], node[1]);
    2021                 :          1 :           debugExtendedRewrite(node, ret, "CTN_REPL_CNSTS_TO_CTN");
    2022                 :          1 :           return ret;
    2023                 :          1 :         }
    2024                 :            :       }
    2025                 :            :       // (str.contains (str.replace x y z) w) --->
    2026                 :            :       //   (str.contains (str.replace x y "") w)
    2027                 :            :       // if (str.contains z w) ---> false and (str.len w) = 1
    2028         [ +  + ]:         11 :       if (se.checkLengthOne(node[1]))
    2029                 :            :       {
    2030                 :         16 :         Node ctn = se.checkContains(node[0][2], node[1]);
    2031 [ +  + ][ +  - ]:          8 :         if (!ctn.isNull() && !ctn.getConst<bool>())
                 [ +  + ]
    2032                 :            :         {
    2033                 :            :           Node ret = d_nm->mkNode(
    2034                 :            :               Kind::STRING_CONTAINS,
    2035                 :          8 :               d_nm->mkNode(Kind::STRING_REPLACE, node[0][0], node[0][1], empty),
    2036                 :         16 :               node[1]);
    2037                 :          4 :           debugExtendedRewrite(node, ret, "CTN_REPL_SIMP_REPL");
    2038                 :          4 :           return ret;
    2039                 :          4 :         }
    2040         [ +  + ]:          8 :       }
    2041 [ +  + ][ +  + ]:         17 :     }
    2042                 :       5099 :     std::vector<Node> nc1;
    2043                 :       5099 :     strings::utils::getConcat(node[0], nc1);
    2044                 :       5099 :     std::vector<Node> nc2;
    2045                 :       5099 :     strings::utils::getConcat(node[1], nc2);
    2046                 :            : 
    2047                 :            :     // extended component-wise containment
    2048                 :       5099 :     std::vector<Node> nc1rb;
    2049                 :       5099 :     std::vector<Node> nc1re;
    2050         [ +  + ]:       5099 :     if (se.componentContainsExt(nc1, nc2, nc1rb, nc1re) != -1)
    2051                 :            :     {
    2052                 :         14 :       debugExtendedRewrite(node, d_true, "CTN_COMPONENT_EXT");
    2053                 :         14 :       return d_true;
    2054                 :            :     }
    2055                 :            : 
    2056         [ +  + ]:      10174 :     for (const Node& n : nc2)
    2057                 :            :     {
    2058                 :            :       // (str.contains x (str.++ w (str.replace x y x) z)) --->
    2059                 :            :       //   (= x (str.++ w (str.replace x y x) z))
    2060                 :            :       //
    2061                 :       5092 :       if (n.getKind() == Kind::STRING_REPLACE && node[0] == n[0]
    2062                 :       5092 :           && node[0] == n[2])
    2063                 :            :       {
    2064                 :          0 :         Node ret = d_nm->mkNode(Kind::EQUAL, node[0], node[1]);
    2065                 :          0 :         debugExtendedRewrite(node, ret, "CTN_REPL_SELF");
    2066                 :          0 :         return ret;
    2067                 :          0 :       }
    2068                 :            :     }
    2069 [ +  + ][ +  + ]:       5141 :   }
         [ +  + ][ +  + ]
    2070                 :            :   // otherwise, the use of recursive approximations and rewriting via
    2071                 :            :   // the entailment utilities may make a standard conditional rewrite
    2072                 :            :   // applicable.
    2073                 :      18213 :   RewriteResponse rr = sr.postRewrite(node);
    2074         [ +  + ]:      18213 :   if (rr.d_node != node)
    2075                 :            :   {
    2076                 :         13 :     return rr.d_node;
    2077                 :            :   }
    2078                 :            : 
    2079                 :      18200 :   return Node::null();
    2080                 :      18582 : }
    2081                 :            : 
    2082                 :        330 : Node ExtendedRewriter::extendedRewriteSets(const Node& node) const
    2083                 :            : {
    2084 [ +  + ][ +  + ]:        355 :   if (node.getKind() == Kind::SET_MINUS && node[1].getKind() == Kind::SET_MINUS
                 [ -  - ]
    2085                 :        355 :       && node[1][0] == node[0])
    2086                 :            :   {
    2087                 :            :     // Note this cannot be a rewrite rule or a ppRewrite, since it impacts the
    2088                 :            :     // cardinality graph. In particular, if we internally inspect (set.minus A
    2089                 :            :     // (setminus A B)), for instance if we are splitting the Venn regions of A
    2090                 :            :     // and (set.minus A B), then we should not transform this to an intersection
    2091                 :            :     // term. (set.minus A (set.minus A B)) = (set.inter A B)
    2092                 :          3 :     NodeManager* nm = d_nm;
    2093                 :          6 :     Node ret = nm->mkNode(Kind::SET_INTER, node[0], node[1][1]);
    2094                 :          3 :     debugExtendedRewrite(node, ret, "SET_MINUS_MINUS");
    2095                 :          3 :     return ret;
    2096                 :          3 :   }
    2097                 :        327 :   return Node::null();
    2098                 :            : }
    2099                 :            : 
    2100                 :     116315 : void ExtendedRewriter::debugExtendedRewrite(Node n,
    2101                 :            :                                             Node ret,
    2102                 :            :                                             const char* c) const
    2103                 :            : {
    2104                 :     232630 :   Assert(ret.isNull() || n.getType().isComparableTo(ret.getType()))
    2105 [ -  + ][ -  + ]:     116315 :       << "Extended rewrite does not preserve type: " << n << " --> " << ret;
                 [ -  - ]
    2106         [ -  + ]:     116315 :   if (TraceIsOn("q-ext-rewrite"))
    2107                 :            :   {
    2108         [ -  - ]:          0 :     if (!ret.isNull())
    2109                 :            :     {
    2110         [ -  - ]:          0 :       Trace("q-ext-rewrite-apply") << "sygus-extr : apply " << c << std::endl;
    2111         [ -  - ]:          0 :       Trace("q-ext-rewrite") << "sygus-extr : " << c << " : " << n
    2112                 :          0 :                              << " rewrites to " << ret << std::endl;
    2113                 :            :     }
    2114                 :            :   }
    2115                 :     116315 : }
    2116                 :            : 
    2117                 :            : }  // namespace quantifiers
    2118                 :            : }  // namespace theory
    2119                 :            : }  // namespace cvc5::internal

Generated by: LCOV version 1.14