summaryrefslogtreecommitdiff
path: root/src/theory/strings/base_solver.cpp
diff options
context:
space:
mode:
authorAndrew Reynolds <andrew.j.reynolds@gmail.com>2020-02-22 01:05:43 -0600
committerGitHub <noreply@github.com>2020-02-21 23:05:43 -0800
commit9b20af281db3e77a25540305dfb73cbe56519f75 (patch)
tree2122c9f51c7d536621a3e3d32da66216d3cde1e8 /src/theory/strings/base_solver.cpp
parenta626d85e490256a5d872fec49910cdb43e85c16d (diff)
Move cardinality inference scheme to base solver in strings (#3792)
Moves handling of cardinality to the base solver, refactors how cardinality is accessed. No intended behavior change in this commit.
Diffstat (limited to 'src/theory/strings/base_solver.cpp')
-rw-r--r--src/theory/strings/base_solver.cpp133
1 files changed, 133 insertions, 0 deletions
diff --git a/src/theory/strings/base_solver.cpp b/src/theory/strings/base_solver.cpp
index 2f5bc8e2b..343f6e4f8 100644
--- a/src/theory/strings/base_solver.cpp
+++ b/src/theory/strings/base_solver.cpp
@@ -35,6 +35,7 @@ BaseSolver::BaseSolver(context::Context* c,
{
d_emptyString = NodeManager::currentNM()->mkConst(::CVC4::String(""));
d_false = NodeManager::currentNM()->mkConst(false);
+ d_cardSize = utils::getAlphabetCardinality();
}
BaseSolver::~BaseSolver() {}
@@ -359,6 +360,138 @@ void BaseSolver::checkConstantEquivalenceClasses(TermIndex* ti,
}
}
+void BaseSolver::checkCardinality()
+{
+ // This will create a partition of eqc, where each collection has length that
+ // are pairwise propagated to be equal. We do not require disequalities
+ // between the lengths of each collection, since we split on disequalities
+ // between lengths of string terms that are disequal (DEQ-LENGTH-SP).
+ std::vector<std::vector<Node> > cols;
+ std::vector<Node> lts;
+ d_state.separateByLength(d_stringsEqc, cols, lts);
+ NodeManager* nm = NodeManager::currentNM();
+ Trace("strings-card") << "Check cardinality...." << std::endl;
+ // for each collection
+ for (unsigned i = 0, csize = cols.size(); i < csize; ++i)
+ {
+ Node lr = lts[i];
+ Trace("strings-card") << "Number of strings with length equal to " << lr
+ << " is " << cols[i].size() << std::endl;
+ if (cols[i].size() <= 1)
+ {
+ // no restriction on sets in the partition of size 1
+ continue;
+ }
+ // size > c^k
+ unsigned card_need = 1;
+ double curr = static_cast<double>(cols[i].size());
+ while (curr > d_cardSize)
+ {
+ curr = curr / static_cast<double>(d_cardSize);
+ card_need++;
+ }
+ Trace("strings-card")
+ << "Need length " << card_need
+ << " for this number of strings (where alphabet size is " << d_cardSize
+ << ")." << std::endl;
+ // check if we need to split
+ bool needsSplit = true;
+ if (lr.isConst())
+ {
+ // if constant, compare
+ Node cmp = nm->mkNode(GEQ, lr, nm->mkConst(Rational(card_need)));
+ cmp = Rewriter::rewrite(cmp);
+ needsSplit = !cmp.getConst<bool>();
+ }
+ else
+ {
+ // find the minimimum constant that we are unknown to be disequal from, or
+ // otherwise stop if we increment such that cardinality does not apply
+ unsigned r = 0;
+ bool success = true;
+ while (r < card_need && success)
+ {
+ Node rr = nm->mkConst(Rational(r));
+ if (d_state.areDisequal(rr, lr))
+ {
+ r++;
+ }
+ else
+ {
+ success = false;
+ }
+ }
+ if (r > 0)
+ {
+ Trace("strings-card")
+ << "Symbolic length " << lr << " must be at least " << r
+ << " due to constant disequalities." << std::endl;
+ }
+ needsSplit = r < card_need;
+ }
+
+ if (!needsSplit)
+ {
+ // don't need to split
+ continue;
+ }
+ // first, try to split to merge equivalence classes
+ for (std::vector<Node>::iterator itr1 = cols[i].begin();
+ itr1 != cols[i].end();
+ ++itr1)
+ {
+ for (std::vector<Node>::iterator itr2 = itr1 + 1; itr2 != cols[i].end();
+ ++itr2)
+ {
+ if (!d_state.areDisequal(*itr1, *itr2))
+ {
+ // add split lemma
+ if (d_im.sendSplit(*itr1, *itr2, "CARD-SP"))
+ {
+ return;
+ }
+ }
+ }
+ }
+ // otherwise, we need a length constraint
+ uint32_t int_k = static_cast<uint32_t>(card_need);
+ EqcInfo* ei = d_state.getOrMakeEqcInfo(lr, true);
+ Trace("strings-card") << "Previous cardinality used for " << lr << " is "
+ << ((int)ei->d_cardinalityLemK.get() - 1)
+ << std::endl;
+ if (int_k + 1 > ei->d_cardinalityLemK.get())
+ {
+ Node k_node = nm->mkConst(Rational(int_k));
+ // add cardinality lemma
+ Node dist = nm->mkNode(DISTINCT, cols[i]);
+ std::vector<Node> vec_node;
+ vec_node.push_back(dist);
+ for (std::vector<Node>::iterator itr1 = cols[i].begin();
+ itr1 != cols[i].end();
+ ++itr1)
+ {
+ Node len = nm->mkNode(STRING_LENGTH, *itr1);
+ if (len != lr)
+ {
+ Node len_eq_lr = len.eqNode(lr);
+ vec_node.push_back(len_eq_lr);
+ }
+ }
+ Node len = nm->mkNode(STRING_LENGTH, cols[i][0]);
+ Node cons = nm->mkNode(GEQ, len, k_node);
+ cons = Rewriter::rewrite(cons);
+ ei->d_cardinalityLemK.set(int_k + 1);
+ if (!cons.isConst() || !cons.getConst<bool>())
+ {
+ std::vector<Node> emptyVec;
+ d_im.sendInference(emptyVec, vec_node, cons, "CARDINALITY", true);
+ return;
+ }
+ }
+ }
+ Trace("strings-card") << "...end check cardinality" << std::endl;
+}
+
bool BaseSolver::isCongruent(Node n)
{
return d_congruent.find(n) != d_congruent.end();
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback