summaryrefslogtreecommitdiff
path: root/src/theory/strings/regexp_solver.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/theory/strings/regexp_solver.cpp')
-rw-r--r--src/theory/strings/regexp_solver.cpp290
1 files changed, 108 insertions, 182 deletions
diff --git a/src/theory/strings/regexp_solver.cpp b/src/theory/strings/regexp_solver.cpp
index 49dd1ead6..c50889e78 100644
--- a/src/theory/strings/regexp_solver.cpp
+++ b/src/theory/strings/regexp_solver.cpp
@@ -19,6 +19,7 @@
#include <cmath>
#include "options/strings_options.h"
+#include "theory/ext_theory.h"
#include "theory/strings/theory_strings.h"
#include "theory/strings/theory_strings_rewriter.h"
#include "theory/strings/theory_strings_utils.h"
@@ -38,13 +39,8 @@ RegExpSolver::RegExpSolver(TheoryStrings& p,
context::UserContext* u)
: d_parent(p),
d_im(im),
- d_regexp_memberships(c),
d_regexp_ucached(u),
d_regexp_ccached(c),
- d_pos_memberships(c),
- d_neg_memberships(c),
- d_inter_cache(c),
- d_inter_index(c),
d_processed_memberships(c)
{
d_emptyString = NodeManager::currentNM()->mkConst(::CVC4::String(""));
@@ -54,118 +50,27 @@ RegExpSolver::RegExpSolver(TheoryStrings& p,
d_false = NodeManager::currentNM()->mkConst(false);
}
-unsigned RegExpSolver::getNumMemberships(Node n, bool isPos)
-{
- if (isPos)
- {
- NodeUIntMap::const_iterator it = d_pos_memberships.find(n);
- if (it != d_pos_memberships.end())
- {
- return (*it).second;
- }
- }
- else
- {
- NodeUIntMap::const_iterator it = d_neg_memberships.find(n);
- if (it != d_neg_memberships.end())
- {
- return (*it).second;
- }
- }
- return 0;
-}
-
-Node RegExpSolver::getMembership(Node n, bool isPos, unsigned i)
-{
- return isPos ? d_pos_memberships_data[n][i] : d_neg_memberships_data[n][i];
-}
-
Node RegExpSolver::mkAnd(Node c1, Node c2)
{
return NodeManager::currentNM()->mkNode(AND, c1, c2);
}
-void RegExpSolver::check()
+void RegExpSolver::check(const std::map<Node, std::vector<Node> >& mems)
{
bool addedLemma = false;
bool changed = false;
std::vector<Node> processed;
std::vector<Node> cprocessed;
- Trace("regexp-debug") << "Checking Memberships ... " << std::endl;
- for (NodeUIntMap::const_iterator itr_xr = d_pos_memberships.begin();
- itr_xr != d_pos_memberships.end();
- ++itr_xr)
+ Trace("regexp-process") << "Checking Memberships ... " << std::endl;
+ for (const std::pair<const Node, std::vector<Node> >& mr : mems)
{
- bool spflag = false;
- Node x = (*itr_xr).first;
- Trace("regexp-debug") << "Checking Memberships for " << x << std::endl;
- if (d_inter_index.find(x) == d_inter_index.end())
+ Trace("regexp-process")
+ << "Memberships(" << mr.first << ") = " << mr.second << std::endl;
+ if (!checkEqcIntersect(mr.second))
{
- d_inter_index[x] = 0;
- }
- int cur_inter_idx = d_inter_index[x];
- unsigned n_pmem = (*itr_xr).second;
- Assert(getNumMemberships(x, true) == n_pmem);
- if (cur_inter_idx != (int)n_pmem)
- {
- if (n_pmem == 1)
- {
- d_inter_cache[x] = getMembership(x, true, 0);
- d_inter_index[x] = 1;
- Trace("regexp-debug") << "... only one choice " << std::endl;
- }
- else if (n_pmem > 1)
- {
- Node r;
- if (d_inter_cache.find(x) != d_inter_cache.end())
- {
- r = d_inter_cache[x];
- }
- if (r.isNull())
- {
- r = getMembership(x, true, 0);
- cur_inter_idx = 1;
- }
-
- unsigned k_start = cur_inter_idx;
- Trace("regexp-debug") << "... staring from : " << cur_inter_idx
- << ", we have " << n_pmem << std::endl;
- for (unsigned k = k_start; k < n_pmem; k++)
- {
- Node r2 = getMembership(x, true, k);
- r = d_regexp_opr.intersect(r, r2, spflag);
- if (spflag)
- {
- break;
- }
- else if (r == d_emptyRegexp)
- {
- std::vector<Node> vec_nodes;
- for (unsigned kk = 0; kk <= k; kk++)
- {
- Node rr = getMembership(x, true, kk);
- Node n =
- NodeManager::currentNM()->mkNode(STRING_IN_REGEXP, x, rr);
- vec_nodes.push_back(n);
- }
- Node conc;
- d_im.sendInference(vec_nodes, conc, "INTERSECT CONFLICT", true);
- addedLemma = true;
- break;
- }
- if (d_im.hasConflict())
- {
- break;
- }
- }
- // updates
- if (!d_im.hasConflict() && !spflag)
- {
- d_inter_cache[x] = r;
- d_inter_index[x] = (int)n_pmem;
- }
- }
+ // conflict discovered, return
+ return;
}
}
@@ -174,6 +79,20 @@ void RegExpSolver::check()
<< std::endl;
if (!addedLemma)
{
+ // get all memberships
+ std::vector<Node> allMems;
+ for (const std::pair<const Node, std::vector<Node> >& mr : mems)
+ {
+ for (const Node& m : mr.second)
+ {
+ bool polarity = m.getKind() != NOT;
+ if (polarity || !options::stringIgnNegMembership())
+ {
+ allMems.push_back(m);
+ }
+ }
+ }
+
NodeManager* nm = NodeManager::currentNM();
// representatives of strings that are the LHS of positive memberships that
// we unfolded
@@ -181,7 +100,7 @@ void RegExpSolver::check()
// check positive (e=0), then negative (e=1) memberships
for (unsigned e = 0; e < 2; e++)
{
- for (const Node& assertion : d_regexp_memberships)
+ for (const Node& assertion : allMems)
{
// check regular expression membership
Trace("regexp-debug")
@@ -327,6 +246,90 @@ void RegExpSolver::check()
}
}
+bool RegExpSolver::checkEqcIntersect(const std::vector<Node>& mems)
+{
+ if (mems.empty())
+ {
+ // nothing to do
+ return true;
+ }
+ // the initial regular expression membership
+ Node mi;
+ NodeManager* nm = NodeManager::currentNM();
+ for (const Node& m : mems)
+ {
+ if (m.getKind() != STRING_IN_REGEXP)
+ {
+ // do not do negative
+ Assert(m.getKind() == NOT && m[0].getKind() == STRING_IN_REGEXP);
+ continue;
+ }
+ if (!d_regexp_opr.checkConstRegExp(m))
+ {
+ // cannot do intersection on RE with variables
+ continue;
+ }
+ if (mi.isNull())
+ {
+ // first regular expression seen
+ mi = m;
+ continue;
+ }
+ bool spflag = false;
+ Node resR = d_regexp_opr.intersect(mi[1], m[1], spflag);
+ // intersection should be computable
+ Assert(!resR.isNull());
+ Assert(!spflag);
+ if (resR == d_emptyRegexp)
+ {
+ // conflict, explain
+ std::vector<Node> vec_nodes;
+ vec_nodes.push_back(mi);
+ vec_nodes.push_back(m);
+ if (mi[0] != m[0])
+ {
+ vec_nodes.push_back(mi[0].eqNode(m[0]));
+ }
+ Node conc;
+ d_im.sendInference(vec_nodes, conc, "INTERSECT CONFLICT", true);
+ // conflict, return
+ return false;
+ }
+ // rewrite to ensure the equality checks below are precise
+ Node mres = Rewriter::rewrite(nm->mkNode(STRING_IN_REGEXP, mi[0], resR));
+ if (mres == mi)
+ {
+ // if R1 = intersect( R1, R2 ), then x in R1 ^ x in R2 is equivalent
+ // to x in R1, hence x in R2 can be marked redundant.
+ d_parent.getExtTheory()->markReduced(m);
+ }
+ else if (mres == m)
+ {
+ // same as above, opposite direction
+ d_parent.getExtTheory()->markReduced(mi);
+ }
+ else
+ {
+ // new conclusion
+ // (x in R ^ y in R2 ^ x = y) => (x in intersect(R1,R2))
+ std::vector<Node> vec_nodes;
+ vec_nodes.push_back(mi);
+ vec_nodes.push_back(m);
+ if (mi[0] != m[0])
+ {
+ vec_nodes.push_back(mi[0].eqNode(m[0]));
+ }
+ d_im.sendInference(vec_nodes, mres, "INTERSECT INFER", true);
+ // both are reduced
+ d_parent.getExtTheory()->markReduced(m);
+ d_parent.getExtTheory()->markReduced(mi);
+ // do not send more than one lemma for this class
+ return true;
+ }
+ }
+ return true;
+}
+
bool RegExpSolver::checkPDerivative(
Node x, Node r, Node atom, bool& addedLemma, std::vector<Node>& nf_exp)
{
@@ -452,83 +455,6 @@ bool RegExpSolver::deriveRegExp(Node x,
return false;
}
-void RegExpSolver::addMembership(Node assertion)
-{
- bool polarity = assertion.getKind() != NOT;
- TNode atom = polarity ? assertion : assertion[0];
- Node x = atom[0];
- Node r = atom[1];
- if (polarity)
- {
- unsigned index = 0;
- NodeUIntMap::const_iterator it = d_pos_memberships.find(x);
- if (it != d_pos_memberships.end())
- {
- index = (*it).second;
- for (unsigned k = 0; k < index; k++)
- {
- if (k < d_pos_memberships_data[x].size())
- {
- if (d_pos_memberships_data[x][k] == r)
- {
- return;
- }
- }
- else
- {
- break;
- }
- }
- }
- d_pos_memberships[x] = index + 1;
- if (index < d_pos_memberships_data[x].size())
- {
- d_pos_memberships_data[x][index] = r;
- }
- else
- {
- d_pos_memberships_data[x].push_back(r);
- }
- }
- else if (!options::stringIgnNegMembership())
- {
- unsigned index = 0;
- NodeUIntMap::const_iterator it = d_neg_memberships.find(x);
- if (it != d_neg_memberships.end())
- {
- index = (*it).second;
- for (unsigned k = 0; k < index; k++)
- {
- if (k < d_neg_memberships_data[x].size())
- {
- if (d_neg_memberships_data[x][k] == r)
- {
- return;
- }
- }
- else
- {
- break;
- }
- }
- }
- d_neg_memberships[x] = index + 1;
- if (index < d_neg_memberships_data[x].size())
- {
- d_neg_memberships_data[x][index] = r;
- }
- else
- {
- d_neg_memberships_data[x].push_back(r);
- }
- }
- // old
- if (polarity || !options::stringIgnNegMembership())
- {
- d_regexp_memberships.push_back(assertion);
- }
-}
-
Node RegExpSolver::getNormalSymRegExp(Node r, std::vector<Node>& nf_exp)
{
Node ret = r;
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback