mirror of
https://github.com/Z3Prover/z3
synced 2026-06-24 09:30:31 +00:00
Refactor: replace int_constraint with constraint struct, promote cur_path to member, expose path leaf side constraints (#9124)
* chore: update plan with cur_path and side constraints requirements Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com> Agent-Logs-Url: https://github.com/Z3Prover/z3/sessions/1523cf0a-b7a4-41a6-b792-7cd41b4dcd3b * Refactor: rename int_constraint to constraint, remove int_constraint_kind enum - Rename int_constraint struct to constraint with fields fml/dep - Remove int_constraint_kind enum; pre-build formula expressions instead - nielsen_edge: add_side_int/side_int() -> add_side_constraint/side_constraints() - nielsen_node: add_int_constraint/int_constraints() -> add_constraint/constraints() - nielsen_graph: mk_int_constraint(lhs,rhs,kind,dep) -> mk_constraint(fml,dep) - Remove int_constraint_to_expr (no longer needed) - search_dfs/simplify_and_init/check_int_feasibility/check_lp_le: drop cur_path param - Add m_cur_path member to nielsen_graph; m_cur_path.reset() in solve() - Add get_path_leaf_side_constraints() implementation - Update seq_parikh.h/cpp and seq_nielsen_pp.cpp to use new constraint API Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * refactor: constraint struct, promote cur_path, expose path leaf side constraints Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com> Agent-Logs-Url: https://github.com/Z3Prover/z3/sessions/1523cf0a-b7a4-41a6-b792-7cd41b4dcd3b * fix: remove spurious includes from seq_nielsen.cpp Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com> Agent-Logs-Url: https://github.com/Z3Prover/z3/sessions/aa283d79-cd42-4b87-aaf0-4273a8327b76 * fix: update test files to use renamed constraint API and fix inverted root guard Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com> Agent-Logs-Url: https://github.com/Z3Prover/z3/sessions/b09bbc56-9617-4277-8e0c-27fa7e588037 --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
9f6eb4f455
commit
e3e235aa7f
7 changed files with 183 additions and 231 deletions
|
|
@ -3300,26 +3300,26 @@ static void test_add_lower_int_bound_basic() {
|
|||
// initially no bounds
|
||||
SASSERT(node->var_lb(x) == 0);
|
||||
SASSERT(node->var_ub(x) == UINT_MAX);
|
||||
SASSERT(node->int_constraints().empty());
|
||||
SASSERT(node->constraints().empty());
|
||||
|
||||
// add lower bound lb=3: should tighten and add constraint
|
||||
bool tightened = node->add_lower_int_bound(x, 3, dep);
|
||||
SASSERT(tightened);
|
||||
SASSERT(node->var_lb(x) == 3);
|
||||
SASSERT(node->int_constraints().size() == 1);
|
||||
SASSERT(node->int_constraints()[0].m_kind == seq::int_constraint_kind::ge);
|
||||
SASSERT(node->constraints().size() == 1);
|
||||
SASSERT(node->constraints()[0].fml);
|
||||
|
||||
// add weaker lb=2: no tightening
|
||||
tightened = node->add_lower_int_bound(x, 2, dep);
|
||||
SASSERT(!tightened);
|
||||
SASSERT(node->var_lb(x) == 3);
|
||||
SASSERT(node->int_constraints().size() == 1);
|
||||
SASSERT(node->constraints().size() == 1);
|
||||
|
||||
// add tighter lb=5: should tighten and add another constraint
|
||||
tightened = node->add_lower_int_bound(x, 5, dep);
|
||||
SASSERT(tightened);
|
||||
SASSERT(node->var_lb(x) == 5);
|
||||
SASSERT(node->int_constraints().size() == 2);
|
||||
SASSERT(node->constraints().size() == 2);
|
||||
|
||||
std::cout << " ok\n";
|
||||
}
|
||||
|
|
@ -3347,20 +3347,20 @@ static void test_add_upper_int_bound_basic() {
|
|||
bool tightened = node->add_upper_int_bound(x, 10, dep);
|
||||
SASSERT(tightened);
|
||||
SASSERT(node->var_ub(x) == 10);
|
||||
SASSERT(node->int_constraints().size() == 1);
|
||||
SASSERT(node->int_constraints()[0].m_kind == seq::int_constraint_kind::le);
|
||||
SASSERT(node->constraints().size() == 1);
|
||||
SASSERT(node->constraints()[0].fml);
|
||||
|
||||
// add weaker ub=20: no tightening
|
||||
tightened = node->add_upper_int_bound(x, 20, dep);
|
||||
SASSERT(!tightened);
|
||||
SASSERT(node->var_ub(x) == 10);
|
||||
SASSERT(node->int_constraints().size() == 1);
|
||||
SASSERT(node->constraints().size() == 1);
|
||||
|
||||
// add tighter ub=5: tightens
|
||||
tightened = node->add_upper_int_bound(x, 5, dep);
|
||||
SASSERT(tightened);
|
||||
SASSERT(node->var_ub(x) == 5);
|
||||
SASSERT(node->int_constraints().size() == 2);
|
||||
SASSERT(node->constraints().size() == 2);
|
||||
|
||||
std::cout << " ok\n";
|
||||
}
|
||||
|
|
@ -3427,7 +3427,7 @@ static void test_bounds_cloned() {
|
|||
SASSERT(child->var_ub(y) == UINT_MAX);
|
||||
|
||||
// child's int_constraints should also be cloned (3 constraints: lb_x, ub_x, lb_y)
|
||||
SASSERT(child->int_constraints().size() == parent->int_constraints().size());
|
||||
SASSERT(child->constraints().size() == parent->constraints().size());
|
||||
|
||||
std::cout << " ok\n";
|
||||
}
|
||||
|
|
@ -3454,7 +3454,7 @@ static void test_var_bound_watcher_single_var() {
|
|||
// set bounds: 3 <= len(x) <= 7
|
||||
node->add_lower_int_bound(x, 3, dep);
|
||||
node->add_upper_int_bound(x, 7, dep);
|
||||
node->int_constraints().reset(); // clear for clean count
|
||||
node->constraints().reset(); // clear for clean count
|
||||
|
||||
// apply substitution x → a·y
|
||||
euf::snode* ay = sg.mk_concat(a, y);
|
||||
|
|
@ -3490,7 +3490,7 @@ static void test_var_bound_watcher_conflict() {
|
|||
|
||||
// set bounds: 3 <= len(x) (so x must have at least 3 chars)
|
||||
node->add_lower_int_bound(x, 3, dep);
|
||||
node->int_constraints().reset();
|
||||
node->constraints().reset();
|
||||
|
||||
// apply substitution x → a·b (const_len=2 < lb=3)
|
||||
euf::snode* ab = sg.mk_concat(a, b);
|
||||
|
|
@ -3624,7 +3624,7 @@ static void test_var_bound_watcher_multi_var() {
|
|||
|
||||
// set upper bound: len(x) <= 5
|
||||
node->add_upper_int_bound(x, 5, dep);
|
||||
node->int_constraints().reset();
|
||||
node->constraints().reset();
|
||||
|
||||
// apply substitution x → y·z (two vars, no constants)
|
||||
euf::snode* yz = sg.mk_concat(y, z);
|
||||
|
|
|
|||
|
|
@ -326,7 +326,7 @@ static void test_generate_constraints_ab_star() {
|
|||
seq::dep_tracker dep = dm.mk_leaf(lit);
|
||||
seq::str_mem mem(x, regex, nullptr, 0, dep);
|
||||
|
||||
vector<seq::int_constraint> out;
|
||||
vector<seq::constraint> out;
|
||||
parikh.generate_parikh_constraints(mem, out);
|
||||
|
||||
// expect at least: len(x)=0+2k and k>=0
|
||||
|
|
@ -337,19 +337,19 @@ static void test_generate_constraints_ab_star() {
|
|||
// check that one constraint is an equality (len(x) = 0 + 2·k)
|
||||
bool has_eq = false;
|
||||
for (auto const& ic : out)
|
||||
if (ic.m_kind == seq::int_constraint_kind::eq) has_eq = true;
|
||||
if (m.is_eq(ic.fml)) has_eq = true;
|
||||
SASSERT(has_eq);
|
||||
|
||||
// check that one constraint is k >= 0
|
||||
bool has_ge = false;
|
||||
for (auto const& ic : out)
|
||||
if (ic.m_kind == seq::int_constraint_kind::ge) has_ge = true;
|
||||
if (arith.is_ge(ic.fml)) has_ge = true;
|
||||
SASSERT(has_ge);
|
||||
|
||||
// should NOT have an upper bound (star is unbounded)
|
||||
bool has_le = false;
|
||||
for (auto const& ic : out)
|
||||
if (ic.m_kind == seq::int_constraint_kind::le) has_le = true;
|
||||
if (arith.is_le(ic.fml)) has_le = true;
|
||||
SASSERT(!has_le);
|
||||
}
|
||||
|
||||
|
|
@ -361,6 +361,7 @@ static void test_generate_constraints_bounded_loop() {
|
|||
euf::egraph eg(m);
|
||||
euf::sgraph sg(m, eg);
|
||||
seq_util seq(m);
|
||||
arith_util arith(m);
|
||||
seq::seq_parikh parikh(sg);
|
||||
|
||||
euf::snode* x = sg.mk_var(symbol("x"), sg.get_str_sort());
|
||||
|
|
@ -372,7 +373,7 @@ static void test_generate_constraints_bounded_loop() {
|
|||
seq::dep_tracker dep = dm.mk_leaf(sat::null_literal);
|
||||
seq::str_mem mem(x, regex, nullptr, 0, dep);
|
||||
|
||||
vector<seq::int_constraint> out;
|
||||
vector<seq::constraint> out;
|
||||
parikh.generate_parikh_constraints(mem, out);
|
||||
|
||||
// expect: eq + ge + le = 3 constraints
|
||||
|
|
@ -381,9 +382,9 @@ static void test_generate_constraints_bounded_loop() {
|
|||
|
||||
bool has_eq = false, has_ge = false, has_le = false;
|
||||
for (auto const& ic : out) {
|
||||
if (ic.m_kind == seq::int_constraint_kind::eq) has_eq = true;
|
||||
if (ic.m_kind == seq::int_constraint_kind::ge) has_ge = true;
|
||||
if (ic.m_kind == seq::int_constraint_kind::le) has_le = true;
|
||||
if (m.is_eq(ic.fml)) has_eq = true;
|
||||
if (arith.is_ge(ic.fml)) has_ge = true;
|
||||
if (arith.is_le(ic.fml)) has_le = true;
|
||||
}
|
||||
SASSERT(has_eq);
|
||||
SASSERT(has_ge);
|
||||
|
|
@ -409,7 +410,7 @@ static void test_generate_constraints_stride_one() {
|
|||
seq::dep_tracker dep = dm.mk_leaf(sat::null_literal);
|
||||
seq::str_mem mem(x, regex, nullptr, 0, dep);
|
||||
|
||||
vector<seq::int_constraint> out;
|
||||
vector<seq::constraint> out;
|
||||
parikh.generate_parikh_constraints(mem, out);
|
||||
std::cout << " generated " << out.size() << " constraints (expect 0)\n";
|
||||
SASSERT(out.empty());
|
||||
|
|
@ -432,7 +433,7 @@ static void test_generate_constraints_fixed_length() {
|
|||
seq::dep_tracker dep = dm.mk_leaf(sat::null_literal);
|
||||
seq::str_mem mem(x, regex, nullptr, 0, dep);
|
||||
|
||||
vector<seq::int_constraint> out;
|
||||
vector<seq::constraint> out;
|
||||
parikh.generate_parikh_constraints(mem, out);
|
||||
std::cout << " generated " << out.size() << " constraints (expect 0)\n";
|
||||
SASSERT(out.empty());
|
||||
|
|
@ -456,14 +457,14 @@ static void test_generate_constraints_dep_propagated() {
|
|||
seq::dep_tracker dep = dm.mk_leaf(lit);
|
||||
seq::str_mem mem(x, regex, nullptr, 0, dep);
|
||||
|
||||
vector<seq::int_constraint> out;
|
||||
vector<seq::constraint> out;
|
||||
parikh.generate_parikh_constraints(mem, out);
|
||||
|
||||
// all generated constraints must carry dep_source{mem,7} in their dependency
|
||||
for (auto const& ic : out) {
|
||||
SASSERT(ic.m_dep != nullptr);
|
||||
SASSERT(ic.dep != nullptr);
|
||||
vector<seq::dep_source, false> vs;
|
||||
dm.linearize(ic.m_dep, vs);
|
||||
dm.linearize(ic.dep, vs);
|
||||
bool found = false;
|
||||
for (auto const& d : vs)
|
||||
if (std::get<sat::literal>(d) == lit) found = true;
|
||||
|
|
@ -495,11 +496,11 @@ static void test_apply_to_node_adds_constraints() {
|
|||
|
||||
// root node should have no int_constraints initially
|
||||
SASSERT(ng.root() != nullptr);
|
||||
unsigned before = ng.root()->int_constraints().size();
|
||||
unsigned before = ng.root()->constraints().size();
|
||||
|
||||
parikh.apply_to_node(*ng.root());
|
||||
|
||||
unsigned after = ng.root()->int_constraints().size();
|
||||
unsigned after = ng.root()->constraints().size();
|
||||
std::cout << " before=" << before << " after=" << after << "\n";
|
||||
SASSERT(after > before);
|
||||
}
|
||||
|
|
@ -525,9 +526,9 @@ static void test_apply_to_node_stride_one_no_constraints() {
|
|||
euf::snode* regex = sg.mk(re);
|
||||
ng.add_str_mem(x, regex);
|
||||
|
||||
unsigned before = ng.root()->int_constraints().size();
|
||||
unsigned before = ng.root()->constraints().size();
|
||||
parikh.apply_to_node(*ng.root());
|
||||
unsigned after = ng.root()->int_constraints().size();
|
||||
unsigned after = ng.root()->constraints().size();
|
||||
std::cout << " before=" << before << " after=" << after << " (expect no change)\n";
|
||||
SASSERT(after == before);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue