3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-10-31 19:52:29 +00:00

updated with immediate axioms

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2025-10-16 09:20:46 +02:00
parent d0a7b19806
commit b53e87dcba
4 changed files with 105 additions and 34 deletions

View file

@ -140,6 +140,15 @@ void finite_set_axioms::in_singleton_axiom(expr *x, expr *a) {
return; return;
expr_ref x_in_a(u.mk_in(x, a), m); expr_ref x_in_a(u.mk_in(x, a), m);
if (x == b) {
// If x and b are syntactically identical, then (x in a) is always true
expr_ref_vector clause(m);
clause.push_back(x_in_a);
m_add_clause(clause);
return;
}
expr_ref x_eq_b(m.mk_eq(x, b), m); expr_ref x_eq_b(m.mk_eq(x, b), m);
// (x in a) => (x == b) // (x in a) => (x == b)
@ -271,3 +280,22 @@ void finite_set_axioms::size_singleton_axiom(expr *a) {
clause.push_back(eq); clause.push_back(eq);
m_add_clause(clause); m_add_clause(clause);
} }
void finite_set_axioms::subset_axiom(expr* a) {
expr *b = nullptr, *c = nullptr;
if (!u.is_subset(a, b, c))
return;
expr_ref intersect_bc(u.mk_intersect(b, c), m);
expr_ref eq(m.mk_eq(intersect_bc, b), m);
expr_ref_vector clause1(m);
clause1.push_back(m.mk_not(a));
clause1.push_back(eq);
m_add_clause(clause1);
expr_ref_vector clause2(m);
clause2.push_back(a);
clause2.push_back(m.mk_not(eq));
m_add_clause(clause2);
}

View file

@ -61,6 +61,10 @@ public:
// (x in a) <=> (x in b) and p(x) // (x in a) <=> (x in b) and p(x)
void in_select_axiom(expr *x, expr *a); void in_select_axiom(expr *x, expr *a);
// a := set.subset(b, c)
// (a) <=> (set.intersect(b, c) = b)
void subset_axiom(expr *a);
// a := set.singleton(b) // a := set.singleton(b)
// set.size(a) = 1 // set.size(a) = 1
void size_singleton_axiom(expr *a); void size_singleton_axiom(expr *a);

View file

