LCOV - code coverage report
Current view: top level - buildbot/coverage/build/src/theory/strings - regexp_operation.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 288 1019 28.3 %
Date: 2025-01-09 12:37:31 Functions: 12 24 50.0 %
Branches: 135 610 22.1 %

           Branch data     Line data    Source code
       1                 :            : /******************************************************************************
       2                 :            :  * Top contributors (to current version):
       3                 :            :  *   Tianyi Liang, Andrew Reynolds, Aina Niemetz
       4                 :            :  *
       5                 :            :  * This file is part of the cvc5 project.
       6                 :            :  *
       7                 :            :  * Copyright (c) 2009-2024 by the authors listed in the file AUTHORS
       8                 :            :  * in the top-level source directory and their institutional affiliations.
       9                 :            :  * All rights reserved.  See the file COPYING in the top-level source
      10                 :            :  * directory for licensing information.
      11                 :            :  * ****************************************************************************
      12                 :            :  *
      13                 :            :  * Symbolic Regular Expresion Operations
      14                 :            :  */
      15                 :            : 
      16                 :            : #include "theory/strings/regexp_operation.h"
      17                 :            : 
      18                 :            : #include <sstream>
      19                 :            : 
      20                 :            : #include "expr/node_algorithm.h"
      21                 :            : #include "options/strings_options.h"
      22                 :            : #include "theory/rewriter.h"
      23                 :            : #include "theory/strings/regexp_entail.h"
      24                 :            : #include "theory/strings/theory_strings_utils.h"
      25                 :            : #include "theory/strings/word.h"
      26                 :            : #include "util/regexp.h"
      27                 :            : 
      28                 :            : using namespace cvc5::internal::kind;
      29                 :            : 
      30                 :            : namespace cvc5::internal {
      31                 :            : namespace theory {
      32                 :            : namespace strings {
      33                 :            : 
      34                 :      50038 : RegExpOpr::RegExpOpr(Env& env, SkolemCache* sc)
      35                 :            :     : EnvObj(env),
      36                 :          0 :       d_true(nodeManager()->mkConst(true)),
      37                 :          0 :       d_false(nodeManager()->mkConst(false)),
      38                 :            :       d_emptyRegexp(
      39                 :      50038 :           nodeManager()->mkNode(Kind::REGEXP_NONE, std::vector<Node>{})),
      40                 :      50038 :       d_zero(nodeManager()->mkConstInt(Rational(0))),
      41                 :      50038 :       d_one(nodeManager()->mkConstInt(Rational(1))),
      42                 :      50038 :       d_sigma(nodeManager()->mkNode(Kind::REGEXP_ALLCHAR, std::vector<Node>{})),
      43                 :     100076 :       d_sigma_star(nodeManager()->mkNode(Kind::REGEXP_STAR, d_sigma)),
      44                 :     250190 :       d_sc(sc)
      45                 :            : {
      46                 :      50038 :   d_emptyString = Word::mkEmptyWord(nodeManager()->stringType());
      47                 :            : 
      48                 :            :   d_emptySingleton =
      49                 :      50038 :       nodeManager()->mkNode(Kind::STRING_TO_REGEXP, d_emptyString);
      50                 :      50038 :   d_lastchar = options().strings.stringsAlphaCard - 1;
      51                 :      50038 : }
      52                 :            : 
      53                 :      49782 : RegExpOpr::~RegExpOpr() {}
      54                 :            : 
      55                 :       2720 : bool RegExpOpr::checkConstRegExp( Node r ) {
      56 [ -  + ][ -  + ]:       2720 :   Assert(r.getType().isRegExp());
                 [ -  - ]
      57         [ +  - ]:       5440 :   Trace("strings-regexp-cstre")
      58                 :       2720 :       << "RegExpOpr::checkConstRegExp /" << mkString(r) << "/" << std::endl;
      59                 :       2720 :   RegExpConstType rct = getRegExpConstType(r);
      60                 :       2720 :   return rct != RE_C_VARIABLE;
      61                 :            : }
      62                 :            : 
      63                 :       2734 : RegExpConstType RegExpOpr::getRegExpConstType(Node r)
      64                 :            : {
      65 [ -  + ][ -  + ]:       2734 :   Assert(r.getType().isRegExp());
                 [ -  - ]
      66                 :       2734 :   std::unordered_map<Node, RegExpConstType>::iterator it;
      67                 :       5468 :   std::vector<TNode> visit;
      68                 :       2734 :   TNode cur;
      69                 :       2734 :   visit.push_back(r);
      70                 :       4921 :   do
      71                 :            :   {
      72                 :       7655 :     cur = visit.back();
      73                 :       7655 :     visit.pop_back();
      74                 :       7655 :     it = d_constCache.find(cur);
      75                 :            : 
      76                 :       7655 :     Kind ck = cur.getKind();
      77         [ +  + ]:       7655 :     if (it == d_constCache.end())
      78                 :            :     {
      79         [ +  + ]:       2817 :       if (ck == Kind::STRING_TO_REGEXP)
      80                 :            :       {
      81                 :        918 :         Node tmp = rewrite(cur[0]);
      82                 :        918 :         d_constCache[cur] =
      83         [ +  + ]:        918 :             tmp.isConst() ? RE_C_CONCRETE_CONSTANT : RE_C_VARIABLE;
      84                 :            :       }
      85 [ +  + ][ +  + ]:       1899 :       else if (ck == Kind::REGEXP_ALLCHAR || ck == Kind::REGEXP_RANGE)
      86                 :            :       {
      87                 :        287 :         d_constCache[cur] = RE_C_CONSTANT;
      88                 :            :       }
      89         [ +  + ]:       1612 :       else if (!utils::isRegExpKind(ck))
      90                 :            :       {
      91                 :            :         // non-regular expression applications, e.g. function applications
      92                 :            :         // with regular expression return type are treated as variables.
      93                 :          4 :         d_constCache[cur] = RE_C_VARIABLE;
      94                 :            :       }
      95                 :            :       else
      96                 :            :       {
      97                 :       1608 :         d_constCache[cur] = RE_C_UNKNOWN;
      98                 :       1608 :         visit.push_back(cur);
      99                 :       1608 :         visit.insert(visit.end(), cur.begin(), cur.end());
     100                 :            :       }
     101                 :            :     }
     102         [ +  + ]:       4838 :     else if (it->second == RE_C_UNKNOWN)
     103                 :            :     {
     104                 :       1608 :       RegExpConstType ret = ck == Kind::REGEXP_COMPLEMENT
     105         [ +  + ]:       1608 :                                 ? RE_C_CONSTANT
     106                 :            :                                 : RE_C_CONCRETE_CONSTANT;
     107         [ +  + ]:       4921 :       for (const Node& cn : cur)
     108                 :            :       {
     109                 :       3313 :         it = d_constCache.find(cn);
     110 [ -  + ][ -  + ]:       3313 :         Assert(it != d_constCache.end());
                 [ -  - ]
     111         [ +  + ]:       3313 :         if (it->second > ret)
     112                 :            :         {
     113                 :        845 :           ret = it->second;
     114                 :            :         }
     115                 :            :       }
     116                 :       1608 :       d_constCache[cur] = ret;
     117                 :            :     }
     118         [ +  + ]:       7655 :   } while (!visit.empty());
     119 [ -  + ][ -  + ]:       2734 :   Assert(d_constCache.find(r) != d_constCache.end());
                 [ -  - ]
     120                 :       5468 :   return d_constCache[r];
     121                 :            : }
     122                 :            : 
     123                 :            : // 0-unknown, 1-yes, 2-no
     124                 :         24 : int RegExpOpr::delta( Node r, Node &exp ) {
     125                 :            :   std::map<Node, std::pair<int, Node> >::const_iterator itd =
     126                 :         24 :       d_delta_cache.find(r);
     127         [ +  + ]:         24 :   if (itd != d_delta_cache.end())
     128                 :            :   {
     129                 :            :     // already computed
     130                 :          8 :     exp = itd->second.second;
     131                 :          8 :     return itd->second.first;
     132                 :            :   }
     133         [ +  - ]:         16 :   Trace("regexp-delta") << "RegExpOpr::delta: " << r << std::endl;
     134                 :         16 :   int ret = 0;
     135                 :         16 :   NodeManager* nm = nodeManager();
     136                 :         16 :   Kind k = r.getKind();
     137 [ -  + ][ +  - ]:         16 :   switch (k)
         [ -  - ][ -  - ]
     138                 :            :   {
     139                 :          0 :     case Kind::REGEXP_NONE:
     140                 :            :     case Kind::REGEXP_ALLCHAR:
     141                 :            :     case Kind::REGEXP_RANGE:
     142                 :            :     {
     143                 :            :       // does not contain empty string
     144                 :          0 :       ret = 2;
     145                 :          0 :       break;
     146                 :            :     }
     147                 :          8 :     case Kind::STRING_TO_REGEXP:
     148                 :            :     {
     149                 :         24 :       Node tmp = rewrite(r[0]);
     150         [ +  - ]:          8 :       if (tmp.isConst())
     151                 :            :       {
     152         [ +  - ]:          8 :         if (tmp == d_emptyString)
     153                 :            :         {
     154                 :          8 :           ret = 1;
     155                 :            :         } else {
     156                 :          0 :           ret = 2;
     157                 :            :         }
     158                 :            :       }
     159                 :            :       else
     160                 :            :       {
     161                 :          0 :         ret = 0;
     162         [ -  - ]:          0 :         if (tmp.getKind() == Kind::STRING_CONCAT)
     163                 :            :         {
     164         [ -  - ]:          0 :           for (const Node& tmpc : tmp)
     165                 :            :           {
     166         [ -  - ]:          0 :             if (tmpc.isConst())
     167                 :            :             {
     168                 :          0 :               ret = 2;
     169                 :          0 :               break;
     170                 :            :             }
     171                 :            :           }
     172                 :            :         }
     173         [ -  - ]:          0 :         if (ret == 0)
     174                 :            :         {
     175                 :          0 :           exp = r[0].eqNode(d_emptyString);
     176                 :            :         }
     177                 :            :       }
     178                 :          8 :       break;
     179                 :            :     }
     180                 :          8 :     case Kind::REGEXP_CONCAT:
     181                 :            :     case Kind::REGEXP_UNION:
     182                 :            :     case Kind::REGEXP_INTER:
     183                 :            :     {
     184                 :            :       // has there been an unknown child?
     185                 :          8 :       bool hasUnknownChild = false;
     186                 :         16 :       std::vector<Node> vec;
     187         [ +  - ]:          8 :       int checkTmp = k == Kind::REGEXP_UNION ? 1 : 2;
     188         [ +  - ]:          8 :       int retTmp = k == Kind::REGEXP_UNION ? 2 : 1;
     189         [ +  - ]:          8 :       for (const Node& rc : r)
     190                 :            :       {
     191                 :          8 :         Node exp2;
     192                 :          8 :         int tmp = delta(rc, exp2);
     193         [ +  - ]:          8 :         if (tmp == checkTmp)
     194                 :            :         {
     195                 :            :           // return is implied by the child's return value
     196                 :          8 :           ret = checkTmp;
     197                 :          8 :           break;
     198                 :            :         }
     199         [ -  - ]:          0 :         else if (tmp == 0)
     200                 :            :         {
     201                 :            :           // unknown if child contains empty string
     202                 :          0 :           Assert(!exp2.isNull());
     203                 :          0 :           vec.push_back(exp2);
     204                 :          0 :           hasUnknownChild = true;
     205                 :            :         }
     206                 :            :       }
     207         [ -  + ]:          8 :       if (ret != checkTmp)
     208                 :            :       {
     209         [ -  - ]:          0 :         if (!hasUnknownChild)
     210                 :            :         {
     211                 :          0 :           ret = retTmp;
     212                 :            :         } else {
     213         [ -  - ]:          0 :           Kind kr = k == Kind::REGEXP_UNION ? Kind::OR : Kind::AND;
     214         [ -  - ]:          0 :           exp = vec.size() == 1 ? vec[0] : nm->mkNode(kr, vec);
     215                 :            :         }
     216                 :            :       }
     217                 :          8 :       break;
     218                 :            :     }
     219                 :          0 :     case Kind::REGEXP_STAR:
     220                 :            :     case Kind::REGEXP_OPT:
     221                 :            :     {
     222                 :            :       // contains empty string
     223                 :          0 :       ret = 1;
     224                 :          0 :       break;
     225                 :            :     }
     226                 :          0 :     case Kind::REGEXP_PLUS:
     227                 :            :     {
     228                 :          0 :       ret = delta(r[0], exp);
     229                 :          0 :       break;
     230                 :            :     }
     231                 :          0 :     case Kind::REGEXP_LOOP:
     232                 :            :     {
     233                 :          0 :       uint32_t lo = utils::getLoopMinOccurrences(r);
     234         [ -  - ]:          0 :       if (lo == 0)
     235                 :            :       {
     236                 :          0 :         ret = 1;
     237                 :            :       }
     238                 :            :       else
     239                 :            :       {
     240                 :          0 :         ret = delta(r[0], exp);
     241                 :            :       }
     242                 :          0 :       break;
     243                 :            :     }
     244                 :          0 :     case Kind::REGEXP_COMPLEMENT:
     245                 :            :     {
     246                 :          0 :       int tmp = delta(r[0], exp);
     247                 :            :       // flip the result if known
     248         [ -  - ]:          0 :       ret = tmp == 0 ? 0 : (3 - tmp);
     249         [ -  - ]:          0 :       exp = exp.isNull() ? exp : exp.negate();
     250                 :          0 :       break;
     251                 :            :     }
     252                 :          0 :     default:
     253                 :            :     {
     254                 :          0 :       Assert(!utils::isRegExpKind(k));
     255                 :          0 :       break;
     256                 :            :     }
     257                 :            :   }
     258         [ -  + ]:         16 :   if (!exp.isNull())
     259                 :            :   {
     260                 :          0 :     exp = rewrite(exp);
     261                 :            :   }
     262                 :         16 :   std::pair<int, Node> p(ret, exp);
     263                 :         16 :   d_delta_cache[r] = p;
     264         [ +  - ]:         32 :   Trace("regexp-delta") << "RegExpOpr::delta returns " << ret << " for " << r
     265                 :         16 :                         << ", expr = " << exp << std::endl;
     266                 :         16 :   return ret;
     267                 :            : }
     268                 :            : 
     269                 :            : // 0-unknown, 1-yes, 2-no
     270                 :         48 : int RegExpOpr::derivativeS(Node r, cvc5::internal::String c, Node& retNode)
     271                 :            : {
     272 [ -  + ][ -  + ]:         48 :   Assert(c.size() < 2);
                 [ -  - ]
     273                 :         48 :   Trace("regexp-derive") << "RegExp-derive starts with /" << mkString( r ) << "/, c=" << c << std::endl;
     274                 :            : 
     275                 :         48 :   int ret = 1;
     276                 :         48 :   retNode = d_emptyRegexp;
     277                 :         48 :   NodeManager* nm = nodeManager();
     278                 :            : 
     279                 :         96 :   PairNodeStr dv = std::make_pair( r, c );
     280         [ +  + ]:         48 :   if( d_deriv_cache.find( dv ) != d_deriv_cache.end() ) {
     281                 :          8 :     retNode = d_deriv_cache[dv].first;
     282                 :          8 :     ret = d_deriv_cache[dv].second;
     283                 :            :   }
     284         [ -  + ]:         40 :   else if (c.empty())
     285                 :            :   {
     286                 :          0 :     Node expNode;
     287                 :          0 :     ret = delta( r, expNode );
     288         [ -  - ]:          0 :     if(ret == 0) {
     289                 :          0 :       retNode = nodeManager()->mkNode(Kind::ITE, expNode, r, d_emptyRegexp);
     290         [ -  - ]:          0 :     } else if(ret == 1) {
     291                 :          0 :       retNode = r;
     292                 :            :     }
     293                 :          0 :     std::pair< Node, int > p(retNode, ret);
     294                 :          0 :     d_deriv_cache[dv] = p;
     295                 :            :   } else {
     296 [ -  - ][ -  + ]:         40 :     switch( r.getKind() ) {
         [ +  + ][ -  + ]
            [ -  - ][ - ]
     297                 :          0 :       case Kind::REGEXP_NONE:
     298                 :            :       {
     299                 :          0 :         ret = 2;
     300                 :          0 :         break;
     301                 :            :       }
     302                 :          0 :       case Kind::REGEXP_ALLCHAR:
     303                 :            :       {
     304                 :          0 :         retNode = d_emptySingleton;
     305                 :          0 :         break;
     306                 :            :       }
     307                 :          0 :       case Kind::REGEXP_RANGE:
     308                 :            :       {
     309                 :          0 :         cvc5::internal::String a = r[0].getConst<String>();
     310                 :          0 :         cvc5::internal::String b = r[1].getConst<String>();
     311                 :          0 :         retNode = (a <= c && c <= b) ? d_emptySingleton : d_emptyRegexp;
     312                 :          0 :         break;
     313                 :            :       }
     314                 :         16 :       case Kind::STRING_TO_REGEXP:
     315                 :            :       {
     316                 :         48 :         Node tmp = rewrite(r[0]);
     317         [ +  - ]:         16 :         if(tmp.isConst()) {
     318         [ +  + ]:         16 :           if(tmp == d_emptyString) {
     319                 :          8 :             ret = 2;
     320                 :            :           } else {
     321         [ -  + ]:          8 :             if (tmp.getConst<String>().front() == c.front())
     322                 :            :             {
     323                 :            :               retNode =
     324                 :          0 :                   nm->mkNode(Kind::STRING_TO_REGEXP,
     325                 :          0 :                              Word::getLength(tmp) == 1 ? d_emptyString
     326                 :          0 :                                                        : Word::substr(tmp, 1));
     327                 :            :             } else {
     328                 :          8 :               ret = 2;
     329                 :            :             }
     330                 :            :           }
     331                 :            :         } else {
     332                 :          0 :           ret = 0;
     333                 :          0 :           Node rest;
     334         [ -  - ]:          0 :           if (tmp.getKind() == Kind::STRING_CONCAT)
     335                 :            :           {
     336                 :          0 :             Node t2 = tmp[0];
     337         [ -  - ]:          0 :             if(t2.isConst()) {
     338         [ -  - ]:          0 :               if (t2.getConst<String>().front() == c.front())
     339                 :            :               {
     340                 :            :                 Node n = nm->mkNode(Kind::STRING_TO_REGEXP,
     341                 :          0 :                                     Word::getLength(tmp) == 1
     342                 :          0 :                                         ? d_emptyString
     343                 :          0 :                                         : Word::substr(tmp, 1));
     344                 :          0 :                 std::vector< Node > vec_nodes;
     345                 :          0 :                 vec_nodes.push_back(n);
     346         [ -  - ]:          0 :                 for(unsigned i=1; i<tmp.getNumChildren(); i++) {
     347                 :          0 :                   vec_nodes.push_back(tmp[i]);
     348                 :            :                 }
     349                 :          0 :                 retNode = nm->mkNode(Kind::REGEXP_CONCAT, vec_nodes);
     350                 :          0 :                 ret = 1;
     351                 :            :               } else {
     352                 :          0 :                 ret = 2;
     353                 :            :               }
     354                 :            :             } else {
     355                 :          0 :               tmp = tmp[0];
     356                 :          0 :               std::vector< Node > vec_nodes;
     357         [ -  - ]:          0 :               for(unsigned i=1; i<tmp.getNumChildren(); i++) {
     358                 :          0 :                 vec_nodes.push_back(tmp[i]);
     359                 :            :               }
     360                 :          0 :               rest = nm->mkNode(Kind::REGEXP_CONCAT, vec_nodes);
     361                 :            :             }
     362                 :            :           }
     363         [ -  - ]:          0 :           if(ret == 0) {
     364                 :            :             Node sk = NodeManager::mkDummySkolem(
     365                 :          0 :                 "rsp", nm->stringType(), "Split RegExp");
     366                 :          0 :             retNode = nm->mkNode(Kind::STRING_TO_REGEXP, sk);
     367         [ -  - ]:          0 :             if(!rest.isNull()) {
     368                 :          0 :               retNode = rewrite(nm->mkNode(Kind::REGEXP_CONCAT, retNode, rest));
     369                 :            :             }
     370                 :            :             Node exp =
     371                 :          0 :                 tmp.eqNode(nm->mkNode(Kind::STRING_CONCAT, nm->mkConst(c), sk));
     372                 :            :             retNode =
     373                 :          0 :                 rewrite(nm->mkNode(Kind::ITE, exp, retNode, d_emptyRegexp));
     374                 :            :           }
     375                 :            :         }
     376                 :         16 :         break;
     377                 :            :       }
     378                 :          8 :       case Kind::REGEXP_CONCAT:
     379                 :            :       {
     380                 :         16 :         std::vector< Node > vec_nodes;
     381                 :         16 :         std::vector< Node > delta_nodes;
     382                 :         16 :         Node dnode = d_true;
     383         [ +  + ]:         24 :         for(unsigned i=0; i<r.getNumChildren(); ++i) {
     384                 :         16 :           Node dc;
     385                 :         16 :           Node exp2;
     386                 :         16 :           int rt = derivativeS(r[i], c, dc);
     387         [ -  + ]:         16 :           if(rt != 2) {
     388         [ -  - ]:          0 :             if(rt == 0) {
     389                 :          0 :               ret = 0;
     390                 :            :             }
     391                 :          0 :             std::vector< Node > vec_nodes2;
     392         [ -  - ]:          0 :             if(dc != d_emptySingleton) {
     393                 :          0 :               vec_nodes2.push_back( dc );
     394                 :            :             }
     395         [ -  - ]:          0 :             for(unsigned j=i+1; j<r.getNumChildren(); ++j) {
     396         [ -  - ]:          0 :               if(r[j] != d_emptySingleton) {
     397                 :          0 :                 vec_nodes2.push_back( r[j] );
     398                 :            :               }
     399                 :            :             }
     400                 :          0 :             Node tmp = vec_nodes2.size() == 0
     401                 :          0 :                            ? d_emptySingleton
     402                 :          0 :                            : vec_nodes2.size() == 1
     403                 :          0 :                                  ? vec_nodes2[0]
     404                 :            :                                  : nodeManager()->mkNode(Kind::REGEXP_CONCAT,
     405                 :          0 :                                                          vec_nodes2);
     406         [ -  - ]:          0 :             if(dnode != d_true) {
     407                 :          0 :               tmp = rewrite(nm->mkNode(Kind::ITE, dnode, tmp, d_emptyRegexp));
     408                 :          0 :               ret = 0;
     409                 :            :             }
     410         [ -  - ]:          0 :             if(std::find(vec_nodes.begin(), vec_nodes.end(), tmp) == vec_nodes.end()) {
     411                 :          0 :               vec_nodes.push_back( tmp );
     412                 :            :             }
     413                 :            :           }
     414                 :         16 :           Node exp3;
     415                 :         16 :           int rt2 = delta( r[i], exp3 );
     416         [ -  + ]:         16 :           if( rt2 == 0 ) {
     417                 :          0 :             dnode = rewrite(nm->mkNode(Kind::AND, dnode, exp3));
     418         [ -  + ]:         16 :           } else if( rt2 == 2 ) {
     419                 :          0 :             break;
     420                 :            :           }
     421                 :            :         }
     422                 :            :         retNode =
     423                 :          8 :             vec_nodes.size() == 0
     424 [ +  - ][ -  - ]:         16 :                 ? d_emptyRegexp
     425                 :          0 :                 : (vec_nodes.size() == 1
     426                 :          0 :                        ? vec_nodes[0]
     427                 :          8 :                        : nodeManager()->mkNode(Kind::REGEXP_UNION, vec_nodes));
     428         [ +  - ]:          8 :         if(retNode == d_emptyRegexp) {
     429                 :          8 :           ret = 2;
     430                 :            :         }
     431                 :          8 :         break;
     432                 :            :       }
     433                 :          8 :       case Kind::REGEXP_UNION:
     434                 :            :       {
     435                 :         16 :         std::vector< Node > vec_nodes;
     436         [ +  + ]:         24 :         for(unsigned i=0; i<r.getNumChildren(); ++i) {
     437                 :         32 :           Node dc;
     438                 :         16 :           int rt = derivativeS(r[i], c, dc);
     439         [ -  + ]:         16 :           if(rt == 0) {
     440                 :          0 :             ret = 0;
     441                 :            :           }
     442         [ -  + ]:         16 :           if(rt != 2) {
     443         [ -  - ]:          0 :             if(std::find(vec_nodes.begin(), vec_nodes.end(), dc) == vec_nodes.end()) {
     444                 :          0 :               vec_nodes.push_back( dc );
     445                 :            :             }
     446                 :            :           }
     447                 :            :           //Trace("regexp-derive") << "RegExp-derive OR R[" << i << "] " << mkString(r[i]) << " returns " << mkString(dc) << std::endl;
     448                 :            :         }
     449                 :            :         retNode =
     450                 :          8 :             vec_nodes.size() == 0
     451 [ +  - ][ -  - ]:         16 :                 ? d_emptyRegexp
     452                 :          0 :                 : (vec_nodes.size() == 1
     453                 :          0 :                        ? vec_nodes[0]
     454                 :          8 :                        : nodeManager()->mkNode(Kind::REGEXP_UNION, vec_nodes));
     455         [ +  - ]:          8 :         if(retNode == d_emptyRegexp) {
     456                 :          8 :           ret = 2;
     457                 :            :         }
     458                 :          8 :         break;
     459                 :            :       }
     460                 :          0 :       case Kind::REGEXP_INTER:
     461                 :            :       {
     462                 :          0 :         bool flag = true;
     463                 :          0 :         bool flag_sg = false;
     464                 :          0 :         std::vector< Node > vec_nodes;
     465         [ -  - ]:          0 :         for(unsigned i=0; i<r.getNumChildren(); ++i) {
     466                 :          0 :           Node dc;
     467                 :          0 :           int rt = derivativeS(r[i], c, dc);
     468         [ -  - ]:          0 :           if(rt == 0) {
     469                 :          0 :             ret = 0;
     470         [ -  - ]:          0 :           } else if(rt == 2) {
     471                 :          0 :             flag = false;
     472                 :          0 :             break;
     473                 :            :           }
     474         [ -  - ]:          0 :           if(dc == d_sigma_star) {
     475                 :          0 :             flag_sg = true;
     476                 :            :           } else {
     477         [ -  - ]:          0 :             if(std::find(vec_nodes.begin(), vec_nodes.end(), dc) == vec_nodes.end()) {
     478                 :          0 :               vec_nodes.push_back( dc );
     479                 :            :             }
     480                 :            :           }
     481                 :            :         }
     482         [ -  - ]:          0 :         if(flag) {
     483 [ -  - ][ -  - ]:          0 :           if(vec_nodes.size() == 0 && flag_sg) {
                 [ -  - ]
     484                 :          0 :             retNode = d_sigma_star;
     485                 :            :           } else {
     486                 :          0 :             retNode = vec_nodes.size() == 0
     487                 :          0 :                           ? d_emptyRegexp
     488                 :          0 :                           : (vec_nodes.size() == 1
     489                 :          0 :                                  ? vec_nodes[0]
     490                 :            :                                  : nodeManager()->mkNode(Kind::REGEXP_INTER,
     491                 :          0 :                                                          vec_nodes));
     492         [ -  - ]:          0 :             if(retNode == d_emptyRegexp) {
     493                 :          0 :               ret = 2;
     494                 :            :             }
     495                 :            :           }
     496                 :            :         } else {
     497                 :          0 :           retNode = d_emptyRegexp;
     498                 :          0 :           ret = 2;
     499                 :            :         }
     500                 :          0 :         break;
     501                 :            :       }
     502                 :          8 :       case Kind::REGEXP_STAR:
     503                 :            :       {
     504                 :         16 :         Node dc;
     505                 :          8 :         ret = derivativeS(r[0], c, dc);
     506                 :            :         retNode =
     507                 :          8 :             dc == d_emptyRegexp
     508                 :         16 :                 ? dc
     509         [ -  - ]:          0 :                 : (dc == d_emptySingleton
     510                 :            :                        ? r
     511                 :          8 :                        : nodeManager()->mkNode(Kind::REGEXP_CONCAT, dc, r));
     512                 :          8 :         break;
     513                 :            :       }
     514                 :          0 :       case Kind::REGEXP_LOOP:
     515                 :            :       {
     516                 :          0 :         uint32_t l = utils::getLoopMinOccurrences(r);
     517                 :          0 :         uint32_t u = utils::getLoopMaxOccurrences(r);
     518 [ -  - ][ -  - ]:          0 :         if (l == u && l == 0)
     519                 :            :         {
     520                 :          0 :           ret = 2;
     521                 :            :           //retNode = d_emptyRegexp;
     522                 :            :         } else {
     523                 :          0 :           Node dc;
     524                 :          0 :           ret = derivativeS(r[0], c, dc);
     525         [ -  - ]:          0 :           if(dc==d_emptyRegexp) {
     526         [ -  - ]:          0 :             Node lop = nm->mkConst(RegExpLoop(l == 0 ? 0 : (l - 1), u - 1));
     527                 :          0 :             Node r2 = nm->mkNode(Kind::REGEXP_LOOP, lop, r[0]);
     528                 :          0 :             retNode = dc == d_emptySingleton
     529                 :          0 :                           ? r2
     530                 :          0 :                           : nodeManager()->mkNode(Kind::REGEXP_CONCAT, dc, r2);
     531                 :            :           } else {
     532                 :          0 :             retNode = d_emptyRegexp;
     533                 :            :           }
     534                 :            :         }
     535                 :          0 :         break;
     536                 :            :       }
     537                 :          0 :       case Kind::REGEXP_COMPLEMENT:
     538                 :            :       {
     539                 :            :         // don't know result
     540                 :          0 :         return 0;
     541                 :            :         break;
     542                 :            :       }
     543                 :          0 :       default: {
     544                 :          0 :         Assert(!utils::isRegExpKind(r.getKind()));
     545                 :          0 :         return 0;
     546                 :            :         break;
     547                 :            :       }
     548                 :            :     }
     549         [ -  + ]:         40 :     if(retNode != d_emptyRegexp) {
     550                 :          0 :       retNode = rewrite(retNode);
     551                 :            :     }
     552                 :         80 :     std::pair< Node, int > p(retNode, ret);
     553                 :         40 :     d_deriv_cache[dv] = p;
     554                 :            :   }
     555                 :            : 
     556                 :         48 :   Trace("regexp-derive") << "RegExp-derive returns : /" << mkString( retNode ) << "/" << std::endl;
     557                 :         48 :   return ret;
     558                 :            : }
     559                 :            : 
     560                 :          0 : Node RegExpOpr::derivativeSingle(Node r, cvc5::internal::String c)
     561                 :            : {
     562                 :          0 :   Assert(c.size() < 2);
     563                 :          0 :   Trace("regexp-derive") << "RegExp-derive starts with /" << mkString( r ) << "/, c=" << c << std::endl;
     564                 :          0 :   Node retNode = d_emptyRegexp;
     565                 :          0 :   PairNodeStr dv = std::make_pair( r, c );
     566                 :          0 :   NodeManager* nm = nodeManager();
     567         [ -  - ]:          0 :   if( d_dv_cache.find( dv ) != d_dv_cache.end() ) {
     568                 :          0 :     retNode = d_dv_cache[dv];
     569                 :            :   }
     570         [ -  - ]:          0 :   else if (c.empty())
     571                 :            :   {
     572                 :          0 :     Node exp;
     573                 :          0 :     int tmp = delta( r, exp );
     574         [ -  - ]:          0 :     if(tmp == 0) {
     575                 :            :       // TODO variable
     576                 :          0 :       retNode = d_emptyRegexp;
     577         [ -  - ]:          0 :     } else if(tmp == 1) {
     578                 :          0 :       retNode = r;
     579                 :            :     } else {
     580                 :          0 :       retNode = d_emptyRegexp;
     581                 :            :     }
     582                 :            :   } else {
     583                 :          0 :     Kind k = r.getKind();
     584 [ -  - ][ -  - ]:          0 :     switch( k ) {
         [ -  - ][ -  - ]
                 [ -  - ]
     585                 :          0 :       case Kind::REGEXP_NONE:
     586                 :            :       {
     587                 :          0 :         retNode = d_emptyRegexp;
     588                 :          0 :         break;
     589                 :            :       }
     590                 :          0 :       case Kind::REGEXP_ALLCHAR:
     591                 :            :       {
     592                 :          0 :         retNode = nodeManager()->mkNode(Kind::STRING_TO_REGEXP, d_emptyString);
     593                 :          0 :         break;
     594                 :            :       }
     595                 :          0 :       case Kind::REGEXP_RANGE:
     596                 :            :       {
     597                 :          0 :         cvc5::internal::String a = r[0].getConst<String>();
     598                 :          0 :         cvc5::internal::String b = r[1].getConst<String>();
     599                 :          0 :         retNode = (a <= c && c <= b) ? d_emptySingleton : d_emptyRegexp;
     600                 :          0 :         break;
     601                 :            :       }
     602                 :          0 :       case Kind::STRING_TO_REGEXP:
     603                 :            :       {
     604         [ -  - ]:          0 :         if(r[0].isConst()) {
     605         [ -  - ]:          0 :           if(r[0] == d_emptyString) {
     606                 :          0 :             retNode = d_emptyRegexp;
     607                 :            :           } else {
     608         [ -  - ]:          0 :             if (r[0].getConst<String>().front() == c.front())
     609                 :            :             {
     610                 :          0 :               retNode = nm->mkNode(Kind::STRING_TO_REGEXP,
     611                 :          0 :                                    Word::getLength(r[0]) == 1
     612                 :          0 :                                        ? d_emptyString
     613                 :          0 :                                        : Word::substr(r[0], 1));
     614                 :            :             } else {
     615                 :          0 :               retNode = d_emptyRegexp;
     616                 :            :             }
     617                 :            :           }
     618                 :            :         } else {
     619                 :            :           // TODO variable
     620                 :          0 :           retNode = d_emptyRegexp;
     621                 :            :         }
     622                 :          0 :         break;
     623                 :            :       }
     624                 :          0 :       case Kind::REGEXP_CONCAT:
     625                 :            :       {
     626                 :            :         Node rees =
     627                 :          0 :             nodeManager()->mkNode(Kind::STRING_TO_REGEXP, d_emptyString);
     628                 :          0 :         std::vector< Node > vec_nodes;
     629         [ -  - ]:          0 :         for(unsigned i=0; i<r.getNumChildren(); ++i) {
     630                 :          0 :           Node dc = derivativeSingle(r[i], c);
     631         [ -  - ]:          0 :           if(dc != d_emptyRegexp) {
     632                 :          0 :             std::vector< Node > vec_nodes2;
     633         [ -  - ]:          0 :             if(dc != rees) {
     634                 :          0 :               vec_nodes2.push_back( dc );
     635                 :            :             }
     636         [ -  - ]:          0 :             for(unsigned j=i+1; j<r.getNumChildren(); ++j) {
     637         [ -  - ]:          0 :               if(r[j] != rees) {
     638                 :          0 :                 vec_nodes2.push_back( r[j] );
     639                 :            :               }
     640                 :            :             }
     641                 :          0 :             Node tmp = vec_nodes2.size() == 0
     642                 :            :                            ? rees
     643                 :          0 :                            : vec_nodes2.size() == 1
     644                 :          0 :                                  ? vec_nodes2[0]
     645                 :            :                                  : nodeManager()->mkNode(Kind::REGEXP_CONCAT,
     646                 :          0 :                                                          vec_nodes2);
     647         [ -  - ]:          0 :             if(std::find(vec_nodes.begin(), vec_nodes.end(), tmp) == vec_nodes.end()) {
     648                 :          0 :               vec_nodes.push_back( tmp );
     649                 :            :             }
     650                 :            :           }
     651                 :          0 :           Node exp;
     652         [ -  - ]:          0 :           if( delta( r[i], exp ) != 1 ) {
     653                 :          0 :             break;
     654                 :            :           }
     655                 :            :         }
     656                 :            :         retNode =
     657                 :          0 :             vec_nodes.size() == 0
     658                 :          0 :                 ? d_emptyRegexp
     659                 :          0 :                 : (vec_nodes.size() == 1
     660                 :          0 :                        ? vec_nodes[0]
     661                 :          0 :                        : nodeManager()->mkNode(Kind::REGEXP_UNION, vec_nodes));
     662                 :          0 :         break;
     663                 :            :       }
     664                 :          0 :       case Kind::REGEXP_UNION:
     665                 :            :       {
     666                 :          0 :         std::vector< Node > vec_nodes;
     667         [ -  - ]:          0 :         for(unsigned i=0; i<r.getNumChildren(); ++i) {
     668                 :          0 :           Node dc = derivativeSingle(r[i], c);
     669         [ -  - ]:          0 :           if(dc != d_emptyRegexp) {
     670         [ -  - ]:          0 :             if(std::find(vec_nodes.begin(), vec_nodes.end(), dc) == vec_nodes.end()) {
     671                 :          0 :               vec_nodes.push_back( dc );
     672                 :            :             }
     673                 :            :           }
     674                 :            :           //Trace("regexp-derive") << "RegExp-derive OR R[" << i << "] /" << mkString(r[i]) << "/ returns /" << mkString(dc) << "/" << std::endl;
     675                 :            :         }
     676                 :            :         retNode =
     677                 :          0 :             vec_nodes.size() == 0
     678                 :          0 :                 ? d_emptyRegexp
     679                 :          0 :                 : (vec_nodes.size() == 1
     680                 :          0 :                        ? vec_nodes[0]
     681                 :          0 :                        : nodeManager()->mkNode(Kind::REGEXP_UNION, vec_nodes));
     682                 :          0 :         break;
     683                 :            :       }
     684                 :          0 :       case Kind::REGEXP_INTER:
     685                 :            :       {
     686                 :          0 :         bool flag = true;
     687                 :          0 :         bool flag_sg = false;
     688                 :          0 :         std::vector< Node > vec_nodes;
     689         [ -  - ]:          0 :         for(unsigned i=0; i<r.getNumChildren(); ++i) {
     690                 :          0 :           Node dc = derivativeSingle(r[i], c);
     691         [ -  - ]:          0 :           if(dc != d_emptyRegexp) {
     692         [ -  - ]:          0 :             if(dc == d_sigma_star) {
     693                 :          0 :               flag_sg = true;
     694                 :            :             } else {
     695         [ -  - ]:          0 :               if(std::find(vec_nodes.begin(), vec_nodes.end(), dc) == vec_nodes.end()) {
     696                 :          0 :                 vec_nodes.push_back( dc );
     697                 :            :               }
     698                 :            :             }
     699                 :            :           } else {
     700                 :          0 :             flag = false;
     701                 :          0 :             break;
     702                 :            :           }
     703                 :            :         }
     704         [ -  - ]:          0 :         if(flag) {
     705 [ -  - ][ -  - ]:          0 :           if(vec_nodes.size() == 0 && flag_sg) {
                 [ -  - ]
     706                 :          0 :             retNode = d_sigma_star;
     707                 :            :           } else {
     708                 :          0 :             retNode = vec_nodes.size() == 0
     709                 :          0 :                           ? d_emptyRegexp
     710                 :          0 :                           : (vec_nodes.size() == 1
     711                 :          0 :                                  ? vec_nodes[0]
     712                 :            :                                  : nodeManager()->mkNode(Kind::REGEXP_INTER,
     713                 :          0 :                                                          vec_nodes));
     714                 :            :           }
     715                 :            :         } else {
     716                 :          0 :           retNode = d_emptyRegexp;
     717                 :            :         }
     718                 :          0 :         break;
     719                 :            :       }
     720                 :          0 :       case Kind::REGEXP_STAR:
     721                 :            :       {
     722                 :          0 :         Node dc = derivativeSingle(r[0], c);
     723         [ -  - ]:          0 :         if(dc != d_emptyRegexp) {
     724                 :          0 :           retNode = dc == d_emptySingleton
     725                 :          0 :                         ? r
     726                 :          0 :                         : nodeManager()->mkNode(Kind::REGEXP_CONCAT, dc, r);
     727                 :            :         } else {
     728                 :          0 :           retNode = d_emptyRegexp;
     729                 :            :         }
     730                 :          0 :         break;
     731                 :            :       }
     732                 :          0 :       case Kind::REGEXP_LOOP:
     733                 :            :       {
     734                 :          0 :         uint32_t l = utils::getLoopMinOccurrences(r);
     735                 :          0 :         uint32_t u = utils::getLoopMaxOccurrences(r);
     736 [ -  - ][ -  - ]:          0 :         if (l == u || l == 0)
     737                 :            :         {
     738                 :          0 :           retNode = d_emptyRegexp;
     739                 :            :         } else {
     740                 :          0 :           Node dc = derivativeSingle(r[0], c);
     741         [ -  - ]:          0 :           if(dc != d_emptyRegexp) {
     742         [ -  - ]:          0 :             Node lop = nm->mkConst(RegExpLoop(l == 0 ? 0 : (l - 1), u - 1));
     743                 :          0 :             Node r2 = nm->mkNode(Kind::REGEXP_LOOP, lop, r[0]);
     744                 :          0 :             retNode = dc == d_emptySingleton
     745                 :          0 :                           ? r2
     746                 :          0 :                           : nodeManager()->mkNode(Kind::REGEXP_CONCAT, dc, r2);
     747                 :            :           } else {
     748                 :          0 :             retNode = d_emptyRegexp;
     749                 :            :           }
     750                 :            :         }
     751                 :            :         //Trace("regexp-derive") << "RegExp-derive : REGEXP_LOOP returns /" << mkString(retNode) << "/" << std::endl;
     752                 :          0 :         break;
     753                 :            :       }
     754                 :          0 :       case Kind::REGEXP_COMPLEMENT:
     755                 :            :       default: {
     756                 :          0 :         Trace("strings-error") << "Unsupported term: " << mkString( r ) << " in derivative of RegExp." << std::endl;
     757                 :          0 :         Unreachable();
     758                 :            :         break;
     759                 :            :       }
     760                 :            :     }
     761         [ -  - ]:          0 :     if(retNode != d_emptyRegexp) {
     762                 :          0 :       retNode = rewrite(retNode);
     763                 :            :     }
     764                 :          0 :     d_dv_cache[dv] = retNode;
     765                 :            :   }
     766                 :          0 :   Trace("regexp-derive") << "RegExp-derive returns : /" << mkString( retNode ) << "/" << std::endl;
     767                 :          0 :   return retNode;
     768                 :            : }
     769                 :            : 
     770                 :          0 : void RegExpOpr::firstChars(Node r, std::set<unsigned> &pcset, SetNodes &pvset)
     771                 :            : {
     772                 :          0 :   Trace("regexp-fset") << "Start FSET(" << mkString(r) << ")" << std::endl;
     773                 :            :   std::map<Node, std::pair<std::set<unsigned>, SetNodes> >::const_iterator itr =
     774                 :          0 :       d_fset_cache.find(r);
     775         [ -  - ]:          0 :   if(itr != d_fset_cache.end()) {
     776                 :          0 :     pcset.insert((itr->second).first.begin(), (itr->second).first.end());
     777                 :          0 :     pvset.insert((itr->second).second.begin(), (itr->second).second.end());
     778                 :            :   } else {
     779                 :            :     // cset is code points
     780                 :          0 :     std::set<unsigned> cset;
     781                 :          0 :     SetNodes vset;
     782                 :          0 :     Kind k = r.getKind();
     783 [ -  - ][ -  - ]:          0 :     switch( k ) {
         [ -  - ][ -  - ]
                    [ - ]
     784                 :          0 :       case Kind::REGEXP_NONE:
     785                 :            :       {
     786                 :          0 :         break;
     787                 :            :       }
     788                 :          0 :       case Kind::REGEXP_RANGE:
     789                 :            :       {
     790                 :          0 :         unsigned a = r[0].getConst<String>().front();
     791                 :          0 :         unsigned b = r[1].getConst<String>().front();
     792                 :          0 :         Assert(a < b);
     793                 :          0 :         Assert(b < std::numeric_limits<unsigned>::max());
     794         [ -  - ]:          0 :         for (unsigned c = a; c <= b; c++)
     795                 :            :         {
     796                 :          0 :           cset.insert(c);
     797                 :            :         }
     798                 :          0 :         break;
     799                 :            :       }
     800                 :          0 :       case Kind::STRING_TO_REGEXP:
     801                 :            :       {
     802                 :          0 :         Node st = rewrite(r[0]);
     803         [ -  - ]:          0 :         if(st.isConst()) {
     804                 :          0 :           String s = st.getConst<String>();
     805         [ -  - ]:          0 :           if(s.size() != 0) {
     806                 :          0 :             unsigned sc = s.front();
     807                 :          0 :             cset.insert(sc);
     808                 :            :           }
     809                 :            :         }
     810         [ -  - ]:          0 :         else if (st.getKind() == Kind::STRING_CONCAT)
     811                 :            :         {
     812         [ -  - ]:          0 :           if(st[0].isConst()) {
     813                 :          0 :             String s = st[0].getConst<String>();
     814                 :          0 :             unsigned sc = s.front();
     815                 :          0 :             cset.insert(sc);
     816                 :            :           } else {
     817                 :          0 :             vset.insert( st[0] );
     818                 :            :           }
     819                 :            :         }
     820                 :            :         else
     821                 :            :         {
     822                 :          0 :           vset.insert(st);
     823                 :            :         }
     824                 :          0 :         break;
     825                 :            :       }
     826                 :          0 :       case Kind::REGEXP_CONCAT:
     827                 :            :       {
     828         [ -  - ]:          0 :         for(unsigned i=0; i<r.getNumChildren(); i++) {
     829                 :          0 :           firstChars(r[i], cset, vset);
     830                 :          0 :           Node n = r[i];
     831                 :          0 :           Node exp;
     832         [ -  - ]:          0 :           if (delta(n, exp) != 1)
     833                 :            :           {
     834                 :          0 :             break;
     835                 :            :           }
     836                 :            :         }
     837                 :          0 :         break;
     838                 :            :       }
     839                 :          0 :       case Kind::REGEXP_UNION:
     840                 :            :       {
     841         [ -  - ]:          0 :         for(unsigned i=0; i<r.getNumChildren(); i++) {
     842                 :          0 :           firstChars(r[i], cset, vset);
     843                 :            :         }
     844                 :          0 :         break;
     845                 :            :       }
     846                 :          0 :       case Kind::REGEXP_INTER:
     847                 :            :       {
     848                 :            :         //TODO: Overapproximation for now
     849                 :            :         //for(unsigned i=0; i<r.getNumChildren(); i++) {
     850                 :            :         // firstChars(r[i], cset, vset);
     851                 :            :         //}
     852                 :          0 :         firstChars(r[0], cset, vset);
     853                 :          0 :         break;
     854                 :            :       }
     855                 :          0 :       case Kind::REGEXP_STAR:
     856                 :            :       {
     857                 :          0 :         firstChars(r[0], cset, vset);
     858                 :          0 :         break;
     859                 :            :       }
     860                 :          0 :       case Kind::REGEXP_LOOP:
     861                 :            :       {
     862                 :          0 :         firstChars(r[0], cset, vset);
     863                 :          0 :         break;
     864                 :            :       }
     865                 :          0 :       case Kind::REGEXP_ALLCHAR:
     866                 :            :       case Kind::REGEXP_COMPLEMENT:
     867                 :            :       default: {
     868                 :            :         // we do not expect to call this function on regular expressions that
     869                 :            :         // aren't a standard regular expression kind. However, if we do, then
     870                 :            :         // the following code is conservative and says that the current
     871                 :            :         // regular expression can begin with any character.
     872                 :          0 :         Assert(utils::isRegExpKind(k));
     873                 :            :         // can start with any character
     874                 :          0 :         Assert(d_lastchar < std::numeric_limits<unsigned>::max());
     875         [ -  - ]:          0 :         for (unsigned i = 0; i <= d_lastchar; i++)
     876                 :            :         {
     877                 :          0 :           cset.insert(i);
     878                 :            :         }
     879                 :          0 :         break;
     880                 :            :       }
     881                 :            :     }
     882                 :          0 :     pcset.insert(cset.begin(), cset.end());
     883                 :          0 :     pvset.insert(vset.begin(), vset.end());
     884                 :          0 :     std::pair<std::set<unsigned>, SetNodes> p(cset, vset);
     885                 :          0 :     d_fset_cache[r] = p;
     886                 :            :   }
     887                 :            : 
     888         [ -  - ]:          0 :   if(TraceIsOn("regexp-fset")) {
     889                 :          0 :     Trace("regexp-fset") << "END FSET(" << mkString(r) << ") = {";
     890                 :          0 :     for (std::set<unsigned>::const_iterator it = pcset.begin();
     891         [ -  - ]:          0 :          it != pcset.end();
     892                 :          0 :          ++it)
     893                 :            :     {
     894         [ -  - ]:          0 :       if (it != pcset.begin())
     895                 :            :       {
     896         [ -  - ]:          0 :         Trace("regexp-fset") << ",";
     897                 :            :       }
     898         [ -  - ]:          0 :       Trace("regexp-fset") << (*it);
     899                 :            :       }
     900         [ -  - ]:          0 :     Trace("regexp-fset") << "}" << std::endl;
     901                 :            :   }
     902                 :          0 : }
     903                 :            : 
     904                 :        904 : Node RegExpOpr::simplify(Node t, bool polarity)
     905                 :            : {
     906         [ +  - ]:       1808 :   Trace("strings-regexp-simpl")
     907                 :        904 :       << "RegExpOpr::simplify: " << t << ", polarity=" << polarity << std::endl;
     908 [ -  + ][ -  + ]:        904 :   Assert(t.getKind() == Kind::STRING_IN_REGEXP);
                 [ -  - ]
     909         [ +  + ]:       1808 :   Node tlit = polarity ? t : t.notNode();
     910                 :       1808 :   Node conc;
     911                 :        904 :   std::map<Node, Node>::const_iterator itr = d_simpCache.find(tlit);
     912         [ +  + ]:        904 :   if (itr != d_simpCache.end())
     913                 :            :   {
     914                 :         10 :     return itr->second;
     915                 :            :   }
     916         [ +  + ]:        894 :   if (polarity)
     917                 :            :   {
     918                 :        814 :     std::vector<Node> newSkolems;
     919                 :        814 :     conc = reduceRegExpPos(nodeManager(), tlit, d_sc, newSkolems);
     920                 :            :   }
     921                 :            :   else
     922                 :            :   {
     923                 :            :     // see if we can use an optimized version of the reduction for re.++.
     924                 :        160 :     Node r = t[1];
     925         [ +  + ]:         80 :     if (r.getKind() == Kind::REGEXP_CONCAT)
     926                 :            :     {
     927                 :            :       // the index we are removing from the RE concatenation
     928                 :            :       bool isRev;
     929                 :            :       // As an optimization to the reduction, if we can determine that
     930                 :            :       // all strings in the language of R1 have the same length, say n,
     931                 :            :       // then the conclusion of the reduction is quantifier-free:
     932                 :            :       //    ~( substr(s,0,n) in R1 ) OR ~( substr(s,len(s)-n,n) in R2)
     933                 :        144 :       Node reLen = getRegExpConcatFixed(r, isRev);
     934         [ +  + ]:         72 :       if (!reLen.isNull())
     935                 :            :       {
     936                 :         66 :         conc = reduceRegExpNegConcatFixed(nodeManager(), tlit, reLen, isRev);
     937                 :            :       }
     938                 :            :     }
     939         [ +  + ]:         80 :     if (conc.isNull())
     940                 :            :     {
     941                 :         14 :       conc = reduceRegExpNeg(nodeManager(), tlit);
     942                 :            :     }
     943                 :            :   }
     944                 :        894 :   d_simpCache[tlit] = conc;
     945         [ +  - ]:       1788 :   Trace("strings-regexp-simpl")
     946                 :        894 :       << "RegExpOpr::simplify: returns " << conc << std::endl;
     947                 :        894 :   return conc;
     948                 :            : }
     949                 :            : 
     950                 :        107 : Node RegExpOpr::getRegExpConcatFixed(Node r, bool& isRev)
     951                 :            : {
     952 [ -  + ][ -  + ]:        107 :   Assert(r.getKind() == Kind::REGEXP_CONCAT);
                 [ -  - ]
     953                 :        107 :   isRev = false;
     954                 :        321 :   Node reLen = RegExpEntail::getFixedLengthForRegexp(r[0]);
     955         [ +  + ]:        107 :   if (!reLen.isNull())
     956                 :            :   {
     957                 :         58 :     return reLen;
     958                 :            :   }
     959                 :            :   // try from the opposite end
     960                 :         49 :   size_t indexE = r.getNumChildren() - 1;
     961                 :         49 :   reLen = RegExpEntail::getFixedLengthForRegexp(r[indexE]);
     962         [ +  + ]:         49 :   if (!reLen.isNull())
     963                 :            :   {
     964                 :         43 :     isRev = true;
     965                 :         43 :     return reLen;
     966                 :            :   }
     967                 :          6 :   return Node::null();
     968                 :            : }
     969                 :            : 
     970                 :         14 : Node RegExpOpr::reduceRegExpNeg(NodeManager* nm, Node mem)
     971                 :            : {
     972                 :         28 :   Assert(mem.getKind() == Kind::NOT
     973                 :            :          && mem[0].getKind() == Kind::STRING_IN_REGEXP);
     974                 :         28 :   Node s = mem[0][0];
     975                 :         28 :   Node r = mem[0][1];
     976                 :         14 :   Kind k = r.getKind();
     977                 :         28 :   Node zero = nm->mkConstInt(Rational(0));
     978                 :         14 :   Node conc;
     979         [ +  + ]:         14 :   if (k == Kind::REGEXP_CONCAT)
     980                 :            :   {
     981                 :            :     // do not use length entailment, call regular expression concat
     982                 :          6 :     Node reLen;
     983                 :          6 :     conc = reduceRegExpNegConcatFixed(nm, mem, reLen, false);
     984                 :            :   }
     985         [ +  + ]:          8 :   else if (k == Kind::REGEXP_STAR)
     986                 :            :   {
     987                 :         12 :     Node emp = Word::mkEmptyWord(s.getType());
     988                 :         12 :     Node lens = nm->mkNode(Kind::STRING_LENGTH, s);
     989                 :         12 :     Node sne = s.eqNode(emp).negate();
     990                 :         12 :     Node b1 = SkolemCache::mkIndexVar(nm, mem);
     991                 :         12 :     Node b1v = nm->mkNode(Kind::BOUND_VAR_LIST, b1);
     992                 :         18 :     Node g11n = nm->mkNode(Kind::LEQ, b1, zero);
     993                 :         18 :     Node g12n = nm->mkNode(Kind::LT, lens, b1);
     994                 :            :     // internal
     995                 :         18 :     Node s1 = utils::mkPrefix(s, b1);
     996                 :         18 :     Node s2 = utils::mkSuffix(s, b1);
     997                 :         18 :     Node s1r1 = nm->mkNode(Kind::STRING_IN_REGEXP, s1, r[0]).negate();
     998                 :         12 :     Node s2r2 = nm->mkNode(Kind::STRING_IN_REGEXP, s2, r).negate();
     999                 :            : 
    1000 [ +  + ][ -  - ]:         30 :     conc = nm->mkNode(Kind::OR, {g11n, g12n, s1r1, s2r2});
    1001                 :            :     // must mark as an internal quantifier
    1002                 :          6 :     conc = utils::mkForallInternal(nm, b1v, conc);
    1003                 :          6 :     conc = nm->mkNode(Kind::AND, sne, conc);
    1004                 :            :   }
    1005                 :            :   else
    1006                 :            :   {
    1007 [ -  + ][ -  + ]:          2 :     Assert(!utils::isRegExpKind(k));
                 [ -  - ]
    1008                 :            :   }
    1009                 :         28 :   return conc;
    1010                 :            : }
    1011                 :            : 
    1012                 :        128 : Node RegExpOpr::reduceRegExpNegConcatFixed(NodeManager* nm,
    1013                 :            :                                            Node mem,
    1014                 :            :                                            Node reLen,
    1015                 :            :                                            bool isRev)
    1016                 :            : {
    1017                 :        256 :   Assert(mem.getKind() == Kind::NOT
    1018                 :            :          && mem[0].getKind() == Kind::STRING_IN_REGEXP);
    1019                 :        256 :   Node s = mem[0][0];
    1020                 :        256 :   Node r = mem[0][1];
    1021 [ -  + ][ -  + ]:        128 :   Assert(r.getKind() == Kind::REGEXP_CONCAT);
                 [ -  - ]
    1022                 :        256 :   Node zero = nm->mkConstInt(Rational(0));
    1023                 :            :   // The following simplification states that
    1024                 :            :   //    ~( s in R1 ++ R2 ++... ++ Rn )
    1025                 :            :   // is equivalent to
    1026                 :            :   //    forall x.
    1027                 :            :   //      0 <= x <= len(s) =>
    1028                 :            :   //        ~(substr(s,0,x) in R1) OR ~(substr(s,x,len(s)-x) in R2 ++ ... ++ Rn)
    1029                 :            :   // Index is the child index of r that we are stripping off, which is either
    1030                 :            :   // from the beginning or the end.
    1031                 :        256 :   Node lens = nm->mkNode(Kind::STRING_LENGTH, s);
    1032                 :        256 :   Node b1;
    1033                 :        256 :   Node b1v;
    1034                 :        256 :   Node guard1n, guard2n;
    1035         [ +  + ]:        128 :   if (reLen.isNull())
    1036                 :            :   {
    1037                 :          6 :     b1 = SkolemCache::mkIndexVar(nm, mem);
    1038                 :          6 :     b1v = nm->mkNode(Kind::BOUND_VAR_LIST, b1);
    1039                 :          6 :     guard1n = nm->mkNode(Kind::LT, b1, zero);
    1040                 :          6 :     guard2n = nm->mkNode(Kind::LT, nm->mkNode(Kind::STRING_LENGTH, s), b1);
    1041                 :            :   }
    1042                 :            :   else
    1043                 :            :   {
    1044                 :        122 :     b1 = reLen;
    1045                 :            :   }
    1046                 :        256 :   Node s1;
    1047                 :        256 :   Node s2;
    1048         [ +  + ]:        128 :   if (!isRev)
    1049                 :            :   {
    1050                 :         76 :     s1 = utils::mkPrefix(s, b1);
    1051                 :         76 :     s2 = utils::mkSuffix(s, b1);
    1052                 :            :   }
    1053                 :            :   else
    1054                 :            :   {
    1055                 :         52 :     s1 = utils::mkSuffixOfLen(s, b1);
    1056                 :         52 :     s2 = utils::mkPrefix(s, nm->mkNode(Kind::SUB, lens, b1));
    1057                 :            :   }
    1058         [ +  + ]:        128 :   size_t index = isRev ? r.getNumChildren() - 1 : 0;
    1059                 :        384 :   Node s1r1 = nm->mkNode(Kind::STRING_IN_REGEXP, s1, r[index]).negate();
    1060                 :        256 :   std::vector<Node> nvec;
    1061         [ +  + ]:        514 :   for (unsigned i = 0, nchild = r.getNumChildren(); i < nchild; i++)
    1062                 :            :   {
    1063         [ +  + ]:        386 :     if (i != index)
    1064                 :            :     {
    1065                 :        258 :       nvec.push_back(r[i]);
    1066                 :            :     }
    1067                 :            :   }
    1068         [ +  + ]:        256 :   Node r2 = nvec.size() == 1 ? nvec[0] : nm->mkNode(Kind::REGEXP_CONCAT, nvec);
    1069                 :        384 :   Node s2r2 = nm->mkNode(Kind::STRING_IN_REGEXP, s2, r2).negate();
    1070                 :        128 :   Node conc;
    1071         [ +  + ]:        128 :   if (!b1v.isNull())
    1072                 :            :   {
    1073 [ +  + ][ -  - ]:         30 :     conc = nm->mkNode(Kind::OR, {guard1n, guard2n, s1r1, s2r2});
    1074                 :            :     // must mark as an internal quantifier
    1075                 :          6 :     conc = utils::mkForallInternal(nm, b1v, conc);
    1076                 :            :   }
    1077                 :            :   else
    1078                 :            :   {
    1079                 :        122 :     conc = nm->mkNode(Kind::OR, s1r1, s2r2);
    1080                 :            :   }
    1081                 :        256 :   return conc;
    1082                 :            : }
    1083                 :            : 
    1084                 :       1920 : Node RegExpOpr::reduceRegExpPos(NodeManager* nm,
    1085                 :            :                                 Node mem,
    1086                 :            :                                 SkolemCache* sc,
    1087                 :            :                                 std::vector<Node>& newSkolems)
    1088                 :            : {
    1089 [ -  + ][ -  + ]:       1920 :   Assert(mem.getKind() == Kind::STRING_IN_REGEXP);
                 [ -  - ]
    1090                 :       3840 :   Node s = mem[0];
    1091                 :       3840 :   Node r = mem[1];
    1092                 :       1920 :   Kind k = r.getKind();
    1093                 :       1920 :   Node conc;
    1094         [ +  + ]:       1920 :   if (k == Kind::REGEXP_CONCAT)
    1095                 :            :   {
    1096                 :       2778 :     std::vector<Node> nvec;
    1097                 :       2778 :     std::vector<Node> cc;
    1098                 :       1389 :     SkolemManager* sm = nm->getSkolemManager();
    1099                 :            :     // Look up skolems for each of the components. If sc has optimizations
    1100                 :            :     // enabled, this will return arguments of str.to_re.
    1101         [ +  + ]:       5262 :     for (unsigned i = 0, nchild = r.getNumChildren(); i < nchild; ++i)
    1102                 :            :     {
    1103         [ +  + ]:       3873 :       if (r[i].getKind() == Kind::STRING_TO_REGEXP)
    1104                 :            :       {
    1105                 :            :         // optimization, just take the body
    1106                 :       1408 :         newSkolems.push_back(r[i][0]);
    1107                 :            :       }
    1108                 :            :       else
    1109                 :            :       {
    1110                 :       4930 :         Node ivalue = nm->mkConstInt(Rational(i));
    1111                 :            :         Node sk = sm->mkSkolemFunction(SkolemId::RE_UNFOLD_POS_COMPONENT,
    1112                 :      12325 :                                        {mem[0], mem[1], ivalue});
    1113                 :       2465 :         newSkolems.push_back(sk);
    1114                 :       2465 :         nvec.push_back(nm->mkNode(Kind::STRING_IN_REGEXP, newSkolems[i], r[i]));
    1115                 :            :       }
    1116                 :            :     }
    1117                 :            :     // (str.in_re x (re.++ R0 .... Rn)) =>
    1118                 :            :     // (and (= x (str.++ k0 ... kn)) (str.in_re k0 R0) ... (str.in_re kn Rn) )
    1119                 :       1389 :     Node lem = s.eqNode(nm->mkNode(Kind::STRING_CONCAT, newSkolems));
    1120                 :       1389 :     nvec.insert(nvec.begin(), lem);
    1121         [ -  + ]:       1389 :     conc = nvec.size() == 1 ? nvec[0] : nm->mkNode(Kind::AND, nvec);
    1122                 :            :   }
    1123         [ +  + ]:        531 :   else if (k == Kind::REGEXP_STAR)
    1124                 :            :   {
    1125                 :       1054 :     Node emp = Word::mkEmptyWord(s.getType());
    1126                 :       1054 :     Node se = s.eqNode(emp);
    1127                 :       1581 :     Node sinr = nm->mkNode(Kind::STRING_IN_REGEXP, s, r[0]);
    1128                 :       1581 :     Node reExpand = nm->mkNode(Kind::REGEXP_CONCAT, r[0], r, r[0]);
    1129                 :       1581 :     Node sinRExp = nm->mkNode(Kind::STRING_IN_REGEXP, s, reExpand);
    1130                 :            :     // We unfold `x in R*` by considering three cases: `x` is empty, `x`
    1131                 :            :     // is matched by `R`, or `x` is matched by two or more `R`s. For the
    1132                 :            :     // last case, `x` will break into three pieces, making the beginning
    1133                 :            :     // and the end each match `R` and the middle match `R*`. Matching the
    1134                 :            :     // beginning and the end with `R` allows us to reason about the
    1135                 :            :     // beginning and the end of `x` simultaneously.
    1136                 :            :     //
    1137                 :            :     // x in R* ---> (x = "") v (x in R) v (x in (re.++ R (re.* R) R))
    1138                 :            : 
    1139                 :            :     // We also immediately unfold the last disjunct for re.*. The advantage
    1140                 :            :     // of doing this is that we use the same scheme for skolems above.
    1141                 :        527 :     std::vector<Node> newSkolemsC;
    1142                 :        527 :     sinRExp = reduceRegExpPos(nm, sinRExp, sc, newSkolemsC);
    1143 [ -  + ][ -  + ]:        527 :     Assert(newSkolemsC.size() == 3);
                 [ -  - ]
    1144                 :            :     // make the return lemma
    1145                 :            :     // can also assume the component match the first and last R are non-empty.
    1146                 :            :     // This means that the overall conclusion is:
    1147                 :            :     //   (x = "") v (x in R) v (x = (str.++ k1 k2 k3) ^
    1148                 :            :     //                          k1 in R ^ k2 in (re.* R) ^ k3 in R ^
    1149                 :            :     //                          k1 != ""  ^ k3 != "")
    1150                 :       1054 :     conc = nm->mkNode(Kind::OR,
    1151                 :            :                       se,
    1152                 :            :                       sinr,
    1153                 :       1581 :                       nm->mkNode(Kind::AND,
    1154                 :            :                                  sinRExp,
    1155                 :       1054 :                                  newSkolemsC[0].eqNode(emp).negate(),
    1156                 :       1581 :                                  newSkolemsC[2].eqNode(emp).negate()));
    1157                 :            :   }
    1158                 :            :   else
    1159                 :            :   {
    1160 [ -  + ][ -  + ]:          4 :     Assert(!utils::isRegExpKind(k));
                 [ -  - ]
    1161                 :            :   }
    1162                 :       3840 :   return conc;
    1163                 :            : }
    1164                 :            : 
    1165                 :          0 : bool RegExpOpr::isPairNodesInSet(std::set< PairNodes > &s, Node n1, Node n2) {
    1166                 :          0 :   for(std::set< PairNodes >::const_iterator itr = s.begin();
    1167         [ -  - ]:          0 :       itr != s.end(); ++itr) {
    1168                 :          0 :     if((itr->first == n1 && itr->second == n2) ||
    1169                 :          0 :        (itr->first == n2 && itr->second == n1)) {
    1170                 :          0 :       return true;
    1171                 :            :     }
    1172                 :            :   }
    1173                 :          0 :   return false;
    1174                 :            : }
    1175                 :            : 
    1176                 :          0 : bool RegExpOpr::containC2(unsigned cnt, Node n) {
    1177         [ -  - ]:          0 :   if (n.getKind() == Kind::REGEXP_RV)
    1178                 :            :   {
    1179                 :          0 :     Assert(n[0].getConst<Rational>() <= Rational(String::maxSize()))
    1180                 :          0 :         << "Exceeded UINT32_MAX in RegExpOpr::containC2";
    1181                 :          0 :     unsigned y = n[0].getConst<Rational>().getNumerator().toUnsignedInt();
    1182                 :          0 :     return cnt == y;
    1183                 :            :   }
    1184         [ -  - ]:          0 :   else if (n.getKind() == Kind::REGEXP_CONCAT)
    1185                 :            :   {
    1186         [ -  - ]:          0 :     for( unsigned i=0; i<n.getNumChildren(); i++ ) {
    1187         [ -  - ]:          0 :       if(containC2(cnt, n[i])) {
    1188                 :          0 :         return true;
    1189                 :            :       }
    1190                 :            :     }
    1191                 :            :   }
    1192         [ -  - ]:          0 :   else if (n.getKind() == Kind::REGEXP_STAR)
    1193                 :            :   {
    1194                 :          0 :     return containC2(cnt, n[0]);
    1195                 :            :   }
    1196         [ -  - ]:          0 :   else if (n.getKind() == Kind::REGEXP_LOOP)
    1197                 :            :   {
    1198                 :          0 :     return containC2(cnt, n[0]);
    1199                 :            :   }
    1200         [ -  - ]:          0 :   else if (n.getKind() == Kind::REGEXP_UNION)
    1201                 :            :   {
    1202         [ -  - ]:          0 :     for( unsigned i=0; i<n.getNumChildren(); i++ ) {
    1203         [ -  - ]:          0 :       if(containC2(cnt, n[i])) {
    1204                 :          0 :         return true;
    1205                 :            :       }
    1206                 :            :     }
    1207                 :            :   }
    1208                 :          0 :   return false;
    1209                 :            : }
    1210                 :          0 : Node RegExpOpr::convert1(unsigned cnt, Node n) {
    1211         [ -  - ]:          0 :   Trace("regexp-debug") << "Converting " << n << " at " << cnt << "... " << std::endl;
    1212                 :          0 :   Node r1, r2;
    1213                 :          0 :   convert2(cnt, n, r1, r2);
    1214         [ -  - ]:          0 :   Trace("regexp-debug") << "... getting r1=" << r1 << ", and r2=" << r2 << std::endl;
    1215                 :            :   Node ret =
    1216                 :          0 :       r1 == d_emptySingleton
    1217                 :            :           ? r2
    1218                 :          0 :           : nodeManager()->mkNode(Kind::REGEXP_CONCAT,
    1219                 :          0 :                                   nodeManager()->mkNode(Kind::REGEXP_STAR, r1),
    1220                 :          0 :                                   r2);
    1221                 :          0 :   ret = rewrite(ret);
    1222         [ -  - ]:          0 :   Trace("regexp-debug") << "... done convert at " << cnt << ", with return " << ret << std::endl;
    1223                 :          0 :   return ret;
    1224                 :            : }
    1225                 :          0 : void RegExpOpr::convert2(unsigned cnt, Node n, Node &r1, Node &r2) {
    1226         [ -  - ]:          0 :   if(n == d_emptyRegexp) {
    1227                 :          0 :     r1 = d_emptyRegexp;
    1228                 :          0 :     r2 = d_emptyRegexp;
    1229                 :          0 :     return;
    1230         [ -  - ]:          0 :   } else if(n == d_emptySingleton) {
    1231                 :          0 :     r1 = d_emptySingleton;
    1232                 :          0 :     r2 = d_emptySingleton;
    1233                 :            :   }
    1234                 :          0 :   Kind nk = n.getKind();
    1235         [ -  - ]:          0 :   if (nk == Kind::REGEXP_RV)
    1236                 :            :   {
    1237                 :          0 :     Assert(n[0].getConst<Rational>() <= Rational(String::maxSize()))
    1238                 :          0 :         << "Exceeded UINT32_MAX in RegExpOpr::convert2";
    1239                 :          0 :     unsigned y = n[0].getConst<Rational>().getNumerator().toUnsignedInt();
    1240                 :          0 :     r1 = d_emptySingleton;
    1241         [ -  - ]:          0 :     if(cnt == y) {
    1242                 :          0 :       r2 = d_emptyRegexp;
    1243                 :            :     } else {
    1244                 :          0 :       r2 = n;
    1245                 :            :     }
    1246                 :            :   }
    1247         [ -  - ]:          0 :   else if (nk == Kind::REGEXP_CONCAT)
    1248                 :            :   {
    1249                 :          0 :     bool flag = true;
    1250                 :          0 :     std::vector<Node> vr1, vr2;
    1251         [ -  - ]:          0 :     for( unsigned i=0; i<n.getNumChildren(); i++ ) {
    1252         [ -  - ]:          0 :       if(containC2(cnt, n[i])) {
    1253                 :          0 :         Node t1, t2;
    1254                 :          0 :         convert2(cnt, n[i], t1, t2);
    1255                 :          0 :         vr1.push_back(t1);
    1256                 :          0 :         r1 = vr1.size() == 0
    1257                 :          0 :                  ? d_emptyRegexp
    1258                 :          0 :                  : vr1.size() == 1
    1259                 :          0 :                        ? vr1[0]
    1260                 :          0 :                        : nodeManager()->mkNode(Kind::REGEXP_CONCAT, vr1);
    1261                 :          0 :         vr2.push_back(t2);
    1262         [ -  - ]:          0 :         for( unsigned j=i+1; j<n.getNumChildren(); j++ ) {
    1263                 :          0 :           vr2.push_back(n[j]);
    1264                 :            :         }
    1265                 :          0 :         r2 = vr2.size() == 0
    1266                 :          0 :                  ? d_emptyRegexp
    1267                 :          0 :                  : vr2.size() == 1
    1268                 :          0 :                        ? vr2[0]
    1269                 :          0 :                        : nodeManager()->mkNode(Kind::REGEXP_CONCAT, vr2);
    1270                 :          0 :         flag = false;
    1271                 :          0 :         break;
    1272                 :            :       } else {
    1273                 :          0 :         vr1.push_back(n[i]);
    1274                 :            :       }
    1275                 :            :     }
    1276         [ -  - ]:          0 :     if(flag) {
    1277                 :          0 :       r1 = d_emptySingleton;
    1278                 :          0 :       r2 = n;
    1279                 :            :     }
    1280                 :            :   }
    1281         [ -  - ]:          0 :   else if (nk == Kind::REGEXP_UNION)
    1282                 :            :   {
    1283                 :          0 :     std::vector<Node> vr1, vr2;
    1284         [ -  - ]:          0 :     for( unsigned i=0; i<n.getNumChildren(); i++ ) {
    1285                 :          0 :       Node t1, t2;
    1286                 :          0 :       convert2(cnt, n[i], t1, t2);
    1287                 :          0 :       vr1.push_back(t1);
    1288                 :          0 :       vr2.push_back(t2);
    1289                 :            :     }
    1290                 :          0 :     r1 = nodeManager()->mkNode(Kind::REGEXP_UNION, vr1);
    1291                 :          0 :     r2 = nodeManager()->mkNode(Kind::REGEXP_UNION, vr2);
    1292                 :            :   }
    1293 [ -  - ][ -  - ]:          0 :   else if (nk == Kind::STRING_TO_REGEXP || nk == Kind::REGEXP_ALLCHAR
    1294 [ -  - ][ -  - ]:          0 :            || nk == Kind::REGEXP_RANGE || nk == Kind::REGEXP_COMPLEMENT
    1295         [ -  - ]:          0 :            || nk == Kind::REGEXP_LOOP)
    1296                 :            :   {
    1297                 :            :     // this leaves n unchanged
    1298                 :          0 :     r1 = d_emptySingleton;
    1299                 :          0 :     r2 = n;
    1300                 :            :   }
    1301                 :            :   else
    1302                 :            :   {
    1303                 :            :     //is it possible?
    1304                 :          0 :     Unreachable();
    1305                 :            :   }
    1306                 :            : }
    1307                 :            : 
    1308                 :          0 : Node RegExpOpr::intersectInternal( Node r1, Node r2, std::map< PairNodes, Node > cache, unsigned cnt ) {
    1309                 :            :   //Assert(checkConstRegExp(r1) && checkConstRegExp(r2));
    1310         [ -  - ]:          0 :   if(r1 > r2) {
    1311                 :          0 :     TNode tmpNode = r1;
    1312                 :          0 :     r1 = r2;
    1313                 :          0 :     r2 = tmpNode;
    1314                 :            :   }
    1315                 :          0 :   NodeManager* nm = nodeManager();
    1316                 :          0 :   Trace("regexp-int") << "Starting INTERSECT(" << cnt << "):\n  "<< mkString(r1) << ",\n  " << mkString(r2) << std::endl;
    1317                 :          0 :   std::pair < Node, Node > p(r1, r2);
    1318                 :          0 :   std::map < PairNodes, Node >::const_iterator itr = d_inter_cache.find(p);
    1319                 :          0 :   Node rNode;
    1320         [ -  - ]:          0 :   if(itr != d_inter_cache.end()) {
    1321                 :          0 :     rNode = itr->second;
    1322                 :            :   } else {
    1323         [ -  - ]:          0 :     Trace("regexp-int-debug") << " ... not in cache" << std::endl;
    1324                 :          0 :     if(r1 == d_emptyRegexp || r2 == d_emptyRegexp) {
    1325         [ -  - ]:          0 :       Trace("regexp-int-debug") << " ... one is empty set" << std::endl;
    1326                 :          0 :       rNode = d_emptyRegexp;
    1327                 :          0 :     } else if(r1 == d_emptySingleton || r2 == d_emptySingleton) {
    1328         [ -  - ]:          0 :       Trace("regexp-int-debug") << " ... one is empty singleton" << std::endl;
    1329                 :          0 :       Node exp;
    1330         [ -  - ]:          0 :       int r = delta((r1 == d_emptySingleton ? r2 : r1), exp);
    1331         [ -  - ]:          0 :       if(r == 0) {
    1332                 :            :         //TODO: variable
    1333                 :          0 :         Unreachable();
    1334         [ -  - ]:          0 :       } else if(r == 1) {
    1335                 :          0 :         rNode = d_emptySingleton;
    1336                 :            :       } else {
    1337                 :          0 :         rNode = d_emptyRegexp;
    1338                 :            :       }
    1339         [ -  - ]:          0 :     } else if(r1 == r2) {
    1340         [ -  - ]:          0 :       Trace("regexp-int-debug") << " ... equal" << std::endl;
    1341                 :          0 :       rNode = r1; //convert1(cnt, r1);
    1342                 :            :     } else {
    1343         [ -  - ]:          0 :       Trace("regexp-int-debug") << " ... normal checking" << std::endl;
    1344                 :          0 :       std::map< PairNodes, Node >::const_iterator itrcache = cache.find(p);
    1345         [ -  - ]:          0 :       if(itrcache != cache.end()) {
    1346                 :          0 :         rNode = itrcache->second;
    1347                 :            :       } else {
    1348         [ -  - ]:          0 :         Trace("regexp-int-debug") << " ... normal without cache" << std::endl;
    1349                 :          0 :         std::vector<unsigned> cset;
    1350                 :          0 :         std::set<unsigned> cset1, cset2;
    1351                 :          0 :         std::set< Node > vset1, vset2;
    1352                 :          0 :         firstChars(r1, cset1, vset1);
    1353                 :          0 :         firstChars(r2, cset2, vset2);
    1354         [ -  - ]:          0 :         Trace("regexp-int-debug") << " ... got fset" << std::endl;
    1355                 :            :         std::set_intersection(cset1.begin(), cset1.end(), cset2.begin(), cset2.end(),
    1356                 :          0 :              std::inserter(cset, cset.begin()));
    1357                 :          0 :         std::vector< Node > vec_nodes;
    1358                 :          0 :         Node delta_exp;
    1359         [ -  - ]:          0 :         Trace("regexp-int-debug") << " ... try delta" << std::endl;
    1360                 :          0 :         int flag = delta(r1, delta_exp);
    1361                 :          0 :         int flag2 = delta(r2, delta_exp);
    1362         [ -  - ]:          0 :         Trace("regexp-int-debug") << " ... delta1=" << flag << ", delta2=" << flag2 << std::endl;
    1363 [ -  - ][ -  - ]:          0 :         if(flag != 2 && flag2 != 2) {
    1364 [ -  - ][ -  - ]:          0 :           if(flag == 1 && flag2 == 1) {
    1365                 :          0 :             vec_nodes.push_back(d_emptySingleton);
    1366                 :            :           } else {
    1367                 :            :             //TODO: variable
    1368                 :          0 :             Unreachable();
    1369                 :            :           }
    1370                 :            :         }
    1371         [ -  - ]:          0 :         if(TraceIsOn("regexp-int-debug")) {
    1372         [ -  - ]:          0 :           Trace("regexp-int-debug") << "Try CSET(" << cset.size() << ") = {";
    1373                 :          0 :           for (std::vector<unsigned>::const_iterator it = cset.begin();
    1374         [ -  - ]:          0 :                it != cset.end();
    1375                 :          0 :                ++it)
    1376                 :            :           {
    1377         [ -  - ]:          0 :             if (it != cset.begin())
    1378                 :            :             {
    1379         [ -  - ]:          0 :               Trace("regexp-int-debug") << ", ";
    1380                 :            :             }
    1381         [ -  - ]:          0 :             Trace("regexp-int-debug") << (*it);
    1382                 :            :           }
    1383         [ -  - ]:          0 :           Trace("regexp-int-debug") << std::endl;
    1384                 :            :         }
    1385                 :          0 :         std::map< PairNodes, Node > cacheX;
    1386                 :          0 :         for (std::vector<unsigned>::const_iterator it = cset.begin();
    1387         [ -  - ]:          0 :              it != cset.end();
    1388                 :          0 :              ++it)
    1389                 :            :         {
    1390                 :          0 :           std::vector<unsigned> cvec;
    1391                 :          0 :           cvec.push_back(*it);
    1392                 :          0 :           String c(cvec);
    1393         [ -  - ]:          0 :           Trace("regexp-int-debug") << "Try character " << c << " ... " << std::endl;
    1394                 :          0 :           Node r1l = derivativeSingle(r1, c);
    1395                 :          0 :           Node r2l = derivativeSingle(r2, c);
    1396                 :          0 :           Trace("regexp-int-debug") << "  ... got partial(r1,c) = " << mkString(r1l) << std::endl;
    1397                 :          0 :           Trace("regexp-int-debug") << "  ... got partial(r2,c) = " << mkString(r2l) << std::endl;
    1398                 :          0 :           Node rt;
    1399                 :            :           
    1400         [ -  - ]:          0 :           if(r1l > r2l) {
    1401                 :          0 :             Node tnode = r1l;
    1402                 :          0 :             r1l = r2l; r2l = tnode;
    1403                 :            :           }
    1404                 :          0 :           PairNodes pp(r1l, r2l);
    1405                 :          0 :           std::map< PairNodes, Node >::const_iterator itr2 = cacheX.find(pp);
    1406         [ -  - ]:          0 :           if(itr2 != cacheX.end()) {
    1407                 :          0 :             rt = itr2->second;
    1408                 :            :           } else {
    1409                 :          0 :             std::map< PairNodes, Node > cache2(cache);
    1410                 :          0 :             cache2[p] =
    1411                 :          0 :                 nm->mkNode(Kind::REGEXP_RV, nm->mkConstInt(Rational(cnt)));
    1412                 :          0 :             rt = intersectInternal(r1l, r2l, cache2, cnt+1);
    1413                 :          0 :             cacheX[ pp ] = rt;
    1414                 :            :           }
    1415                 :            : 
    1416                 :          0 :           rt = rewrite(
    1417                 :          0 :               nm->mkNode(Kind::REGEXP_CONCAT,
    1418                 :          0 :                          nm->mkNode(Kind::STRING_TO_REGEXP, nm->mkConst(c)),
    1419                 :          0 :                          rt));
    1420                 :            : 
    1421                 :          0 :           Trace("regexp-int-debug") << "  ... got p(r1,c) && p(r2,c) = " << mkString(rt) << std::endl;
    1422                 :          0 :           vec_nodes.push_back(rt);
    1423                 :            :         }
    1424                 :          0 :         rNode = rewrite(vec_nodes.size() == 0 ? d_emptyRegexp
    1425                 :          0 :                         : vec_nodes.size() == 1
    1426                 :          0 :                             ? vec_nodes[0]
    1427                 :          0 :                             : nm->mkNode(Kind::REGEXP_UNION, vec_nodes));
    1428                 :          0 :         rNode = convert1(cnt, rNode);
    1429                 :          0 :         rNode = rewrite(rNode);
    1430                 :            :       }
    1431                 :            :     }
    1432                 :          0 :     Trace("regexp-int-debug") << "  ... try testing no RV of " << mkString(rNode) << std::endl;
    1433         [ -  - ]:          0 :     if (!expr::hasSubtermKind(Kind::REGEXP_RV, rNode))
    1434                 :            :     {
    1435                 :          0 :       d_inter_cache[p] = rNode;
    1436                 :            :     }
    1437                 :            :   }
    1438                 :          0 :   Trace("regexp-int") << "End(" << cnt << ") of INTERSECT( " << mkString(r1) << ", " << mkString(r2) << " ) = " << mkString(rNode) << std::endl;
    1439                 :          0 :   return rNode;
    1440                 :            : }
    1441                 :            : 
    1442                 :          0 : Node RegExpOpr::removeIntersection(Node r) {
    1443                 :          0 :   Assert(checkConstRegExp(r));
    1444                 :          0 :   NodeManager* nm = nodeManager();
    1445                 :          0 :   std::unordered_map<TNode, Node> visited;
    1446                 :          0 :   std::unordered_map<TNode, Node>::iterator it;
    1447                 :          0 :   std::vector<TNode> visit;
    1448                 :          0 :   TNode cur;
    1449                 :          0 :   visit.push_back(r);
    1450                 :          0 :   do
    1451                 :            :   {
    1452                 :          0 :     cur = visit.back();
    1453                 :          0 :     visit.pop_back();
    1454                 :          0 :     it = visited.find(cur);
    1455                 :            : 
    1456         [ -  - ]:          0 :     if (it == visited.end())
    1457                 :            :     {
    1458                 :          0 :       visited[cur] = Node::null();
    1459                 :          0 :       visit.push_back(cur);
    1460         [ -  - ]:          0 :       for (const Node& cn : cur)
    1461                 :            :       {
    1462                 :          0 :         visit.push_back(cn);
    1463                 :            :       }
    1464                 :            :     }
    1465         [ -  - ]:          0 :     else if (it->second.isNull())
    1466                 :            :     {
    1467                 :          0 :       Kind ck = cur.getKind();
    1468                 :          0 :       Node ret;
    1469                 :          0 :       bool childChanged = false;
    1470                 :          0 :       std::vector<Node> children;
    1471         [ -  - ]:          0 :       if (cur.getMetaKind() == kind::metakind::PARAMETERIZED)
    1472                 :            :       {
    1473                 :          0 :         children.push_back(cur.getOperator());
    1474                 :            :       }
    1475         [ -  - ]:          0 :       for (const Node& cn : cur)
    1476                 :            :       {
    1477                 :          0 :         it = visited.find(cn);
    1478                 :          0 :         Assert(it != visited.end());
    1479                 :          0 :         Assert(!it->second.isNull());
    1480         [ -  - ]:          0 :         if (ck == Kind::REGEXP_INTER)
    1481                 :            :         {
    1482         [ -  - ]:          0 :           if (ret.isNull())
    1483                 :            :           {
    1484                 :          0 :             ret = it->second;
    1485                 :            :           }
    1486                 :            :           else
    1487                 :            :           {
    1488                 :          0 :             ret = intersect(ret, it->second);
    1489                 :            :           }
    1490                 :            :         }
    1491                 :            :         else
    1492                 :            :         {
    1493                 :            :           // will construct below
    1494                 :          0 :           childChanged = childChanged || cn != it->second;
    1495                 :          0 :           children.push_back(it->second);
    1496                 :            :         }
    1497                 :            :       }
    1498         [ -  - ]:          0 :       if (ck != Kind::REGEXP_INTER)
    1499                 :            :       {
    1500         [ -  - ]:          0 :         if (childChanged)
    1501                 :            :         {
    1502                 :          0 :           ret = nm->mkNode(cur.getKind(), children);
    1503                 :            :         }
    1504                 :            :         else
    1505                 :            :         {
    1506                 :          0 :           ret = cur;
    1507                 :            :         }
    1508                 :            :       }
    1509                 :          0 :       visited[cur] = ret;
    1510                 :            :     }
    1511         [ -  - ]:          0 :   } while (!visit.empty());
    1512                 :          0 :   Assert(visited.find(r) != visited.end());
    1513                 :          0 :   Assert(!visited.find(r)->second.isNull());
    1514         [ -  - ]:          0 :   if (TraceIsOn("regexp-intersect"))
    1515                 :            :   {
    1516                 :          0 :     Trace("regexp-intersect") << "Remove INTERSECTION( " << mkString(r)
    1517                 :          0 :                               << " ) = " << mkString(visited[r]) << std::endl;
    1518                 :            :   }
    1519                 :          0 :   return visited[r];
    1520                 :            : }
    1521                 :            : 
    1522                 :          0 : Node RegExpOpr::intersect(Node r1, Node r2)
    1523                 :            : {
    1524                 :          0 :   if (!checkConstRegExp(r1) || !checkConstRegExp(r2)
    1525                 :          0 :       || expr::hasSubtermKind(Kind::REGEXP_COMPLEMENT, r1)
    1526                 :          0 :       || expr::hasSubtermKind(Kind::REGEXP_COMPLEMENT, r2))
    1527                 :            :   {
    1528                 :          0 :     return Node::null();
    1529                 :            :   }
    1530                 :          0 :   Node rr1 = removeIntersection(r1);
    1531                 :          0 :   Node rr2 = removeIntersection(r2);
    1532                 :          0 :   std::map<PairNodes, Node> cache;
    1533         [ -  - ]:          0 :   Trace("regexp-intersect-node") << "Intersect (1): " << rr1 << std::endl;
    1534         [ -  - ]:          0 :   Trace("regexp-intersect-node") << "Intersect (2): " << rr2 << std::endl;
    1535                 :          0 :   Trace("regexp-intersect") << "Start INTERSECTION(\n\t" << mkString(r1)
    1536                 :          0 :                             << ",\n\t" << mkString(r2) << ")" << std::endl;
    1537                 :          0 :   Node retNode = intersectInternal(rr1, rr2, cache, 1);
    1538         [ -  - ]:          0 :   Trace("regexp-intersect")
    1539                 :          0 :       << "End INTERSECTION(\n\t" << mkString(r1) << ",\n\t" << mkString(r2)
    1540                 :          0 :       << ") =\n\t" << mkString(retNode) << std::endl;
    1541         [ -  - ]:          0 :   Trace("regexp-intersect-node") << "Intersect finished." << std::endl;
    1542                 :          0 :   return retNode;
    1543                 :            : }
    1544                 :            : 
    1545                 :            : //printing
    1546                 :          0 : std::string RegExpOpr::niceChar(Node r) {
    1547         [ -  - ]:          0 :   if(r.isConst()) {
    1548                 :          0 :     std::string s = r.getConst<String>().toString();
    1549                 :          0 :     return s == "." ? "\\." : s;
    1550                 :            :   } else {
    1551                 :          0 :     std::string ss = "$" + r.toString();
    1552                 :          0 :     return ss;
    1553                 :            :   }
    1554                 :            : }
    1555                 :          0 : std::string RegExpOpr::mkString( Node r ) {
    1556                 :          0 :   std::string retStr;
    1557         [ -  - ]:          0 :   if(r.isNull()) {
    1558                 :          0 :     retStr = "\\E";
    1559                 :            :   } else {
    1560                 :          0 :     Kind k = r.getKind();
    1561 [ -  - ][ -  - ]:          0 :     switch( k ) {
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
                 [ -  - ]
    1562                 :          0 :       case Kind::REGEXP_NONE:
    1563                 :            :       {
    1564                 :          0 :         retStr += "\\E";
    1565                 :          0 :         break;
    1566                 :            :       }
    1567                 :          0 :       case Kind::REGEXP_ALLCHAR:
    1568                 :            :       {
    1569                 :          0 :         retStr += ".";
    1570                 :          0 :         break;
    1571                 :            :       }
    1572                 :          0 :       case Kind::STRING_TO_REGEXP:
    1573                 :            :       {
    1574                 :          0 :         std::string tmp( niceChar( r[0] ) );
    1575                 :          0 :         retStr += tmp.size()==1? tmp : "(" + tmp + ")";
    1576                 :          0 :         break;
    1577                 :            :       }
    1578                 :          0 :       case Kind::REGEXP_CONCAT:
    1579                 :            :       {
    1580                 :          0 :         retStr += "(";
    1581         [ -  - ]:          0 :         for(unsigned i=0; i<r.getNumChildren(); ++i) {
    1582                 :            :           //if(i != 0) retStr += ".";
    1583                 :          0 :           retStr += mkString( r[i] );
    1584                 :            :         }
    1585                 :          0 :         retStr += ")";
    1586                 :          0 :         break;
    1587                 :            :       }
    1588                 :          0 :       case Kind::REGEXP_UNION:
    1589                 :            :       {
    1590                 :          0 :         retStr += "(";
    1591         [ -  - ]:          0 :         for(unsigned i=0; i<r.getNumChildren(); ++i) {
    1592         [ -  - ]:          0 :           if(i != 0) retStr += "|";
    1593                 :          0 :           retStr += mkString( r[i] );
    1594                 :            :         }
    1595                 :          0 :         retStr += ")";
    1596                 :          0 :         break;
    1597                 :            :       }
    1598                 :          0 :       case Kind::REGEXP_INTER:
    1599                 :            :       {
    1600                 :          0 :         retStr += "(";
    1601         [ -  - ]:          0 :         for(unsigned i=0; i<r.getNumChildren(); ++i) {
    1602         [ -  - ]:          0 :           if(i != 0) retStr += "&";
    1603                 :          0 :           retStr += mkString( r[i] );
    1604                 :            :         }
    1605                 :          0 :         retStr += ")";
    1606                 :          0 :         break;
    1607                 :            :       }
    1608                 :          0 :       case Kind::REGEXP_STAR:
    1609                 :            :       {
    1610                 :          0 :         retStr += mkString( r[0] );
    1611                 :          0 :         retStr += "*";
    1612                 :          0 :         break;
    1613                 :            :       }
    1614                 :          0 :       case Kind::REGEXP_PLUS:
    1615                 :            :       {
    1616                 :          0 :         retStr += mkString( r[0] );
    1617                 :          0 :         retStr += "+";
    1618                 :          0 :         break;
    1619                 :            :       }
    1620                 :          0 :       case Kind::REGEXP_OPT:
    1621                 :            :       {
    1622                 :          0 :         retStr += mkString( r[0] );
    1623                 :          0 :         retStr += "?";
    1624                 :          0 :         break;
    1625                 :            :       }
    1626                 :          0 :       case Kind::REGEXP_RANGE:
    1627                 :            :       {
    1628                 :          0 :         retStr += "[";
    1629                 :          0 :         retStr += niceChar( r[0] );
    1630                 :          0 :         retStr += "-";
    1631                 :          0 :         retStr += niceChar( r[1] );
    1632                 :          0 :         retStr += "]";
    1633                 :          0 :         break;
    1634                 :            :       }
    1635                 :          0 :       case Kind::REGEXP_LOOP:
    1636                 :            :       {
    1637                 :          0 :         uint32_t l = utils::getLoopMinOccurrences(r);
    1638                 :          0 :         std::stringstream ss;
    1639                 :          0 :         ss << "(" << mkString(r[0]) << "){" << l << ",";
    1640         [ -  - ]:          0 :         if(r.getNumChildren() == 3) {
    1641                 :          0 :           uint32_t u = utils::getLoopMaxOccurrences(r);
    1642                 :          0 :           ss << u;
    1643                 :            :         }
    1644                 :          0 :         ss << "}";
    1645                 :          0 :         retStr += ss.str();
    1646                 :          0 :         break;
    1647                 :            :       }
    1648                 :          0 :       case Kind::REGEXP_RV:
    1649                 :            :       {
    1650                 :          0 :         retStr += "<";
    1651                 :          0 :         retStr += r[0].getConst<Rational>().getNumerator().toString();
    1652                 :          0 :         retStr += ">";
    1653                 :          0 :         break;
    1654                 :            :       }
    1655                 :          0 :       case Kind::REGEXP_COMPLEMENT:
    1656                 :            :       {
    1657                 :          0 :         retStr += "^(";
    1658                 :          0 :         retStr += mkString(r[0]);
    1659                 :          0 :         retStr += ")";
    1660                 :          0 :         break;
    1661                 :            :       }
    1662                 :          0 :       default:
    1663                 :            :       {
    1664                 :          0 :         std::stringstream ss;
    1665                 :          0 :         ss << r;
    1666                 :          0 :         retStr = ss.str();
    1667                 :          0 :         Assert(!utils::isRegExpKind(r.getKind()));
    1668                 :          0 :         break;
    1669                 :            :       }
    1670                 :            :     }
    1671                 :            :   }
    1672                 :            : 
    1673                 :          0 :   return retStr;
    1674                 :            : }
    1675                 :            : 
    1676                 :       1816 : bool RegExpOpr::regExpIncludes(Node r1, Node r2)
    1677                 :            : {
    1678                 :       1816 :   return RegExpEntail::regExpIncludes(r1, r2, d_inclusionCache);
    1679                 :            : }
    1680                 :            : 
    1681                 :            : }  // namespace strings
    1682                 :            : }  // namespace theory
    1683                 :            : }  // namespace cvc5::internal

Generated by: LCOV version 1.14