mirror of
https://github.com/Z3Prover/z3
synced 2026-06-21 16:10:26 +00:00
seq::derive — Stage 2: range_predicate-based path state
Replace seq::derive's m_intervals + m_intervals_start append-only char-range stack and the imperative intersect_intervals / exclude_interval helpers with a single canonical range_predicate m_path_pred that tracks the feasible character set under the current path. * Add range_predicate_translator: pure AST -> range_predicate translator for the boolean-over-char_le fragment (true/false, eq with const, char_le with const, not/and/or any nesting). Returns false on the first sub-term outside the fragment so the caller can fall back to other reasoning. * push_intervals_impl: translate the candidate predicate to a range_predicate and reduce path tracking to set arithmetic (intersection + subset/empty checks). The legacy top-level and/or descent is preserved for mixed char / non-char conditions. * eval_range_cond: implication becomes subset_of and contradiction becomes !intersects, both linear in the number of ranges with no AST allocation. * range_predicate gains subset_of / intersects / disjoint_from to support allocation-free path queries. * path_save now stores the saved range_predicate by value; the stack switches from svector (CallDestructors=false) to vector because range_predicate owns an inner svector. Tests: 91/91 pass with /a, including the new range_predicate_translator unit test exercising true/false, eq, char_le, and/or/not, and De Morgan agreement. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
parent
904090eec0
commit
4bef7d513c
10 changed files with 405 additions and 128 deletions
102
src/ast/rewriter/range_predicate_translator.cpp
Normal file
102
src/ast/rewriter/range_predicate_translator.cpp
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
/*++
|
||||
Copyright (c) 2026 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
range_predicate_translator.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Implementation of seq::range_predicate_translator. See header for the
|
||||
algebraic specification of the translatable fragment.
|
||||
|
||||
Authors:
|
||||
|
||||
Margus Veanes (veanes) 2026
|
||||
|
||||
--*/
|
||||
|
||||
#include "ast/rewriter/range_predicate_translator.h"
|
||||
|
||||
namespace seq {
|
||||
|
||||
bool range_predicate_translator::translate(expr* ele, expr* cond,
|
||||
range_predicate& out) const {
|
||||
unsigned const max_char = m_u.max_char();
|
||||
|
||||
if (m.is_true(cond)) {
|
||||
out = range_predicate::top(max_char);
|
||||
return true;
|
||||
}
|
||||
if (m.is_false(cond)) {
|
||||
out = range_predicate::empty(max_char);
|
||||
return true;
|
||||
}
|
||||
|
||||
expr* a = nullptr;
|
||||
expr* b = nullptr;
|
||||
unsigned c = 0;
|
||||
|
||||
if (m.is_eq(cond, a, b)) {
|
||||
if (a == ele && m_u.is_const_char(b, c)) {
|
||||
out = range_predicate::singleton(c, max_char);
|
||||
return true;
|
||||
}
|
||||
if (b == ele && m_u.is_const_char(a, c)) {
|
||||
out = range_predicate::singleton(c, max_char);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_u.is_char_le(cond, a, b)) {
|
||||
// ele <= c --> [0, c]
|
||||
if (a == ele && m_u.is_const_char(b, c)) {
|
||||
out = range_predicate::range(0, c, max_char);
|
||||
return true;
|
||||
}
|
||||
// c <= ele --> [c, max_char]
|
||||
if (b == ele && m_u.is_const_char(a, c)) {
|
||||
out = range_predicate::range(c, max_char, max_char);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
expr* arg = nullptr;
|
||||
if (m.is_not(cond, arg)) {
|
||||
range_predicate tmp(max_char);
|
||||
if (!translate(ele, arg, tmp))
|
||||
return false;
|
||||
out = ~tmp;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (m.is_and(cond)) {
|
||||
range_predicate acc = range_predicate::top(max_char);
|
||||
for (expr* sub : *to_app(cond)) {
|
||||
range_predicate p(max_char);
|
||||
if (!translate(ele, sub, p))
|
||||
return false;
|
||||
acc = acc & p;
|
||||
}
|
||||
out = acc;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (m.is_or(cond)) {
|
||||
range_predicate acc = range_predicate::empty(max_char);
|
||||
for (expr* sub : *to_app(cond)) {
|
||||
range_predicate p(max_char);
|
||||
if (!translate(ele, sub, p))
|
||||
return false;
|
||||
acc = acc | p;
|
||||
}
|
||||
out = acc;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue