mirror of
https://github.com/Z3Prover/z3
synced 2025-04-15 13:28:47 +00:00
na
This commit is contained in:
parent
f0d33ddddb
commit
ec8866c91a
|
@ -47,6 +47,8 @@ void value_sweep::reset_values() {
|
||||||
}
|
}
|
||||||
|
|
||||||
expr* value_sweep::get_value(expr* e) const {
|
expr* value_sweep::get_value(expr* e) const {
|
||||||
|
if (m.is_value(e))
|
||||||
|
return e;
|
||||||
if (m_values.size() <= e->get_id())
|
if (m_values.size() <= e->get_id())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
return m_values[e->get_id()];
|
return m_values[e->get_id()];
|
||||||
|
@ -132,9 +134,10 @@ void value_sweep::init(expr_ref_vector const& terms) {
|
||||||
for (expr* t : subterms(terms)) {
|
for (expr* t : subterms(terms)) {
|
||||||
if (!is_app(t))
|
if (!is_app(t))
|
||||||
continue;
|
continue;
|
||||||
for (expr* arg : *to_app(t))
|
for (expr* arg : *to_app(t)) {
|
||||||
m_parents[arg->get_id()].push_back(to_app(t));
|
m_parents[arg->get_id()].push_back(to_app(t));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void value_sweep::operator()(expr_ref_vector const& terms,
|
void value_sweep::operator()(expr_ref_vector const& terms,
|
||||||
|
|
|
@ -110,28 +110,19 @@ bool create_induction_lemmas::viable_induction_sort(sort* s) {
|
||||||
return m_dt.is_datatype(s) && m_dt.is_recursive(s);
|
return m_dt.is_datatype(s) && m_dt.is_recursive(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool create_induction_lemmas::viable_induction_parent(enode* n) {
|
bool create_induction_lemmas::viable_induction_parent(enode* p, enode* n) {
|
||||||
bool in_good_context = false;
|
|
||||||
for (enode* p : n->get_parents()) {
|
|
||||||
app* o = p->get_owner();
|
app* o = p->get_owner();
|
||||||
if (o->get_family_id() == m.get_basic_family_id())
|
return
|
||||||
continue;
|
m_rec.is_defined(o) ||
|
||||||
if (o->get_family_id() == m_rec.get_family_id()) {
|
m_dt.is_constructor(o);
|
||||||
in_good_context |= m_rec.is_defined(o);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (o->get_family_id() == m_dt.get_family_id()) {
|
|
||||||
in_good_context |= m_dt.is_constructor(o);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return in_good_context;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool create_induction_lemmas::viable_induction_term(enode* n) {
|
bool create_induction_lemmas::viable_induction_children(enode* n) {
|
||||||
app* e = n->get_owner();
|
app* e = n->get_owner();
|
||||||
if (m.is_value(e))
|
if (m.is_value(e))
|
||||||
return false;
|
return false;
|
||||||
|
if (e->get_decl()->is_skolem())
|
||||||
|
return false;
|
||||||
if (n->get_num_args() == 0)
|
if (n->get_num_args() == 0)
|
||||||
return true;
|
return true;
|
||||||
if (e->get_family_id() == m_rec.get_family_id())
|
if (e->get_family_id() == m_rec.get_family_id())
|
||||||
|
@ -141,11 +132,11 @@ bool create_induction_lemmas::viable_induction_term(enode* n) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool create_induction_lemmas::viable_induction_position(enode* n) {
|
bool create_induction_lemmas::viable_induction_term(enode* p, enode* n) {
|
||||||
return
|
return
|
||||||
viable_induction_sort(m.get_sort(n->get_owner())) &&
|
viable_induction_sort(m.get_sort(n->get_owner())) &&
|
||||||
viable_induction_parent(n) &&
|
viable_induction_parent(p, n) &&
|
||||||
viable_induction_term(n);
|
viable_induction_children(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -166,13 +157,18 @@ enode_vector create_induction_lemmas::induction_positions(enode* n) {
|
||||||
add_todo(n);
|
add_todo(n);
|
||||||
for (unsigned i = 0; i < todo.size(); ++i) {
|
for (unsigned i = 0; i < todo.size(); ++i) {
|
||||||
n = todo[i];
|
n = todo[i];
|
||||||
for (enode* a : smt::enode::args(n))
|
for (enode* a : smt::enode::args(n)) {
|
||||||
add_todo(a);
|
add_todo(a);
|
||||||
if (viable_induction_position(n))
|
if (!a->is_marked2() && viable_induction_term(n, a)) {
|
||||||
result.push_back(n);
|
result.push_back(a);
|
||||||
|
a->set_mark2();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for (enode* n : todo)
|
for (enode* n : todo)
|
||||||
n->unset_mark();
|
n->unset_mark();
|
||||||
|
for (enode* n : result)
|
||||||
|
n->unset_mark2();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -261,8 +257,6 @@ void create_induction_lemmas::filter_abstractions(bool sign, abstractions& abs)
|
||||||
* lit & a.eqs() => alpha
|
* lit & a.eqs() => alpha
|
||||||
* alpha & is-c(sk) => ~beta
|
* alpha & is-c(sk) => ~beta
|
||||||
*
|
*
|
||||||
* alpha & is-c(t) => is-c(sk);
|
|
||||||
*
|
|
||||||
* where
|
* where
|
||||||
* lit = is a formula containing t
|
* lit = is a formula containing t
|
||||||
* alpha = a.term(), a variant of lit
|
* alpha = a.term(), a variant of lit
|
||||||
|
@ -278,73 +272,82 @@ void create_induction_lemmas::filter_abstractions(bool sign, abstractions& abs)
|
||||||
* the instance of s is true. In the limit one can
|
* the instance of s is true. In the limit one can
|
||||||
* set beta to all instantiations of smaller values than sk.
|
* set beta to all instantiations of smaller values than sk.
|
||||||
*
|
*
|
||||||
*
|
* create_hypotheses creates induction hypotheses.
|
||||||
* TBD: consider k-inductive lemmas.
|
|
||||||
*/
|
*/
|
||||||
void create_induction_lemmas::create_lemmas(expr* t, expr* sk, abstraction& a, literal lit) {
|
|
||||||
|
void create_induction_lemmas::create_hypotheses(
|
||||||
|
unsigned depth, expr* sk0, expr_ref& alpha, expr* sk, literal_vector& lits) {
|
||||||
|
if (depth == 0)
|
||||||
|
return;
|
||||||
|
sort* s = m.get_sort(sk);
|
||||||
|
for (func_decl* c : *m_dt.get_datatype_constructors(s)) {
|
||||||
|
func_decl* is_c = m_dt.get_constructor_recognizer(c);
|
||||||
|
for (func_decl* acc : *m_dt.get_constructor_accessors(c)) {
|
||||||
|
sort* rs = acc->get_range();
|
||||||
|
if (rs != s && !m_dt.is_datatype(rs))
|
||||||
|
continue;
|
||||||
|
if (rs != s && !m_dt.is_recursive(rs))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
lits.push_back(~mk_literal(m.mk_app(is_c, sk)));
|
||||||
|
|
||||||
|
// alpha & is_c(sk) & is_c'(acc(sk)) => ~alpha[acc'(acc(sk)]
|
||||||
|
if (rs != s && depth > 1) {
|
||||||
|
app_ref acc_sk(m.mk_app(acc, sk), m);
|
||||||
|
create_hypotheses(depth - 1, sk0, alpha, acc_sk, lits);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
expr_ref beta(alpha); // set beta := alpha[sk0/acc(sk)]
|
||||||
|
expr_safe_replace rep(m);
|
||||||
|
rep.insert(sk0, m.mk_app(acc, sk));
|
||||||
|
rep(beta);
|
||||||
|
literal b_lit = mk_literal(beta);
|
||||||
|
|
||||||
|
if (lits[0].sign()) b_lit.neg(); // maintain the same sign as alpha
|
||||||
|
|
||||||
|
// alpha & is_c(sk) => ~beta
|
||||||
|
lits.push_back(~b_lit);
|
||||||
|
literal_vector _lits(lits); // mk_clause could make destructive updates
|
||||||
|
add_th_lemma(_lits);
|
||||||
|
lits.pop_back();
|
||||||
|
}
|
||||||
|
lits.pop_back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void create_induction_lemmas::create_lemmas(expr* sk, abstraction& a, literal lit) {
|
||||||
std::cout << "abstraction: " << a.m_term << "\n";
|
std::cout << "abstraction: " << a.m_term << "\n";
|
||||||
sort* s = m.get_sort(sk);
|
sort* s = m.get_sort(sk);
|
||||||
if (!m_dt.is_datatype(s))
|
if (!m_dt.is_datatype(s))
|
||||||
return;
|
return;
|
||||||
expr_ref alpha = a.m_term;
|
expr_ref alpha = a.m_term;
|
||||||
auto const& eqs = a.m_eqs;
|
literal alpha_lit = mk_literal(alpha);
|
||||||
literal alpha_lit = null_literal;
|
|
||||||
literal_vector common_literals;
|
|
||||||
for (func_decl* c : *m_dt.get_datatype_constructors(s)) {
|
|
||||||
func_decl* is_c = m_dt.get_constructor_recognizer(c);
|
|
||||||
bool has_1recursive = false;
|
|
||||||
for (func_decl* acc : *m_dt.get_constructor_accessors(c)) {
|
|
||||||
if (acc->get_range() != s)
|
|
||||||
continue;
|
|
||||||
if (alpha_lit == null_literal) {
|
|
||||||
alpha_lit = mk_literal(alpha);
|
|
||||||
if (lit.sign()) alpha_lit.neg();
|
if (lit.sign()) alpha_lit.neg();
|
||||||
}
|
|
||||||
has_1recursive = true;
|
|
||||||
expr_ref beta(alpha);
|
|
||||||
expr_safe_replace rep(m);
|
|
||||||
rep.insert(sk, m.mk_app(acc, sk));
|
|
||||||
rep(beta);
|
|
||||||
literal b_lit = mk_literal(beta);
|
|
||||||
if (lit.sign()) b_lit.neg();
|
|
||||||
|
|
||||||
// alpha & is_c(sk) => ~beta
|
|
||||||
literal_vector lits;
|
literal_vector lits;
|
||||||
lits.push_back(~alpha_lit);
|
lits.push_back(~alpha_lit);
|
||||||
lits.push_back(~mk_literal(m.mk_app(is_c, sk)));
|
create_hypotheses(1, sk, alpha, sk, lits);
|
||||||
lits.push_back(~b_lit);
|
lits.pop_back();
|
||||||
add_th_lemma(lits);
|
|
||||||
}
|
|
||||||
|
|
||||||
// alpha & is_c(t) => is_c(sk)
|
|
||||||
if (has_1recursive) {
|
|
||||||
literal_vector lits;
|
|
||||||
lits.push_back(~alpha_lit);
|
|
||||||
lits.push_back(~mk_literal(m.mk_app(is_c, t)));
|
|
||||||
lits.push_back(mk_literal(m.mk_app(is_c, sk)));
|
|
||||||
add_th_lemma(lits);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// phi & eqs => alpha
|
// phi & eqs => alpha
|
||||||
if (alpha_lit != null_literal) {
|
|
||||||
literal_vector lits;
|
|
||||||
lits.push_back(~lit);
|
lits.push_back(~lit);
|
||||||
for (auto const& p : eqs) {
|
for (auto const& p : a.m_eqs) {
|
||||||
lits.push_back(~mk_literal(m.mk_eq(p.first, p.second)));
|
lits.push_back(~mk_literal(m.mk_eq(p.first, p.second)));
|
||||||
}
|
}
|
||||||
lits.push_back(alpha_lit);
|
lits.push_back(alpha_lit);
|
||||||
add_th_lemma(lits);
|
add_th_lemma(lits);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void create_induction_lemmas::add_th_lemma(literal_vector const& lits) {
|
void create_induction_lemmas::add_th_lemma(literal_vector const& lits) {
|
||||||
IF_VERBOSE(1, ctx.display_literals_verbose(verbose_stream() << "lemma:\n", lits) << "\n");
|
IF_VERBOSE(0, ctx.display_literals_verbose(verbose_stream() << "lemma:\n", lits) << "\n");
|
||||||
ctx.mk_clause(lits.size(), lits.c_ptr(), nullptr, smt::CLS_TH_AXIOM); // CLS_TH_LEMMA, but then should re-instance if GC'ed
|
ctx.mk_clause(lits.size(), lits.c_ptr(), nullptr, smt::CLS_TH_AXIOM);
|
||||||
|
// CLS_TH_LEMMA, but then should re-instance if GC'ed
|
||||||
++m_num_lemmas;
|
++m_num_lemmas;
|
||||||
}
|
}
|
||||||
|
|
||||||
literal create_induction_lemmas::mk_literal(expr* e) {
|
literal create_induction_lemmas::mk_literal(expr* e) {
|
||||||
|
expr_ref _e(e, m);
|
||||||
if (!ctx.e_internalized(e)) {
|
if (!ctx.e_internalized(e)) {
|
||||||
ctx.internalize(e, false);
|
ctx.internalize(e, false);
|
||||||
}
|
}
|
||||||
|
@ -367,9 +370,8 @@ bool create_induction_lemmas::operator()(literal lit) {
|
||||||
// if (ab.size() > 1) abs.pop_back(); // last position has no generalizations
|
// if (ab.size() > 1) abs.pop_back(); // last position has no generalizations
|
||||||
if (abs.size() > 1) filter_abstractions(lit.sign(), abs);
|
if (abs.size() > 1) filter_abstractions(lit.sign(), abs);
|
||||||
for (abstraction& a : abs) {
|
for (abstraction& a : abs) {
|
||||||
create_lemmas(t, sk, a, lit);
|
create_lemmas(sk, a, lit);
|
||||||
}
|
}
|
||||||
std::cout << "lemmas created\n";
|
|
||||||
++position;
|
++position;
|
||||||
}
|
}
|
||||||
return m_num_lemmas > num;
|
return m_num_lemmas > num;
|
||||||
|
@ -398,12 +400,15 @@ void induction::init_values() {
|
||||||
for (enode* n : ctx.enodes())
|
for (enode* n : ctx.enodes())
|
||||||
if (m.is_value(n->get_owner()))
|
if (m.is_value(n->get_owner()))
|
||||||
for (enode* r : *n)
|
for (enode* r : *n)
|
||||||
|
if (r != n) {
|
||||||
vs.set_value(r->get_owner(), n->get_owner());
|
vs.set_value(r->get_owner(), n->get_owner());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool induction::operator()() {
|
bool induction::operator()() {
|
||||||
bool added_lemma = false;
|
bool added_lemma = false;
|
||||||
vs.reset_values();
|
vs.reset_values();
|
||||||
|
init_values();
|
||||||
literal_vector candidates = m_collect_literals();
|
literal_vector candidates = m_collect_literals();
|
||||||
for (literal lit : candidates) {
|
for (literal lit : candidates) {
|
||||||
if (m_create_lemmas(lit))
|
if (m_create_lemmas(lit))
|
||||||
|
|
|
@ -84,14 +84,15 @@ namespace smt {
|
||||||
typedef vector<abstraction_arg> abstraction_args;
|
typedef vector<abstraction_arg> abstraction_args;
|
||||||
|
|
||||||
bool viable_induction_sort(sort* s);
|
bool viable_induction_sort(sort* s);
|
||||||
bool viable_induction_parent(enode* n);
|
bool viable_induction_parent(enode* p, enode* n);
|
||||||
bool viable_induction_term(enode* n);
|
bool viable_induction_children(enode* n);
|
||||||
bool viable_induction_position(enode* n);
|
bool viable_induction_term(enode* p , enode* n);
|
||||||
enode_vector induction_positions(enode* n);
|
enode_vector induction_positions(enode* n);
|
||||||
void abstract(enode* n, enode* t, expr* x, abstractions& result);
|
void abstract(enode* n, enode* t, expr* x, abstractions& result);
|
||||||
void abstract1(enode* n, enode* t, expr* x, abstractions& result);
|
void abstract1(enode* n, enode* t, expr* x, abstractions& result);
|
||||||
void filter_abstractions(bool sign, abstractions& abs);
|
void filter_abstractions(bool sign, abstractions& abs);
|
||||||
void create_lemmas(expr* t, expr* sk, abstraction& a, literal lit);
|
void create_lemmas(expr* sk, abstraction& a, literal lit);
|
||||||
|
void create_hypotheses(unsigned depth, expr* sk0, expr_ref& alpha, expr* sk, literal_vector& lits);
|
||||||
literal mk_literal(expr* e);
|
literal mk_literal(expr* e);
|
||||||
void add_th_lemma(literal_vector const& lits);
|
void add_th_lemma(literal_vector const& lits);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue