mirror of
https://github.com/Z3Prover/z3
synced 2026-06-07 09:30:54 +00:00
na
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
0c4e4ad702
commit
725b13680e
6 changed files with 80 additions and 104 deletions
|
|
@ -332,27 +332,26 @@ namespace euf {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
snode* sgraph::mk_snode(expr* e, snode_kind k, unsigned num_args, snode* const* args) {
|
snode *sgraph::mk_snode(expr *e, snode_kind k, unsigned num_args, snode *const *args) {
|
||||||
|
SASSERT(e);
|
||||||
unsigned id = m_nodes.size();
|
unsigned id = m_nodes.size();
|
||||||
snode* n = snode::mk(m_region, e, k, id, num_args, args);
|
snode *n = snode::mk(m_region, e, k, id, num_args, args);
|
||||||
compute_metadata(n);
|
compute_metadata(n);
|
||||||
compute_hash_matrix(n);
|
compute_hash_matrix(n);
|
||||||
m_nodes.push_back(n);
|
m_nodes.push_back(n);
|
||||||
SASSERT(!n->is_char_or_unit() || m_seq.str.is_unit(n->get_expr()));
|
SASSERT(!n->is_char_or_unit() || m_seq.str.is_unit(n->get_expr()));
|
||||||
|
unsigned eid = e->get_id();
|
||||||
if (e) {
|
m_expr2snode.reserve(eid + 1, nullptr);
|
||||||
unsigned eid = e->get_id();
|
m_expr2snode[eid] = n;
|
||||||
m_expr2snode.reserve(eid + 1, nullptr);
|
// pin expression via egraph (the egraph has an expr trail)
|
||||||
m_expr2snode[eid] = n;
|
mk_enode(e);
|
||||||
// pin expression via egraph (the egraph has an expr trail)
|
|
||||||
mk_enode(e);
|
|
||||||
}
|
|
||||||
++m_stats.m_num_nodes;
|
++m_stats.m_num_nodes;
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
snode* sgraph::mk(expr* e) {
|
snode* sgraph::mk(expr* e) {
|
||||||
SASSERT(e);
|
SASSERT(e);
|
||||||
|
expr_ref _e(e, m); // pin locally to not clash with character creation, never needed if we use mk_enode early.
|
||||||
snode* n = find(e);
|
snode* n = find(e);
|
||||||
if (n)
|
if (n)
|
||||||
return n;
|
return n;
|
||||||
|
|
|
||||||
|
|
@ -1275,8 +1275,7 @@ namespace seq {
|
||||||
: "UNKNOWN")
|
: "UNKNOWN")
|
||||||
<< "\n";);
|
<< "\n";);
|
||||||
if (r == search_result::sat) {
|
if (r == search_result::sat) {
|
||||||
IF_VERBOSE(
|
IF_VERBOSE(1,
|
||||||
1,
|
|
||||||
verbose_stream() << "side constraints: \n";
|
verbose_stream() << "side constraints: \n";
|
||||||
for (auto const &c : cur_path.back()->side_constraints()) {
|
for (auto const &c : cur_path.back()->side_constraints()) {
|
||||||
verbose_stream() << " side constraint: " << c.fml << "\n";
|
verbose_stream() << " side constraint: " << c.fml << "\n";
|
||||||
|
|
@ -1289,6 +1288,7 @@ namespace seq {
|
||||||
++m_stats.m_num_unsat;
|
++m_stats.m_num_unsat;
|
||||||
auto deps = collect_conflict_deps();
|
auto deps = collect_conflict_deps();
|
||||||
m_dep_mgr.linearize(deps, m_conflict_sources);
|
m_dep_mgr.linearize(deps, m_conflict_sources);
|
||||||
|
TRACE(seq, display(tout, m_root));
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
// depth limit hit – double the bound and retry
|
// depth limit hit – double the bound and retry
|
||||||
|
|
@ -1420,7 +1420,7 @@ namespace seq {
|
||||||
// for each variable with multiple regex constraints, verify
|
// for each variable with multiple regex constraints, verify
|
||||||
// that the intersection of all its regexes is non-empty.
|
// that the intersection of all its regexes is non-empty.
|
||||||
// Mirrors ZIPT NielsenNode.CheckRegex.
|
// Mirrors ZIPT NielsenNode.CheckRegex.
|
||||||
dep_tracker dep;
|
dep_tracker dep = nullptr;
|
||||||
if (!check_leaf_regex(*node, dep)) {
|
if (!check_leaf_regex(*node, dep)) {
|
||||||
node->set_general_conflict();
|
node->set_general_conflict();
|
||||||
node->set_conflict(backtrack_reason::regex, dep);
|
node->set_conflict(backtrack_reason::regex, dep);
|
||||||
|
|
@ -3655,18 +3655,14 @@ namespace seq {
|
||||||
SASSERT(n->m_conflict_external_literal == sat::null_literal);
|
SASSERT(n->m_conflict_external_literal == sat::null_literal);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
SASSERT(n->is_currently_conflict());
|
|
||||||
if (n->m_conflict_external_literal != sat::null_literal) {
|
|
||||||
// We know from the outer solver that this literal is assigned false
|
|
||||||
deps = m_dep_mgr.mk_join(deps, m_dep_mgr.mk_leaf(n->m_conflict_external_literal));
|
|
||||||
if (n->m_conflict_internal)
|
|
||||||
deps = m_dep_mgr.mk_join(deps, n->m_conflict_internal);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
SASSERT(n->outgoing().empty());
|
SASSERT(n->outgoing().empty());
|
||||||
SASSERT(n->m_conflict_internal);
|
SASSERT(n->is_currently_conflict());
|
||||||
deps = m_dep_mgr.mk_join(deps, n->m_conflict_internal);
|
if (n->m_conflict_external_literal != sat::null_literal)
|
||||||
|
// We know from the outer solver that this literal is assigned true and contradicts node constraint
|
||||||
|
deps = m_dep_mgr.mk_join(deps, m_dep_mgr.mk_leaf(n->m_conflict_external_literal));
|
||||||
|
|
||||||
|
if (n->m_conflict_internal)
|
||||||
|
deps = m_dep_mgr.mk_join(deps, n->m_conflict_internal);
|
||||||
}
|
}
|
||||||
return deps;
|
return deps;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -118,15 +118,11 @@ namespace seq {
|
||||||
|
|
||||||
// Multiple stabilizers: build re.union chain.
|
// Multiple stabilizers: build re.union chain.
|
||||||
// union(s1, union(s2, ... union(sN-1, sN)...))
|
// union(s1, union(s2, ... union(sN-1, sN)...))
|
||||||
seq_util& seq = m_sg.get_seq_util();
|
|
||||||
euf::snode* result = stabs[stabs.size() - 1];
|
euf::snode* result = stabs[stabs.size() - 1];
|
||||||
for (unsigned i = stabs.size() - 1; i-- > 0; ) {
|
for (unsigned i = stabs.size() - 1; i-- > 0; ) {
|
||||||
expr* lhs = stabs[i]->get_expr();
|
expr* lhs = stabs[i]->get_expr();
|
||||||
expr* rhs = result->get_expr();
|
expr* rhs = result->get_expr();
|
||||||
if (!lhs || !rhs)
|
result = m_sg.mk(seq.re.mk_union(lhs, rhs));
|
||||||
return nullptr;
|
|
||||||
expr_ref un(seq.re.mk_union(lhs, rhs), m_sg.get_manager());
|
|
||||||
result = m_sg.mk(un);
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
@ -374,10 +370,7 @@ namespace seq {
|
||||||
if (re->is_loop() && re->is_nullable())
|
if (re->is_loop() && re->is_nullable())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
seq_util& seq = m_sg.get_seq_util();
|
|
||||||
expr* e = re->get_expr();
|
expr* e = re->get_expr();
|
||||||
if (!e)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
expr* r1, * r2;
|
expr* r1, * r2;
|
||||||
// union is empty iff both children are empty
|
// union is empty iff both children are empty
|
||||||
|
|
@ -413,7 +406,6 @@ namespace seq {
|
||||||
void seq_regex::collect_char_boundaries(euf::snode* re, unsigned_vector& bounds) const {
|
void seq_regex::collect_char_boundaries(euf::snode* re, unsigned_vector& bounds) const {
|
||||||
SASSERT(re && re->get_expr());
|
SASSERT(re && re->get_expr());
|
||||||
|
|
||||||
seq_util& seq = m_sg.get_seq_util();
|
|
||||||
expr* e = re->get_expr();
|
expr* e = re->get_expr();
|
||||||
|
|
||||||
// Range predicate re.range(lo, hi): boundary at lo and hi+1
|
// Range predicate re.range(lo, hi): boundary at lo and hi+1
|
||||||
|
|
@ -463,7 +455,6 @@ namespace seq {
|
||||||
if (!re || !re->get_expr())
|
if (!re || !re->get_expr())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
seq_util& seq = m_sg.get_seq_util();
|
|
||||||
unsigned max_c = seq.max_char();
|
unsigned max_c = seq.max_char();
|
||||||
|
|
||||||
// Partition the alphabet using boundary points induced by regex
|
// Partition the alphabet using boundary points induced by regex
|
||||||
|
|
@ -536,7 +527,7 @@ namespace seq {
|
||||||
unsigned states_explored = 0;
|
unsigned states_explored = 0;
|
||||||
|
|
||||||
while (!worklist.empty()) {
|
while (!worklist.empty()) {
|
||||||
if (!m_sg.get_manager().inc())
|
if (!m.inc())
|
||||||
return l_undef;
|
return l_undef;
|
||||||
if (states_explored >= max_states)
|
if (states_explored >= max_states)
|
||||||
return l_undef;
|
return l_undef;
|
||||||
|
|
@ -558,7 +549,7 @@ namespace seq {
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for (euf::snode* ch : reps) {
|
for (euf::snode* ch : reps) {
|
||||||
if (!m_sg.get_manager().inc())
|
if (!m.inc())
|
||||||
return l_undef;
|
return l_undef;
|
||||||
// std::cout << "Deriving by " << snode_label_html(ch, sg().get_manager()) << std::endl;
|
// std::cout << "Deriving by " << snode_label_html(ch, sg().get_manager()) << std::endl;
|
||||||
euf::snode* deriv = m_sg.brzozowski_deriv(current, ch);
|
euf::snode* deriv = m_sg.brzozowski_deriv(current, ch);
|
||||||
|
|
@ -594,9 +585,6 @@ namespace seq {
|
||||||
if (regexes.size() == 1)
|
if (regexes.size() == 1)
|
||||||
return is_empty_bfs(regexes[0], max_states);
|
return is_empty_bfs(regexes[0], max_states);
|
||||||
|
|
||||||
seq_util& seq = m_sg.get_seq_util();
|
|
||||||
ast_manager& mgr = m_sg.get_manager();
|
|
||||||
|
|
||||||
euf::snode* result = regexes[0];
|
euf::snode* result = regexes[0];
|
||||||
for (unsigned i = 1; i < regexes.size(); ++i) {
|
for (unsigned i = 1; i < regexes.size(); ++i) {
|
||||||
expr* r1 = result->get_expr();
|
expr* r1 = result->get_expr();
|
||||||
|
|
@ -628,26 +616,14 @@ namespace seq {
|
||||||
return l_true; // L ⊆ L
|
return l_true; // L ⊆ L
|
||||||
|
|
||||||
// Build complement(superset)
|
// Build complement(superset)
|
||||||
seq_util& seq = m_sg.get_seq_util();
|
|
||||||
ast_manager& mgr = m_sg.get_manager();
|
|
||||||
expr* sup_expr = superset_re->get_expr();
|
expr* sup_expr = superset_re->get_expr();
|
||||||
if (!sup_expr)
|
euf::snode *comp_sn = m_sg.mk(seq.re.mk_complement(sup_expr));
|
||||||
return l_undef;
|
|
||||||
expr_ref comp(seq.re.mk_complement(sup_expr), mgr);
|
|
||||||
euf::snode* comp_sn = m_sg.mk(comp);
|
|
||||||
if (!comp_sn)
|
|
||||||
return l_undef;
|
|
||||||
|
|
||||||
// Build intersection and check emptiness
|
// Build intersection and check emptiness
|
||||||
// subset ∩ complement(superset) should be empty for subset relation
|
// subset ∩ complement(superset) should be empty for subset relation
|
||||||
expr* sub_expr = subset_re->get_expr();
|
expr* sub_expr = subset_re->get_expr();
|
||||||
if (!sub_expr)
|
auto inter = seq.re.mk_inter(sub_expr, comp_sn->get_expr());
|
||||||
return l_undef;
|
|
||||||
expr_ref inter(seq.re.mk_inter(sub_expr, comp.get()), mgr);
|
|
||||||
euf::snode* inter_sn = m_sg.mk(inter);
|
euf::snode* inter_sn = m_sg.mk(inter);
|
||||||
if (!inter_sn)
|
|
||||||
return l_undef;
|
|
||||||
|
|
||||||
return is_empty_bfs(inter_sn);
|
return is_empty_bfs(inter_sn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -659,8 +635,6 @@ namespace seq {
|
||||||
euf::snode* var, nielsen_node const& node, dep_manager& dep_mgr, dep_tracker& dep) const {
|
euf::snode* var, nielsen_node const& node, dep_manager& dep_mgr, dep_tracker& dep) const {
|
||||||
SASSERT(var);
|
SASSERT(var);
|
||||||
|
|
||||||
seq_util& seq = m_sg.get_seq_util();
|
|
||||||
ast_manager& m = m_sg.get_manager();
|
|
||||||
euf::snode* result = nullptr;
|
euf::snode* result = nullptr;
|
||||||
|
|
||||||
for (auto const& mem : node.str_mems()) {
|
for (auto const& mem : node.str_mems()) {
|
||||||
|
|
@ -672,7 +646,7 @@ namespace seq {
|
||||||
SASSERT(first);
|
SASSERT(first);
|
||||||
if (first != var)
|
if (first != var)
|
||||||
continue;
|
continue;
|
||||||
TRACE(seq, tout << mk_pp(first->get_expr(), m) << " " << mem_pp(m, mem) << "\n");
|
TRACE(seq, tout << spp(first, m) << " " << mem_pp(m, mem) << "\n");
|
||||||
|
|
||||||
if (!result) {
|
if (!result) {
|
||||||
result = mem.m_regex;
|
result = mem.m_regex;
|
||||||
|
|
@ -682,7 +656,7 @@ namespace seq {
|
||||||
expr* r1 = result->get_expr();
|
expr* r1 = result->get_expr();
|
||||||
expr* r2 = mem.m_regex->get_expr();
|
expr* r2 = mem.m_regex->get_expr();
|
||||||
if (r1 && r2) {
|
if (r1 && r2) {
|
||||||
expr_ref inter(seq.re.mk_inter(r1, r2), m);
|
auto inter = seq.re.mk_inter(r1, r2);
|
||||||
result = m_sg.mk(inter);
|
result = m_sg.mk(inter);
|
||||||
dep = dep_mgr.mk_join(dep, mem.m_dep);
|
dep = dep_mgr.mk_join(dep, mem.m_dep);
|
||||||
}
|
}
|
||||||
|
|
@ -742,8 +716,6 @@ namespace seq {
|
||||||
// For now, only handle the case where the entire string is ground:
|
// For now, only handle the case where the entire string is ground:
|
||||||
// consume all characters from the front (which covers trailing chars
|
// consume all characters from the front (which covers trailing chars
|
||||||
// when the string is fully ground).
|
// when the string is fully ground).
|
||||||
if (!mem.m_str || !mem.m_regex)
|
|
||||||
return simplify_status::ok;
|
|
||||||
if (!mem.m_str->is_ground())
|
if (!mem.m_str->is_ground())
|
||||||
return simplify_status::ok;
|
return simplify_status::ok;
|
||||||
|
|
||||||
|
|
@ -756,8 +728,7 @@ namespace seq {
|
||||||
// -----------------------------------------------------------------------
|
// -----------------------------------------------------------------------
|
||||||
|
|
||||||
int seq_regex::check_trivial(seq::str_mem const& mem) const {
|
int seq_regex::check_trivial(seq::str_mem const& mem) const {
|
||||||
if (!mem.m_str || !mem.m_regex)
|
SASSERT(mem.m_str && mem.m_regex);
|
||||||
return 0;
|
|
||||||
// regex is ∅ => always conflict
|
// regex is ∅ => always conflict
|
||||||
if (is_empty_regex(mem.m_regex))
|
if (is_empty_regex(mem.m_regex))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
@ -802,8 +773,7 @@ namespace seq {
|
||||||
|
|
||||||
bool seq_regex::process_str_mem(seq::str_mem const& mem,
|
bool seq_regex::process_str_mem(seq::str_mem const& mem,
|
||||||
vector<seq::str_mem>& out_mems) {
|
vector<seq::str_mem>& out_mems) {
|
||||||
if (!mem.m_str || !mem.m_regex)
|
SASSERT(mem.m_str && mem.m_regex);
|
||||||
return true;
|
|
||||||
// empty string: check nullable
|
// empty string: check nullable
|
||||||
if (mem.m_str->is_empty())
|
if (mem.m_str->is_empty())
|
||||||
return mem.m_regex->is_nullable();
|
return mem.m_regex->is_nullable();
|
||||||
|
|
@ -840,6 +810,7 @@ namespace seq {
|
||||||
// -----------------------------------------------------------------------
|
// -----------------------------------------------------------------------
|
||||||
|
|
||||||
seq::str_mem seq_regex::record_history(seq::str_mem const& mem, euf::snode* history_re) {
|
seq::str_mem seq_regex::record_history(seq::str_mem const& mem, euf::snode* history_re) {
|
||||||
|
|
||||||
return str_mem(mem.m_str, mem.m_regex, mem.m_dep);
|
return str_mem(mem.m_str, mem.m_regex, mem.m_dep);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -848,6 +819,38 @@ namespace seq {
|
||||||
// -----------------------------------------------------------------------
|
// -----------------------------------------------------------------------
|
||||||
|
|
||||||
euf::snode* seq_regex::extract_cycle(seq::str_mem const& mem) const {
|
euf::snode* seq_regex::extract_cycle(seq::str_mem const& mem) const {
|
||||||
|
#if 0
|
||||||
|
// Walk the history chain looking for a repeated regex.
|
||||||
|
// A cycle exists when the current regex matches a regex in the history.
|
||||||
|
if (!mem.m_regex || !mem.m_history)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
euf::snode* current = mem.m_regex;
|
||||||
|
euf::snode* hist = mem.m_history;
|
||||||
|
|
||||||
|
// Walk the history chain up to a bounded depth.
|
||||||
|
// The history is structured as a chain of regex snapshots connected
|
||||||
|
// via the sgraph's regex-concat: each level's arg(0) is a snapshot
|
||||||
|
// and arg(1) is the tail. A leaf (non-concat) is a terminal entry.
|
||||||
|
unsigned bound = 1000;
|
||||||
|
while (hist && bound-- > 0) {
|
||||||
|
euf::snode* entry = hist;
|
||||||
|
euf::snode* tail = nullptr;
|
||||||
|
|
||||||
|
// If the history node is a regex concat, decompose it:
|
||||||
|
// arg(0) is the regex snapshot, arg(1) is the rest of the chain
|
||||||
|
if (hist->is_concat() && seq.re.is_concat(hist->get_expr())) {
|
||||||
|
entry = hist->arg(0);
|
||||||
|
tail = hist->arg(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check pointer equality (fast, covers normalized regexes)
|
||||||
|
if (entry == current)
|
||||||
|
return entry;
|
||||||
|
|
||||||
|
hist = tail;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -861,11 +864,7 @@ namespace seq {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
expr* re_expr = cycle_regex->get_expr();
|
expr* re_expr = cycle_regex->get_expr();
|
||||||
if (!re_expr)
|
auto star_expr = seq.re.mk_star(re_expr);
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
seq_util& seq = m_sg.get_seq_util();
|
|
||||||
expr_ref star_expr(seq.re.mk_star(re_expr), m_sg.get_manager());
|
|
||||||
return m_sg.mk(star_expr);
|
return m_sg.mk(star_expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -894,9 +893,6 @@ namespace seq {
|
||||||
ptr_vector<euf::snode> const* stabs = get_stabilizers(re);
|
ptr_vector<euf::snode> const* stabs = get_stabilizers(re);
|
||||||
if (!stabs || stabs->empty())
|
if (!stabs || stabs->empty())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
seq_util& seq = m_sg.get_seq_util();
|
|
||||||
ast_manager& m = m_sg.get_manager();
|
|
||||||
euf::snode* filtered_union = nullptr;
|
euf::snode* filtered_union = nullptr;
|
||||||
|
|
||||||
for (euf::snode* s : *stabs) {
|
for (euf::snode* s : *stabs) {
|
||||||
|
|
@ -907,11 +903,12 @@ namespace seq {
|
||||||
if (d && d->is_fail()) {
|
if (d && d->is_fail()) {
|
||||||
if (!filtered_union) {
|
if (!filtered_union) {
|
||||||
filtered_union = s;
|
filtered_union = s;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
expr* e1 = filtered_union->get_expr();
|
expr* e1 = filtered_union->get_expr();
|
||||||
expr* e2 = s->get_expr();
|
expr* e2 = s->get_expr();
|
||||||
if (e1 && e2) {
|
if (e1 && e2) {
|
||||||
expr_ref u(seq.re.mk_union(e1, e2), m);
|
auto u = seq.re.mk_union(e1, e2);
|
||||||
filtered_union = m_sg.mk(u);
|
filtered_union = m_sg.mk(u);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -924,8 +921,7 @@ namespace seq {
|
||||||
expr* fe = filtered_union->get_expr();
|
expr* fe = filtered_union->get_expr();
|
||||||
if (!fe)
|
if (!fe)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
expr_ref star_expr(seq.re.mk_star(fe), m);
|
return m_sg.mk(seq.re.mk_star(fe));
|
||||||
return m_sg.mk(star_expr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
// -----------------------------------------------------------------------
|
||||||
|
|
@ -945,9 +941,6 @@ namespace seq {
|
||||||
if (tokens.empty())
|
if (tokens.empty())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
seq_util& seq = m_sg.get_seq_util();
|
|
||||||
ast_manager& m = m_sg.get_manager();
|
|
||||||
|
|
||||||
// Replay tokens on the cycle regex, detecting sub-cycles.
|
// Replay tokens on the cycle regex, detecting sub-cycles.
|
||||||
// A sub-cycle is detected when the derivative returns to cycle_regex.
|
// A sub-cycle is detected when the derivative returns to cycle_regex.
|
||||||
svector<std::pair<unsigned, unsigned>> sub_cycles;
|
svector<std::pair<unsigned, unsigned>> sub_cycles;
|
||||||
|
|
@ -1006,14 +999,11 @@ namespace seq {
|
||||||
if (filtered) {
|
if (filtered) {
|
||||||
expr* fe = filtered->get_expr();
|
expr* fe = filtered->get_expr();
|
||||||
if (fe) {
|
if (fe) {
|
||||||
if (!body) {
|
if (!body)
|
||||||
body = filtered;
|
body = filtered;
|
||||||
} else {
|
else {
|
||||||
expr* be = body->get_expr();
|
expr* be = body->get_expr();
|
||||||
if (be) {
|
body = m_sg.mk(seq.re.mk_concat(be, fe));
|
||||||
expr_ref cat(seq.re.mk_concat(be, fe), m);
|
|
||||||
body = m_sg.mk(cat);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1021,8 +1011,6 @@ namespace seq {
|
||||||
|
|
||||||
// Convert char token to regex: to_re(unit(tok))
|
// Convert char token to regex: to_re(unit(tok))
|
||||||
expr* tok_expr = tok->get_expr();
|
expr* tok_expr = tok->get_expr();
|
||||||
if (!tok_expr)
|
|
||||||
break;
|
|
||||||
|
|
||||||
expr_ref unit_str(seq.str.mk_unit(tok_expr), m);
|
expr_ref unit_str(seq.str.mk_unit(tok_expr), m);
|
||||||
expr_ref tok_re(seq.re.mk_to_re(unit_str), m);
|
expr_ref tok_re(seq.re.mk_to_re(unit_str), m);
|
||||||
|
|
@ -1087,15 +1075,9 @@ namespace seq {
|
||||||
if (!stab_union)
|
if (!stab_union)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
seq_util& seq = m_sg.get_seq_util();
|
|
||||||
ast_manager& mgr = m_sg.get_manager();
|
|
||||||
expr* su_expr = stab_union->get_expr();
|
expr* su_expr = stab_union->get_expr();
|
||||||
if (!su_expr)
|
expr_ref stab_star(seq.re.mk_star(su_expr), m);
|
||||||
return false;
|
|
||||||
expr_ref stab_star(seq.re.mk_star(su_expr), mgr);
|
|
||||||
euf::snode* stab_star_sn = m_sg.mk(stab_star);
|
euf::snode* stab_star_sn = m_sg.mk(stab_star);
|
||||||
if (!stab_star_sn)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// 4. Collect all primitive regex constraints on variable `first`
|
// 4. Collect all primitive regex constraints on variable `first`
|
||||||
euf::snode* x_range = collect_primitive_regex_intersection(first, node, dep);
|
euf::snode* x_range = collect_primitive_regex_intersection(first, node, dep);
|
||||||
|
|
@ -1111,7 +1093,6 @@ namespace seq {
|
||||||
}
|
}
|
||||||
|
|
||||||
char_set seq_regex::minterm_to_char_set(expr* re_expr) {
|
char_set seq_regex::minterm_to_char_set(expr* re_expr) {
|
||||||
seq_util& seq = m_sg.get_seq_util();
|
|
||||||
unsigned max_c = seq.max_char();
|
unsigned max_c = seq.max_char();
|
||||||
|
|
||||||
if (!re_expr)
|
if (!re_expr)
|
||||||
|
|
@ -1190,5 +1171,3 @@ namespace seq {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,8 @@ Author:
|
||||||
namespace seq {
|
namespace seq {
|
||||||
|
|
||||||
class seq_regex {
|
class seq_regex {
|
||||||
|
ast_manager &m;
|
||||||
|
seq_util &seq;
|
||||||
euf::sgraph& m_sg;
|
euf::sgraph& m_sg;
|
||||||
|
|
||||||
// -----------------------------------------------------------------
|
// -----------------------------------------------------------------
|
||||||
|
|
@ -91,7 +93,7 @@ namespace seq {
|
||||||
// -----------------------------------------------------------------------
|
// -----------------------------------------------------------------------
|
||||||
char_set minterm_to_char_set(expr* minterm_re);
|
char_set minterm_to_char_set(expr* minterm_re);
|
||||||
|
|
||||||
seq_regex(euf::sgraph& sg) : m_sg(sg) {}
|
seq_regex(euf::sgraph& sg) : m(sg.get_manager()), seq(sg.get_seq_util()), m_sg(sg) {}
|
||||||
|
|
||||||
euf::sgraph& sg() { return m_sg; }
|
euf::sgraph& sg() { return m_sg; }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,6 @@ namespace smt {
|
||||||
|
|
||||||
std::function<sat::literal(expr*)> literal_if_false = [&](expr* e) {
|
std::function<sat::literal(expr*)> literal_if_false = [&](expr* e) {
|
||||||
bool is_not = m.is_not(e, e);
|
bool is_not = m.is_not(e, e);
|
||||||
TRACE(seq, tout << "literal_if_false: " << mk_pp(e, m) << " internalized - " << ctx.b_internalized(e) << "\n");
|
|
||||||
if (!ctx.b_internalized(e))
|
if (!ctx.b_internalized(e))
|
||||||
// it can happen that the element is not internalized, but as soon as we do it, it becomes false.
|
// it can happen that the element is not internalized, but as soon as we do it, it becomes false.
|
||||||
// In case we just skip one of those uninternalized expressions,
|
// In case we just skip one of those uninternalized expressions,
|
||||||
|
|
@ -93,14 +92,15 @@ namespace smt {
|
||||||
// Alternatively, we could just retry Nielsen saturation in case
|
// Alternatively, we could just retry Nielsen saturation in case
|
||||||
// adding the Nielsen assumption yields the assumption being false after internalizing
|
// adding the Nielsen assumption yields the assumption being false after internalizing
|
||||||
ctx.internalize(to_app(e), false);
|
ctx.internalize(to_app(e), false);
|
||||||
|
|
||||||
literal lit = ctx.get_literal(e);
|
literal lit = ctx.get_literal(e);
|
||||||
if (is_not)
|
if (is_not)
|
||||||
lit.neg();
|
lit.neg();
|
||||||
if (ctx.get_assignment(lit) == l_false) {
|
if (ctx.get_assignment(lit) == l_false) {
|
||||||
TRACE(seq, tout << "literal_if_false: " << lit << " " << mk_pp(e, m) << " is assigned false\n");
|
// TRACE(seq, tout << "literal_if_false: " << lit << " " << mk_pp(e, m) << " is assigned false\n");
|
||||||
return lit;
|
return lit;
|
||||||
}
|
}
|
||||||
TRACE(seq, tout << "literal_if_false: " << mk_pp(e, m) << " is assigned " << ctx.get_assignment(lit) << "\n");
|
// TRACE(seq, tout << "literal_if_false: " << mk_pp(e, m) << " is assigned " << ctx.get_assignment(lit) << "\n");
|
||||||
return sat::null_literal;
|
return sat::null_literal;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue