3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2026-04-02 09:58:59 +00:00

hoist functionality

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2026-04-01 09:41:49 -07:00
parent 5f5a0ffbd8
commit 9a29a0fc24
2 changed files with 34 additions and 27 deletions

View file

@ -42,12 +42,10 @@ NSB review:
namespace seq {
void deps_to_lits(dep_tracker const& deps,
svector<enode_pair>& eqs,
svector<sat::literal>& lits) {
void deps_to_lits(dep_tracker const &deps, svector<enode_pair> &eqs, svector<sat::literal> &lits) {
vector<dep_source, false> vs;
dep_manager::s_linearize(deps, vs);
for (dep_source const& d : vs) {
for (dep_source const &d : vs) {
if (std::holds_alternative<enode_pair>(d))
eqs.push_back(std::get<enode_pair>(d));
else
@ -58,7 +56,7 @@ namespace seq {
// Normalize an arithmetic expression using th_rewriter.
// Simplifies e.g. (n - 1 + 1) to n, preventing unbounded growth
// of power exponents during unwind/merge cycles.
static expr_ref normalize_arith(ast_manager& m, expr* e) {
static expr_ref normalize_arith(ast_manager &m, expr *e) {
expr_ref result(e, m);
th_rewriter rw(m);
rw(result);
@ -68,25 +66,30 @@ namespace seq {
// Directional helpers mirroring ZIPT's fwd flag:
// fwd=true -> left-to-right (prefix/head)
// fwd=false -> right-to-left (suffix/tail)
static euf::snode* dir_token(euf::snode* s, bool fwd) {
if (!s) return nullptr;
static euf::snode *dir_token(euf::snode *s, bool fwd) {
if (!s)
return nullptr;
return fwd ? s->first() : s->last();
}
static euf::snode* dir_drop(euf::sgraph& sg, euf::snode* s, unsigned count, bool fwd) {
if (!s || count == 0) return s;
static euf::snode *dir_drop(euf::sgraph &sg, euf::snode *s, unsigned count, bool fwd) {
if (!s || count == 0)
return s;
return fwd ? sg.drop_left(s, count) : sg.drop_right(s, count);
}
static euf::snode* dir_concat(euf::sgraph& sg, euf::snode* a, euf::snode* b, bool fwd) {
if (!a) return b;
if (!b) return a;
static euf::snode *dir_concat(euf::sgraph &sg, euf::snode *a, euf::snode *b, bool fwd) {
if (!a)
return b;
if (!b)
return a;
return fwd ? sg.mk_concat(a, b) : sg.mk_concat(b, a);
}
static void collect_tokens_dir(euf::snode* s, bool fwd, euf::snode_vector& toks) {
static void collect_tokens_dir(euf::snode *s, bool fwd, euf::snode_vector &toks) {
toks.reset();
if (!s) return;
if (!s)
return;
s->collect_tokens(toks);
if (!fwd)
toks.reverse();
@ -94,15 +97,15 @@ namespace seq {
// Right-derivative helper used by backward str_mem simplification:
// dR(re, c) = reverse( derivative(c, reverse(re)) ).
static euf::snode* reverse_brzozowski_deriv(euf::sgraph& sg, euf::snode* re, euf::snode* elem) {
static euf::snode *reverse_brzozowski_deriv(euf::sgraph &sg, euf::snode *re, euf::snode *elem) {
if (!re || !elem || !re->get_expr() || !elem->get_expr())
return nullptr;
ast_manager& m = sg.get_manager();
seq_util& seq = sg.get_seq_util();
ast_manager &m = sg.get_manager();
seq_util &seq = sg.get_seq_util();
seq_rewriter rw(m);
expr* elem_expr = elem->get_expr();
expr* ch = nullptr;
expr *elem_expr = elem->get_expr();
expr *ch = nullptr;
if (seq.str.is_unit(elem_expr, ch))
elem_expr = ch;
@ -127,18 +130,17 @@ namespace seq {
}
bool str_eq::is_trivial() const {
return m_lhs == m_rhs ||
(m_lhs && m_rhs && m_lhs->is_empty() && m_rhs->is_empty());
return m_lhs == m_rhs || (m_lhs && m_rhs && m_lhs->is_empty() && m_rhs->is_empty());
}
bool str_eq::contains_var(euf::snode* var) const {
bool str_eq::contains_var(euf::snode *var) const {
if (!var)
return false;
// check if var appears in the token list of lhs or rhs
if (m_lhs) {
euf::snode_vector tokens;
m_lhs->collect_tokens(tokens);
for (euf::snode* t : tokens) {
for (euf::snode *t : tokens) {
if (t == var)
return true;
}
@ -146,7 +148,7 @@ namespace seq {
if (m_rhs) {
euf::snode_vector tokens;
m_rhs->collect_tokens(tokens);
for (euf::snode* t : tokens) {
for (euf::snode *t : tokens) {
if (t == var)
return true;
}
@ -166,6 +168,10 @@ namespace seq {
return m_str && m_regex && m_str->is_empty() && m_regex->is_nullable();
}
bool str_mem::is_contradiction() const {
return (m_str && m_regex && m_str->is_empty() && !m_regex->is_nullable());
}
bool str_mem::contains_var(euf::snode* var) const {
SASSERT(var);
if (m_str) {
@ -1173,8 +1179,7 @@ namespace seq {
// check for regex memberships that are immediately infeasible
for (str_mem& mem : m_str_mem) {
SASSERT(mem.m_str && mem.m_regex);
if (mem.m_str->is_empty() && !mem.m_regex->is_nullable()) {
if (mem.is_contradiction()) {
m_is_general_conflict = true;
m_reason = backtrack_reason::regex;
return simplify_result::conflict;

View file

@ -405,7 +405,9 @@ namespace seq {
// check if the constraint has the form x in R with x a single variable
bool is_primitive() const;
bool is_trivial() const;
bool is_trivial() const;
bool is_contradiction() const;
// check if the constraint contains a given variable
bool contains_var(euf::snode* var) const;