mirror of
https://github.com/Z3Prover/z3
synced 2026-06-01 14:47:51 +00:00
Regex factorization missed some justifications
This commit is contained in:
parent
2db99473a3
commit
0c4e4ad702
1 changed files with 45 additions and 26 deletions
|
|
@ -2901,6 +2901,12 @@ namespace seq {
|
||||||
if (!m_regex_factorization)
|
if (!m_regex_factorization)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
struct rf_split {
|
||||||
|
euf::snode* m_p;
|
||||||
|
euf::snode* m_q;
|
||||||
|
dep_tracker m_dep;
|
||||||
|
};
|
||||||
|
|
||||||
for (str_mem const& mem : node->str_mems()) {
|
for (str_mem const& mem : node->str_mems()) {
|
||||||
SASSERT(mem.m_str && mem.m_regex);
|
SASSERT(mem.m_str && mem.m_regex);
|
||||||
|
|
||||||
|
|
@ -2909,49 +2915,62 @@ namespace seq {
|
||||||
|
|
||||||
euf::snode* first = mem.m_str->first();
|
euf::snode* first = mem.m_str->first();
|
||||||
SASSERT(first);
|
SASSERT(first);
|
||||||
|
SASSERT(!first->is_char());
|
||||||
euf::snode* tail = m_sg.drop_first(mem.m_str);
|
euf::snode* tail = m_sg.drop_first(mem.m_str);
|
||||||
SASSERT(tail);
|
SASSERT(tail);
|
||||||
|
|
||||||
tau_pairs pairs;
|
tau_pairs pairs;
|
||||||
compute_tau(m, m_seq, m_sg, mem.m_regex->get_expr(), pairs);
|
compute_tau(m, m_seq, m_sg, mem.m_regex->get_expr(), pairs);
|
||||||
|
|
||||||
|
vector<rf_split> feasible;
|
||||||
|
dep_tracker eliminated_dep = mem.m_dep;
|
||||||
|
|
||||||
for (auto const& pair : pairs) {
|
for (auto const& pair : pairs) {
|
||||||
euf::snode* sn_p = m_sg.mk(pair.m_p);
|
euf::snode* sn_p = m_sg.mk(pair.m_p);
|
||||||
euf::snode* sn_q = m_sg.mk(pair.m_q);
|
euf::snode* sn_q = m_sg.mk(pair.m_q);
|
||||||
|
|
||||||
// Eagerly eliminate contradictory cases
|
|
||||||
// e.g. check intersection emptiness with max_states = 100
|
|
||||||
if (m_seq_regex->is_empty_bfs(sn_p, 100) == l_true)
|
|
||||||
continue;
|
|
||||||
if (m_seq_regex->is_empty_bfs(sn_q, 100) == l_true)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Also check intersection with other primitive constraints on `first`
|
// Also check intersection with other primitive constraints on `first`
|
||||||
ptr_vector<euf::snode> regexes_p;
|
ptr_vector<euf::snode> regexes_p;
|
||||||
regexes_p.push_back(sn_p);
|
regexes_p.push_back(sn_p);
|
||||||
|
dep_tracker first_filter_dep = nullptr;
|
||||||
for (auto const& prev_mem : node->str_mems()) {
|
for (auto const& prev_mem : node->str_mems()) {
|
||||||
if (prev_mem.m_str == first)
|
if (prev_mem.m_str == first) {
|
||||||
regexes_p.push_back(prev_mem.m_regex);
|
regexes_p.push_back(prev_mem.m_regex);
|
||||||
}
|
first_filter_dep = m_dep_mgr.mk_join(first_filter_dep, prev_mem.m_dep);
|
||||||
if (regexes_p.size() > 1 && m_seq_regex->check_intersection_emptiness(regexes_p, 100) == l_true)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
nielsen_node* child = mk_child(node);
|
|
||||||
mk_edge(node, child, true);
|
|
||||||
|
|
||||||
// remove the original mem from child
|
|
||||||
auto& child_mems = child->str_mems();
|
|
||||||
for (unsigned k = 0; k < child_mems.size(); ++k) {
|
|
||||||
if (child_mems[k] == mem) {
|
|
||||||
child_mems[k] = child_mems.back();
|
|
||||||
child_mems.pop_back();
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (regexes_p.size() > 1 && m_seq_regex->check_intersection_emptiness(regexes_p, 100) == l_true) {
|
||||||
child->add_str_mem(str_mem(first, sn_p, mem.m_dep));
|
eliminated_dep = m_dep_mgr.mk_join(eliminated_dep, first_filter_dep);
|
||||||
child->add_str_mem(str_mem(tail, sn_q, mem.m_dep));
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
feasible.push_back({ sn_p, sn_q, m_dep_mgr.mk_join(mem.m_dep, first_filter_dep) });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (feasible.empty()) {
|
||||||
|
node->set_general_conflict();
|
||||||
|
node->set_conflict(backtrack_reason::regex, eliminated_dep);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (feasible.size() > 1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
nielsen_node* child = mk_child(node);
|
||||||
|
mk_edge(node, child, true);
|
||||||
|
|
||||||
|
// remove the original mem from child
|
||||||
|
auto& child_mems = child->str_mems();
|
||||||
|
for (unsigned k = 0; k < child_mems.size(); ++k) {
|
||||||
|
if (child_mems[k] == mem) {
|
||||||
|
child_mems[k] = child_mems.back();
|
||||||
|
child_mems.pop_back();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
child->add_str_mem(str_mem(first, feasible[0].m_p, feasible[0].m_dep));
|
||||||
|
child->add_str_mem(str_mem(tail, feasible[0].m_q, feasible[0].m_dep));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue