Assert(nk == REGEXP_UNION || nk == REGEXP_INTER);
Trace("strings-rewrite-debug")
<< "Strings::rewriteAndOrRegExp start " << node << std::endl;
+ NodeManager* nm = NodeManager::currentNM();
std::vector<Node> node_vec;
std::vector<Node> polRegExp[2];
+ // list of constant string regular expressions (str.to_re c)
+ std::vector<Node> constStrRe;
+ // list of all other regular expressions
+ std::vector<Node> otherRe;
for (const Node& ni : node)
{
- if (ni.getKind() == nk)
+ Kind nik = ni.getKind();
+ if (nik == nk)
{
for (const Node& nic : ni)
{
}
}
}
- else if (ni.getKind() == REGEXP_NONE)
+ else if (nik == REGEXP_NONE)
{
if (nk == REGEXP_INTER)
{
}
// otherwise, can ignore
}
- else if (ni.getKind() == REGEXP_STAR && ni[0].getKind() == REGEXP_ALLCHAR)
+ else if (nik == REGEXP_STAR && ni[0].getKind() == REGEXP_ALLCHAR)
{
if (nk == REGEXP_UNION)
{
}
else if (std::find(node_vec.begin(), node_vec.end(), ni) == node_vec.end())
{
+ if (nik == STRING_TO_REGEXP && ni[0].isConst())
+ {
+ if (nk == REGEXP_INTER)
+ {
+ if (!constStrRe.empty())
+ {
+ Assert(constStrRe[0][0] != ni[0]);
+ // (re.inter .. (str.to_re c1) .. (str.to_re c2) ..) ---> re.none
+ // for distinct constant strings c1, c2.
+ Node ret = nm->mkNode(kind::REGEXP_NONE);
+ return returnRewrite(
+ node, ret, Rewrite::RE_INTER_CONST_CONST_CONFLICT);
+ }
+ }
+ else
+ {
+ Assert(nk == REGEXP_UNION);
+ }
+ constStrRe.push_back(ni);
+ }
+ else
+ {
+ otherRe.push_back(ni);
+ uint32_t pindex = nik == REGEXP_COMPLEMENT ? 1 : 0;
+ Node nia = pindex == 1 ? ni[0] : ni;
+ polRegExp[pindex].push_back(nia);
+ }
node_vec.push_back(ni);
- uint32_t pindex = ni.getKind() == REGEXP_COMPLEMENT ? 1 : 0;
- Node nia = pindex == 1 ? ni[0] : ni;
- polRegExp[pindex].push_back(nia);
}
}
- NodeManager* nm = NodeManager::currentNM();
+ Trace("strings-rewrite-debug")
+ << "Partition constant components " << constStrRe.size() << " / "
+ << otherRe.size() << std::endl;
+ // go back and process constant strings against the others
+ if (!constStrRe.empty())
+ {
+ std::unordered_set<Node> toRemove;
+ for (const Node& c : constStrRe)
+ {
+ Assert(c.getKind() == STRING_TO_REGEXP && c[0].getKind() == CONST_STRING);
+ cvc5::String s = c[0].getConst<String>();
+ for (const Node& r : otherRe)
+ {
+ Trace("strings-rewrite-debug")
+ << "Check " << c << " vs " << r << std::endl;
+ // skip if already removing, or not constant
+ if (!RegExpEntail::isConstRegExp(r)
+ || toRemove.find(r) != toRemove.end())
+ {
+ Trace("strings-rewrite-debug") << "...skip" << std::endl;
+ continue;
+ }
+ // test whether c from (str.to_re c) is in r
+ if (RegExpEntail::testConstStringInRegExp(s, 0, r))
+ {
+ Trace("strings-rewrite-debug") << "...included" << std::endl;
+ if (nk == REGEXP_INTER)
+ {
+ // (re.inter .. (str.to_re c) .. R ..) --->
+ // (re.inter .. (str.to_re c) .. ..) when c in R
+ toRemove.insert(r);
+ }
+ else
+ {
+ // (re.union .. (str.to_re c) .. R ..) --->
+ // (re.union .. .. R ..) when c in R
+ toRemove.insert(c);
+ break;
+ }
+ }
+ else
+ {
+ Trace("strings-rewrite-debug") << "...not included" << std::endl;
+ if (nk == REGEXP_INTER)
+ {
+ // (re.inter .. (str.to_re c) .. R ..) ---> re.none
+ // if c is not a member of R.
+ Node ret = nm->mkNode(kind::REGEXP_NONE);
+ return returnRewrite(
+ node, ret, Rewrite::RE_INTER_CONST_RE_CONFLICT);
+ }
+ }
+ }
+ }
+ if (!toRemove.empty())
+ {
+ std::vector<Node> nodeVecTmp;
+ node_vec.swap(nodeVecTmp);
+ for (const Node& nvt : nodeVecTmp)
+ {
+ if (toRemove.find(nvt) == toRemove.end())
+ {
+ node_vec.push_back(nvt);
+ }
+ }
+ }
+ }
// use inclusion tests
for (const Node& negMem : polRegExp[1])
{