@ -53,11 +53,7 @@ namespace smt {
* The second effect is to set up tracking and assert axioms. * The second effect is to set up tracking and assert axioms.
* Tracking: * Tracking:
* For every occurrence (set.in x_i S_i) we track x_i. * For every occurrence (set.in x_i S_i) we track x_i.
* Axioms: * Axioms that can be added immediately.
* We can immediately assert some axioms because they are unit literals:
* - (set.in x set.empty) is false
* - (set.subset S T) <=> (= (set.union S T) T) (or (= (set.intersect S T) S))
* Axioms can be deffered to when the atomic formulas become "relevant" for the theory solver.
* *
*/ */
bool theory_finite_set::internalize_atom(app * atom, bool gate_ctx) { bool theory_finite_set::internalize_atom(app * atom, bool gate_ctx) {
@ -76,7 +72,8 @@ namespace smt {
} }
// Assert immediate axioms // Assert immediate axioms
// add_immediate_axioms(atom); // if (!ctx.relevancy())
add_immediate_axioms(atom);
return true; return true;
} }
@ -135,51 +132,96 @@ namespace smt {
* It is responsible for asserting any remaining axioms and checking for inconsistencies. * It is responsible for asserting any remaining axioms and checking for inconsistencies.
* *
* It ensures saturation with respect to the theory axioms: * It ensures saturation with respect to the theory axioms:
* - Set membership is saturated with respect to set operations. * - membership axioms
* For every (set.in x S) where S is a union, assert (or propagate) (set.in x S1) or (set.in x S2) * - extensionality axioms
* - It saturates with respect to extensionality:
* Sets corresponding to shared variables having the same interpretation should also be congruent
*/ */
final_check_status theory_finite_set::final_check_eh() { final_check_status theory_finite_set::final_check_eh() {
TRACE(finite_set, tout << "final_check_eh\n";); TRACE(finite_set, tout << "final_check_eh\n";);
if (add_membership_axioms())
return FC_CONTINUE;
if (add_extensionality_axioms())
return FC_CONTINUE;
return FC_DONE;
}
/**
* Add immediate axioms that can be asserted when the atom is created.
* These are unit clauses that can be added immediately.
* - (set.in x set.empty) is false
* - (set.subset S T) <=> (= (set.union S T) T) (or (= (set.intersect S T) S))
*
* Other axioms:
* - (set.singleton x) -> (set.in x (set.singleton x))
* - (set.singleton x) -> (set.size (set.singleton x)) = 1
* - (set.empty) -> (set.size (set.empty)) = 0
*/
void theory_finite_set::add_immediate_axioms(app* term) {
expr *elem = nullptr, *set = nullptr;
unsigned sz = m_lemmas.size();
if (u.is_in(term, elem, set) && u.is_empty(set))
add_membership_axioms(elem, set);
else if (u.is_subset(term))
m_axioms.subset_axiom(term);
else if (u.is_singleton(term, elem))
m_axioms.in_singleton_axiom(elem, term);
// Assert all new lemmas as clauses
for (unsigned i = sz; i < m_lemmas.size(); ++i)
assert_clause(m_lemmas[i]);
}
/**
* Set membership is saturated with respect to set operations.
* For every (set.in x S) where S is a union, assert (or propagate) (set.in x S1) or (set.in x S2)
*/
bool theory_finite_set::add_membership_axioms() {
expr *elem1 = nullptr, *set1 = nullptr;
// walk all parents of elem in congruence table. // walk all parents of elem in congruence table.
// if a parent is of the form elem' in S u T, or similar. // if a parent is of the form elem' in S u T, or similar.
// create clauses for elem in S u T. // create clauses for elem in S u T.
// Saturate membership constraints
expr* elem1 = nullptr, *set1 = nullptr;
for (auto elem : m_elements) { for (auto elem : m_elements) {
if (!ctx.is_relevant(elem)) if (!ctx.is_relevant(elem))
continue; continue;
for (auto p : enode::parents(elem)) { for (auto p : enode::parents(elem)) {
if (!u.is_in(p->get_expr(), elem1, set1)) if (!u.is_in(p->get_expr(), elem1, set1))
continue; continue;
if (elem->get_root() != p->get_arg(0)->get_root()) if (elem->get_root() != p->get_arg(0)->get_root())
continue; // elem is then equal to set1 but not elem1. This is a different case. continue; // elem is then equal to set1 but not elem1. This is a different case.
if (!ctx.is_relevant(p)) if (!ctx.is_relevant(p))
continue; continue;
for (auto sib : *p->get_arg(1)) for (auto sib : *p->get_arg(1))
instantiate_axioms(elem->get_expr(), sib->get_expr()); add_membership_axioms(elem->get_expr(), sib->get_expr());
} }
} }
if (instantiate_false_lemma()) if (instantiate_false_lemma())
return FC_CONTINUE; return true;
if (instantiate_unit_propagation()) if (instantiate_unit_propagation())
return FC_CONTINUE; return true;
if (instantiate_free_lemma()) if (instantiate_free_lemma())
return FC_CONTINUE; return true;
return false;
// TODO: Extensionality axioms for sets }
return FC_DONE;
/**
* Saturate with respect to extensionality:
* - Sets corresponding to shared variables having the same interpretation should also be congruent
*/
bool theory_finite_set::add_extensionality_axioms() {
return false;
} }
/** /**
* Instantiate axioms for a given element in a set. * Instantiate axioms for a given element in a set.
*/ */
void theory_finite_set::instantiate_axioms(expr* elem, expr* set) { void theory_finite_set::add_membership_axioms(expr *elem, expr *set) {
TRACE(finite_set, tout << "instantiate_axioms: " << mk_pp(elem, m) << " in " << mk_pp(set, m) << "\n";); TRACE(finite_set, tout << "add_membership_axioms: " << mk_pp(elem, m) << " in " << mk_pp(set, m) << "\n";);
struct insert_obj_pair_table : public trail { struct insert_obj_pair_table : public trail {
obj_pair_hashtable<expr, expr> &table; obj_pair_hashtable<expr, expr> &table;
expr *a, *b; expr *a, *b;
@ -218,13 +260,7 @@ namespace smt {
} }
else if (u.is_select(set)) { else if (u.is_select(set)) {
m_axioms.in_select_axiom(elem, set); m_axioms.in_select_axiom(elem, set);
} }
// Instantiate size axioms for singleton sets
// TODO, such axioms don't belong here
if (u.is_singleton(set)) {
m_axioms.size_singleton_axiom(set);
}
} }
void theory_finite_set::add_clause(expr_ref_vector const& clause) { void theory_finite_set::add_clause(expr_ref_vector const& clause) {
@ -281,7 +317,7 @@ namespace smt {
* A theory axiom is also removed during backtracking. * A theory axiom is also removed during backtracking.
*/ */
bool theory_finite_set::instantiate_unit_propagation() { bool theory_finite_set::instantiate_unit_propagation() {
bool propagaed = false; bool propagated = false;
for (auto const &clause : m_lemmas) { for (auto const &clause : m_lemmas) {
expr *undef = nullptr; expr *undef = nullptr;
bool is_unit_propagating = true; bool is_unit_propagating = true;

View file

@ -115,13 +115,16 @@ namespace smt {
model_value_proc * mk_value(enode * n, model_generator & mg) override; model_value_proc * mk_value(enode * n, model_generator & mg) override;
// Helper methods for axiom instantiation // Helper methods for axiom instantiation
void instantiate_axioms(expr* elem, expr* set); void add_membership_axioms(expr* elem, expr* set);
void add_clause(expr_ref_vector const& clause); void add_clause(expr_ref_vector const& clause);
void assert_clause(expr_ref_vector const &clause); void assert_clause(expr_ref_vector const &clause);
bool instantiate_false_lemma(); bool instantiate_false_lemma();
bool instantiate_unit_propagation(); bool instantiate_unit_propagation();
bool instantiate_free_lemma(); bool instantiate_free_lemma();
lbool truth_value(expr *e); lbool truth_value(expr *e);
void add_immediate_axioms(app *atom);
bool add_membership_axioms();
bool add_extensionality_axioms();
public: public:
theory_finite_set(context& ctx); theory_finite_set(context& ctx);