mirror of
https://github.com/Z3Prover/z3
synced 2026-06-02 15:17:54 +00:00
Remove recursive paths from model construction
This commit is contained in:
parent
cedb13d045
commit
5dcc5efcdd
1 changed files with 27 additions and 40 deletions
|
|
@ -191,8 +191,7 @@ namespace smt {
|
||||||
vector<std::pair<euf::snode*, euf::snode*>> bindings;
|
vector<std::pair<euf::snode*, euf::snode*>> bindings;
|
||||||
for (seq::nielsen_edge* e : sat_path) {
|
for (seq::nielsen_edge* e : sat_path) {
|
||||||
for (seq::nielsen_subst const& s : e->subst()) {
|
for (seq::nielsen_subst const& s : e->subst()) {
|
||||||
if (!s.m_var)
|
SASSERT(s.m_var);
|
||||||
continue;
|
|
||||||
IF_VERBOSE(1, {
|
IF_VERBOSE(1, {
|
||||||
verbose_stream() << " subst: snode[" << s.m_var->id() << "]";
|
verbose_stream() << " subst: snode[" << s.m_var->id() << "]";
|
||||||
if (s.m_var->get_expr()) verbose_stream() << "=" << mk_bounded_pp(s.m_var->get_expr(), m, 2);
|
if (s.m_var->get_expr()) verbose_stream() << "=" << mk_bounded_pp(s.m_var->get_expr(), m, 2);
|
||||||
|
|
@ -210,17 +209,18 @@ namespace smt {
|
||||||
for (auto const &[var, replacement] : bindings) {
|
for (auto const &[var, replacement] : bindings) {
|
||||||
SASSERT(var);
|
SASSERT(var);
|
||||||
unsigned id = var->first()->id(); // TODO - first or just var->id()?
|
unsigned id = var->first()->id(); // TODO - first or just var->id()?
|
||||||
if (!m_var_replacement.contains(id))
|
SASSERT(!m_var_replacement.contains(id));
|
||||||
m_var_replacement.insert(id, replacement);
|
m_var_replacement.insert(id, replacement);
|
||||||
|
std::cout << "Assignment: " << mk_pp(var->get_expr(), m) << ": " << mk_pp(replacement->get_expr(), m) << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void seq_model::collect_dependencies(euf::snode *n, ptr_vector<enode> &deps) const {
|
void seq_model::collect_dependencies(euf::snode *n, ptr_vector<enode> &deps) const {
|
||||||
uint_set seen;
|
uint_set seen;
|
||||||
buffer<std::pair<euf::snode*, bool>> todo;
|
buffer<euf::snode*> todo;
|
||||||
todo.push_back({n, false});
|
todo.push_back(n);
|
||||||
while (!todo.empty()) {
|
while (!todo.empty()) {
|
||||||
auto [curr, is_recursive] = todo.back();
|
auto curr = todo.back();
|
||||||
todo.pop_back();
|
todo.pop_back();
|
||||||
if (seen.contains(curr->id()))
|
if (seen.contains(curr->id()))
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -236,7 +236,7 @@ namespace smt {
|
||||||
}
|
}
|
||||||
else if (curr->is_concat()) {
|
else if (curr->is_concat()) {
|
||||||
for (unsigned i = 0; i < curr->num_args(); ++i)
|
for (unsigned i = 0; i < curr->num_args(); ++i)
|
||||||
todo.push_back({curr->arg(i), is_recursive});
|
todo.push_back(curr->arg(i));
|
||||||
}
|
}
|
||||||
else if (curr->is_power()) {
|
else if (curr->is_power()) {
|
||||||
// pretend there are no dependencies
|
// pretend there are no dependencies
|
||||||
|
|
@ -249,8 +249,8 @@ namespace smt {
|
||||||
// map the values that are passed in to the sub-terms that are listed as dependencies.
|
// map the values that are passed in to the sub-terms that are listed as dependencies.
|
||||||
// sub-terms are under concat, power and unit
|
// sub-terms are under concat, power and unit
|
||||||
euf::snode *replacement = nullptr;
|
euf::snode *replacement = nullptr;
|
||||||
if (!is_recursive && m_var_replacement.find(curr->id(), replacement))
|
if (m_var_replacement.find(curr->id(), replacement))
|
||||||
todo.push_back({replacement, true});
|
todo.push_back(replacement);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
IF_VERBOSE(0, {
|
IF_VERBOSE(0, {
|
||||||
|
|
@ -276,26 +276,26 @@ namespace smt {
|
||||||
// and the inner "leftover" remainder (is_recursive == true, value == "").
|
// and the inner "leftover" remainder (is_recursive == true, value == "").
|
||||||
u_map<expr *> var2value;
|
u_map<expr *> var2value;
|
||||||
u_map<expr *> node2value;
|
u_map<expr *> node2value;
|
||||||
auto mk_key = [](euf::snode* s, bool r) { return s->id() * 2 + (r ? 1u : 0u); };
|
|
||||||
// resolve: check leaf deps by expression ID, computed nodes by (snode,recursive) key.
|
// resolve: check leaf deps by expression ID, computed nodes by (snode,recursive) key.
|
||||||
auto resolve = [&](euf::snode* s, bool r, expr*& out) -> bool {
|
auto resolve = [&](euf::snode* s, expr*& out) -> bool {
|
||||||
if (var2value.find(s->get_expr()->get_id(), out))
|
if (var2value.find(s->get_expr()->get_id(), out))
|
||||||
return true;
|
return true;
|
||||||
return node2value.find(mk_key(s, r), out);
|
return node2value.find(s->id(), out);
|
||||||
};
|
};
|
||||||
buffer<std::pair<euf::snode *, bool>> todo;
|
buffer<euf::snode *> todo;
|
||||||
for (unsigned i = 0; i < deps.size(); ++i)
|
for (unsigned i = 0; i < deps.size(); ++i) {
|
||||||
var2value.insert(deps[i]->get_expr_id(), values[i]);
|
var2value.insert(deps[i]->get_expr_id(), values[i]);
|
||||||
todo.push_back({n, false});
|
}
|
||||||
|
todo.push_back(n);
|
||||||
expr_ref_vector args(m), pinned(m);
|
expr_ref_vector args(m), pinned(m);
|
||||||
arith_util a(m);
|
arith_util a(m);
|
||||||
|
|
||||||
expr *val = nullptr;
|
expr *val = nullptr;
|
||||||
while (!todo.empty()) {
|
while (!todo.empty()) {
|
||||||
auto [curr, is_recursive] = todo.back();
|
auto curr = todo.back();
|
||||||
// Early exit: already computed (as leaf dep or computed node).
|
// Early exit: already computed (as leaf dep or computed node).
|
||||||
expr* cached = nullptr;
|
expr* cached = nullptr;
|
||||||
if (resolve(curr, is_recursive, cached)) {
|
if (resolve(curr, cached)) {
|
||||||
todo.pop_back();
|
todo.pop_back();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -331,10 +331,10 @@ namespace smt {
|
||||||
for (unsigned i = 0; i < curr->num_args(); ++i) {
|
for (unsigned i = 0; i < curr->num_args(); ++i) {
|
||||||
auto arg = curr->arg(i);
|
auto arg = curr->arg(i);
|
||||||
expr* av = nullptr;
|
expr* av = nullptr;
|
||||||
if (resolve(arg, is_recursive, av))
|
if (resolve(arg, av))
|
||||||
args.push_back(av);
|
args.push_back(av);
|
||||||
else {
|
else {
|
||||||
todo.push_back({arg, is_recursive});
|
todo.push_back(arg);
|
||||||
all_ready = false;
|
all_ready = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -345,28 +345,15 @@ namespace smt {
|
||||||
}
|
}
|
||||||
else if (curr->is_var()) {
|
else if (curr->is_var()) {
|
||||||
euf::snode *replacement = nullptr;
|
euf::snode *replacement = nullptr;
|
||||||
if (!is_recursive && m_var_replacement.find(curr->id(), replacement)) {
|
if (m_var_replacement.find(curr->id(), replacement)) {
|
||||||
// outer variable: its value is the value of its replacement.
|
// outer variable: its value is the value of its replacement.
|
||||||
expr* rv = nullptr;
|
expr* rv = nullptr;
|
||||||
if (!resolve(replacement, true, rv)) {
|
if (!resolve(replacement, rv)) {
|
||||||
todo.push_back({replacement, true});
|
todo.push_back(replacement);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
val = rv;
|
val = rv;
|
||||||
}
|
}
|
||||||
else if (is_recursive) {
|
|
||||||
// recursive "leftover" remainder of a Nielsen substitution
|
|
||||||
// such as x -> [nth_u(x,k)] ++ x. If the variable still
|
|
||||||
// carries a primitive membership at the satisfying node
|
|
||||||
// (recorded in m_var_regex), the leftover is a genuine
|
|
||||||
// non-empty witness of that residual regex, not an
|
|
||||||
// eliminated remainder. Otherwise the path drove it to the
|
|
||||||
// empty string.
|
|
||||||
if (m_var_regex.contains(curr->first()->id()))
|
|
||||||
val = get_var_value(curr);
|
|
||||||
else
|
|
||||||
val = m_seq.str.mk_empty(curr->get_sort());
|
|
||||||
}
|
|
||||||
else {
|
else {
|
||||||
// genuinely free variable (no replacement): respect its
|
// genuinely free variable (no replacement): respect its
|
||||||
// length / regex constraints.
|
// length / regex constraints.
|
||||||
|
|
@ -377,12 +364,12 @@ namespace smt {
|
||||||
IF_VERBOSE(0, verbose_stream() << "not handled " << mk_pp(curr->get_expr(), m) << "\n");
|
IF_VERBOSE(0, verbose_stream() << "not handled " << mk_pp(curr->get_expr(), m) << "\n");
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
node2value.insert(mk_key(curr, is_recursive), val);
|
node2value.insert(curr->id(), val);
|
||||||
pinned.push_back(val);
|
pinned.push_back(val);
|
||||||
todo.pop_back();
|
todo.pop_back();
|
||||||
}
|
}
|
||||||
expr* result = nullptr;
|
expr* result = nullptr;
|
||||||
node2value.find(mk_key(n, false), result);
|
node2value.find(n->id(), result);
|
||||||
if (!result)
|
if (!result)
|
||||||
var2value.find(n->get_expr()->get_id(), result);
|
var2value.find(n->get_expr()->get_id(), result);
|
||||||
return expr_ref(result, m);
|
return expr_ref(result, m);
|
||||||
|
|
@ -502,13 +489,13 @@ namespace smt {
|
||||||
unsigned n = len_val.get_unsigned();
|
unsigned n = len_val.get_unsigned();
|
||||||
zstring w;
|
zstring w;
|
||||||
for (unsigned i = 0; i < n; ++i)
|
for (unsigned i = 0; i < n; ++i)
|
||||||
w += zstring('0');
|
w += zstring('a');
|
||||||
expr* witness = m_seq.str.mk_string(w);
|
expr* witness = m_seq.str.mk_string(w);
|
||||||
m_factory->register_value(witness);
|
m_factory->register_value(witness);
|
||||||
return witness;
|
return witness;
|
||||||
}
|
}
|
||||||
|
|
||||||
expr* base = m_seq.str.mk_string("0");
|
expr* base = m_seq.str.mk_string("a");
|
||||||
expr* witness = m_seq.str.mk_power(base, arith.mk_int(len_val));
|
expr* witness = m_seq.str.mk_power(base, arith.mk_int(len_val));
|
||||||
m_factory->register_value(witness);
|
m_factory->register_value(witness);
|
||||||
return witness;
|
return witness;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue