mirror of
https://github.com/Z3Prover/z3
synced 2026-06-29 20:08:52 +00:00
reuse char extraction from seq_util
This commit is contained in:
parent
f02391a01f
commit
fc4d15e4f8
2 changed files with 7 additions and 64 deletions
|
|
@ -544,68 +544,8 @@ namespace seq {
|
||||||
// char_le(lo_expr, ele) → range [lo, max_char]
|
// char_le(lo_expr, ele) → range [lo, max_char]
|
||||||
// char_le(ele, hi_expr) → range [0, hi]
|
// char_le(ele, hi_expr) → range [0, hi]
|
||||||
// Returns false if not a recognizable range condition.
|
// Returns false if not a recognizable range condition.
|
||||||
bool derive::extract_char_range(expr* cond, unsigned& lo, unsigned& hi) {
|
|
||||||
expr* e1 = nullptr, *e2 = nullptr, *lhs = nullptr, *rhs = nullptr;
|
|
||||||
lo = 0;
|
|
||||||
hi = u().max_char();
|
|
||||||
|
|
||||||
// Negation: not handled here — handled via pred_implies logic
|
|
||||||
if (m.is_not(cond, e1))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Equality: ele == c → range [c, c]
|
|
||||||
if (m.is_eq(cond, e1, e2)) {
|
|
||||||
unsigned v;
|
|
||||||
if (u().is_const_char(e1, v) && e2 == m_ele) {
|
|
||||||
lo = hi = v;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (u().is_const_char(e2, v) && e1 == m_ele) {
|
|
||||||
lo = hi = v;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Conjunction: and(char_le(lo, x), char_le(x, hi))
|
|
||||||
if (m.is_and(cond, e1, e2)) {
|
|
||||||
expr *a1, *a2, *b1, *b2;
|
|
||||||
unsigned v;
|
|
||||||
if (u().is_char_le(e1, a1, a2)) {
|
|
||||||
if (u().is_const_char(a1, v) && a2 == m_ele)
|
|
||||||
lo = std::max(lo, v); // v <= ele
|
|
||||||
else if (a1 == m_ele && u().is_const_char(a2, v))
|
|
||||||
hi = std::min(hi, v); // ele <= v
|
|
||||||
}
|
|
||||||
if (u().is_char_le(e2, b1, b2)) {
|
|
||||||
unsigned v2;
|
|
||||||
if (u().is_const_char(b1, v2) && b2 == m_ele)
|
|
||||||
lo = std::max(lo, v2); // v2 <= ele
|
|
||||||
else if (b1 == m_ele && u().is_const_char(b2, v2))
|
|
||||||
hi = std::min(hi, v2); // ele <= v2
|
|
||||||
}
|
|
||||||
return lo <= hi;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Single char_le
|
|
||||||
if (u().is_char_le(cond, lhs, rhs)) {
|
|
||||||
unsigned v;
|
|
||||||
if (u().is_const_char(lhs, v) && rhs == m_ele) {
|
|
||||||
lo = v; // v <= ele
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (lhs == m_ele && u().is_const_char(rhs, v)) {
|
|
||||||
hi = v; // ele <= v
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Predicate implication for character range conditions.
|
// Predicate implication for character range conditions.
|
||||||
// Returns true if: whenever cond_a is true, cond_b must also be true.
|
// Returns true if: whenever cond_a is true, cond_b must also be true.
|
||||||
// Used for BDD-merge of derivative ITE trees.
|
|
||||||
// pred_implies(sign_a, a, sign_b, b): does (sign_a ? ¬a : a) imply (sign_b ? ¬b : b)?
|
// pred_implies(sign_a, a, sign_b, b): does (sign_a ? ¬a : a) imply (sign_b ? ¬b : b)?
|
||||||
bool derive::pred_implies(bool sign_a, expr* a, bool sign_b, expr* b) {
|
bool derive::pred_implies(bool sign_a, expr* a, bool sign_b, expr* b) {
|
||||||
// Same atom: check sign compatibility
|
// Same atom: check sign compatibility
|
||||||
|
|
@ -616,20 +556,24 @@ namespace seq {
|
||||||
return pred_implies(false, b, false, a);
|
return pred_implies(false, b, false, a);
|
||||||
|
|
||||||
unsigned lo_a, hi_a, lo_b, hi_b;
|
unsigned lo_a, hi_a, lo_b, hi_b;
|
||||||
|
bool neg_a, neg_b;
|
||||||
|
|
||||||
if (!sign_a && !sign_b) {
|
if (!sign_a && !sign_b) {
|
||||||
// a → b: range_a ⊆ range_b
|
// a → b: range_a ⊆ range_b
|
||||||
if (extract_char_range(a, lo_a, hi_a) && extract_char_range(b, lo_b, hi_b))
|
if (u().is_char_const_range(m_ele, a, lo_a, hi_a, neg_a) && !neg_a &&
|
||||||
|
u().is_char_const_range(m_ele, b, lo_b, hi_b, neg_b) && !neg_b)
|
||||||
return lo_b <= lo_a && hi_a <= hi_b;
|
return lo_b <= lo_a && hi_a <= hi_b;
|
||||||
}
|
}
|
||||||
else if (!sign_a && sign_b) {
|
else if (!sign_a && sign_b) {
|
||||||
// a → ¬b: range_a ∩ range_b = ∅
|
// a → ¬b: range_a ∩ range_b = ∅
|
||||||
if (extract_char_range(a, lo_a, hi_a) && extract_char_range(b, lo_b, hi_b))
|
if (u().is_char_const_range(m_ele, a, lo_a, hi_a, neg_a) && !neg_a &&
|
||||||
|
u().is_char_const_range(m_ele, b, lo_b, hi_b, neg_b) && !neg_b)
|
||||||
return hi_a < lo_b || hi_b < lo_a;
|
return hi_a < lo_b || hi_b < lo_a;
|
||||||
}
|
}
|
||||||
else if (sign_a && !sign_b) {
|
else if (sign_a && !sign_b) {
|
||||||
// ¬a → b: complement of range_a ⊆ range_b
|
// ¬a → b: complement of range_a ⊆ range_b
|
||||||
if (extract_char_range(a, lo_a, hi_a) && extract_char_range(b, lo_b, hi_b))
|
if (u().is_char_const_range(m_ele, a, lo_a, hi_a, neg_a) && !neg_a &&
|
||||||
|
u().is_char_const_range(m_ele, b, lo_b, hi_b, neg_b) && !neg_b)
|
||||||
return lo_b == 0 && hi_b >= u().max_char();
|
return lo_b == 0 && hi_b >= u().max_char();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -150,7 +150,6 @@ namespace seq {
|
||||||
// Predicate implication for character range conditions.
|
// Predicate implication for character range conditions.
|
||||||
bool pred_implies(bool sign_a, expr* a, bool sign_b, expr* b);
|
bool pred_implies(bool sign_a, expr* a, bool sign_b, expr* b);
|
||||||
bool pred_implies(expr* a, expr* b);
|
bool pred_implies(expr* a, expr* b);
|
||||||
bool extract_char_range(expr* cond, unsigned& lo, unsigned& hi);
|
|
||||||
|
|
||||||
// Normalize reverse(r) by pushing reverse inward
|
// Normalize reverse(r) by pushing reverse inward
|
||||||
expr_ref normalize_reverse(expr* r);
|
expr_ref normalize_reverse(expr* r);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue