mirror of
https://github.com/Z3Prover/z3
synced 2025-04-12 12:08:18 +00:00
formatting/reviewing
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
d2ae3b4025
commit
c3fb863ad1
|
@ -1744,6 +1744,14 @@ public:
|
||||||
arity, domain);
|
arity, domain);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func_decl * mk_const_decl(const char* name, sort * s) {
|
||||||
|
return mk_func_decl(symbol(name), static_cast<unsigned>(0), nullptr, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
func_decl * mk_const_decl(std::string const& name, sort * s) {
|
||||||
|
return mk_func_decl(symbol(name.c_str()), static_cast<unsigned>(0), nullptr, s);
|
||||||
|
}
|
||||||
|
|
||||||
func_decl * mk_const_decl(symbol const & name, sort * s) {
|
func_decl * mk_const_decl(symbol const & name, sort * s) {
|
||||||
return mk_func_decl(name, static_cast<unsigned>(0), nullptr, s);
|
return mk_func_decl(name, static_cast<unsigned>(0), nullptr, s);
|
||||||
}
|
}
|
||||||
|
@ -1810,6 +1818,14 @@ public:
|
||||||
return mk_const(mk_const_decl(name, s));
|
return mk_const(mk_const_decl(name, s));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
app * mk_const(std::string const & name, sort * s) {
|
||||||
|
return mk_const(mk_const_decl(name, s));
|
||||||
|
}
|
||||||
|
|
||||||
|
app * mk_const(char const* name, sort * s) {
|
||||||
|
return mk_const(mk_const_decl(name, s));
|
||||||
|
}
|
||||||
|
|
||||||
func_decl * mk_fresh_func_decl(symbol const & prefix, symbol const & suffix, unsigned arity,
|
func_decl * mk_fresh_func_decl(symbol const & prefix, symbol const & suffix, unsigned arity,
|
||||||
sort * const * domain, sort * range);
|
sort * const * domain, sort * range);
|
||||||
|
|
||||||
|
@ -2150,6 +2166,23 @@ public:
|
||||||
return n > 0 && get_sort(p->get_arg(n - 1)) != m_proof_sort;
|
return n > 0 && get_sort(p->get_arg(n - 1)) != m_proof_sort;
|
||||||
}
|
}
|
||||||
expr * get_fact(proof const * p) const { SASSERT(is_proof(p)); SASSERT(has_fact(p)); return p->get_arg(p->get_num_args() - 1); }
|
expr * get_fact(proof const * p) const { SASSERT(is_proof(p)); SASSERT(has_fact(p)); return p->get_arg(p->get_num_args() - 1); }
|
||||||
|
|
||||||
|
class proof_parents {
|
||||||
|
ast_manager& m;
|
||||||
|
proof * m_proof;
|
||||||
|
public:
|
||||||
|
proof_parents(ast_manager& m, proof * p): m(m), m_proof(p) {}
|
||||||
|
proof * const * begin() const { return (proof* const*)(m_proof->begin()); }
|
||||||
|
proof * const * end() const {
|
||||||
|
unsigned n = m_proof->get_num_args();
|
||||||
|
return (proof* const*)(begin() + (m.has_fact(m_proof) ? n - 1 : n));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
proof_parents get_parents(proof* p) {
|
||||||
|
return proof_parents(*this, p);
|
||||||
|
}
|
||||||
|
|
||||||
unsigned get_num_parents(proof const * p) const {
|
unsigned get_num_parents(proof const * p) const {
|
||||||
SASSERT(is_proof(p));
|
SASSERT(is_proof(p));
|
||||||
unsigned n = p->get_num_args();
|
unsigned n = p->get_num_args();
|
||||||
|
|
|
@ -1500,11 +1500,9 @@ void pred_transformer::mk_assumptions(func_decl* head, expr* fml,
|
||||||
expr_ref_vector& result)
|
expr_ref_vector& result)
|
||||||
{
|
{
|
||||||
expr_ref tmp1(m), tmp2(m);
|
expr_ref tmp1(m), tmp2(m);
|
||||||
obj_map<expr, datalog::rule const*>::iterator it = m_tag2rule.begin(),
|
for (auto& kv : m_tag2rule) {
|
||||||
end = m_tag2rule.end();
|
expr* tag = kv.m_key;
|
||||||
for (; it != end; ++it) {
|
datalog::rule const* r = kv.m_value;
|
||||||
expr* tag = it->m_key;
|
|
||||||
datalog::rule const* r = it->m_value;
|
|
||||||
if (!r) { continue; }
|
if (!r) { continue; }
|
||||||
find_predecessors(*r, m_predicates);
|
find_predecessors(*r, m_predicates);
|
||||||
for (unsigned i = 0; i < m_predicates.size(); i++) {
|
for (unsigned i = 0; i < m_predicates.size(); i++) {
|
||||||
|
@ -2338,7 +2336,6 @@ void context::init_rules(datalog::rule_set& rules, decl2rel& rels)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize use list dependencies
|
// Initialize use list dependencies
|
||||||
// for (auto it = rels.begin(), end = rels.end(); it != end; ++it) {
|
|
||||||
for (auto &entry : rels) {
|
for (auto &entry : rels) {
|
||||||
func_decl* pred = entry.m_key;
|
func_decl* pred = entry.m_key;
|
||||||
pred_transformer* pt = entry.m_value, *pt_user = nullptr;
|
pred_transformer* pt = entry.m_value, *pt_user = nullptr;
|
||||||
|
@ -2464,14 +2461,13 @@ bool context::validate()
|
||||||
get_level_property(m_inductive_lvl, refs, rs);
|
get_level_property(m_inductive_lvl, refs, rs);
|
||||||
inductive_property ex(m, mc, rs);
|
inductive_property ex(m, mc, rs);
|
||||||
ex.to_model(model);
|
ex.to_model(model);
|
||||||
decl2rel::iterator it = m_rels.begin(), end = m_rels.end();
|
|
||||||
var_subst vs(m, false);
|
var_subst vs(m, false);
|
||||||
for (; it != end; ++it) {
|
for (auto& kv : m_rels) {
|
||||||
ptr_vector<datalog::rule> const& rules = it->m_value->rules();
|
ptr_vector<datalog::rule> const& rules = kv.m_value->rules();
|
||||||
TRACE ("spacer", tout << "PT: " << it->m_value->head ()->get_name ().str ()
|
TRACE ("spacer", tout << "PT: " << kv.m_value->head ()->get_name ().str ()
|
||||||
<< "\n";);
|
<< "\n";);
|
||||||
for (unsigned i = 0; i < rules.size(); ++i) {
|
for (auto* rp : rules) {
|
||||||
datalog::rule& r = *rules[i];
|
datalog::rule& r = *rp;
|
||||||
|
|
||||||
TRACE ("spacer",
|
TRACE ("spacer",
|
||||||
get_datalog_context ().
|
get_datalog_context ().
|
||||||
|
@ -2603,11 +2599,9 @@ void context::init_lemma_generalizers()
|
||||||
}
|
}
|
||||||
|
|
||||||
void context::get_level_property(unsigned lvl, expr_ref_vector& res,
|
void context::get_level_property(unsigned lvl, expr_ref_vector& res,
|
||||||
vector<relation_info>& rs) const
|
vector<relation_info>& rs) const {
|
||||||
{
|
for (auto const& kv : m_rels) {
|
||||||
decl2rel::iterator it = m_rels.begin(), end = m_rels.end();
|
pred_transformer* r = kv.m_value;
|
||||||
for (; it != end; ++it) {
|
|
||||||
pred_transformer* r = it->m_value;
|
|
||||||
if (r->head() == m_query_pred) {
|
if (r->head() == m_query_pred) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -2619,12 +2613,9 @@ void context::get_level_property(unsigned lvl, expr_ref_vector& res,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void context::simplify_formulas()
|
void context::simplify_formulas() {
|
||||||
{
|
for (auto& kv : m_rels) {
|
||||||
decl2rel::iterator it = m_rels.begin(), end = m_rels.end();
|
kv.m_value->simplify_formulas();
|
||||||
for (; it != end; ++it) {
|
|
||||||
pred_transformer* r = it->m_value;
|
|
||||||
r->simplify_formulas();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3549,18 +3540,17 @@ bool context::propagate(unsigned min_prop_lvl,
|
||||||
tout << "In full propagation\n";);
|
tout << "In full propagation\n";);
|
||||||
|
|
||||||
bool all_propagated = true;
|
bool all_propagated = true;
|
||||||
decl2rel::iterator it = m_rels.begin(), end = m_rels.end();
|
for (auto & kv : m_rels) {
|
||||||
for (; it != end; ++it) {
|
|
||||||
checkpoint();
|
checkpoint();
|
||||||
pred_transformer& r = *it->m_value;
|
pred_transformer& r = *kv.m_value;
|
||||||
all_propagated = r.propagate_to_next_level(lvl) && all_propagated;
|
all_propagated = r.propagate_to_next_level(lvl) && all_propagated;
|
||||||
}
|
}
|
||||||
//CASSERT("spacer", check_invariant(lvl));
|
//CASSERT("spacer", check_invariant(lvl));
|
||||||
|
|
||||||
if (all_propagated) {
|
if (all_propagated) {
|
||||||
for (it = m_rels.begin(); it != end; ++it) {
|
for (auto& kv : m_rels) {
|
||||||
checkpoint ();
|
checkpoint ();
|
||||||
pred_transformer& r = *it->m_value;
|
pred_transformer& r = *kv.m_value;
|
||||||
r.propagate_to_infinity (lvl);
|
r.propagate_to_infinity (lvl);
|
||||||
}
|
}
|
||||||
if (lvl <= max_prop_lvl) {
|
if (lvl <= max_prop_lvl) {
|
||||||
|
@ -3793,9 +3783,8 @@ void context::collect_statistics(statistics& st) const
|
||||||
m_pool1->collect_statistics(st);
|
m_pool1->collect_statistics(st);
|
||||||
m_pool2->collect_statistics(st);
|
m_pool2->collect_statistics(st);
|
||||||
|
|
||||||
decl2rel::iterator it = m_rels.begin(), end = m_rels.end();
|
for (auto const& kv : m_rels) {
|
||||||
for (it = m_rels.begin(); it != end; ++it) {
|
kv.m_value->collect_statistics(st);
|
||||||
it->m_value->collect_statistics(st);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// -- number of times a pob for some predicate transformer has
|
// -- number of times a pob for some predicate transformer has
|
||||||
|
@ -3846,9 +3835,8 @@ void context::reset_statistics()
|
||||||
m_pool1->reset_statistics();
|
m_pool1->reset_statistics();
|
||||||
m_pool2->reset_statistics();
|
m_pool2->reset_statistics();
|
||||||
|
|
||||||
decl2rel::iterator it = m_rels.begin(), end = m_rels.end();
|
for (auto & kv : m_rels) {
|
||||||
for (it = m_rels.begin(); it != end; ++it) {
|
kv.m_value->reset_statistics();
|
||||||
it->m_value->reset_statistics();
|
|
||||||
}
|
}
|
||||||
m_stats.reset();
|
m_stats.reset();
|
||||||
|
|
||||||
|
@ -3897,9 +3885,8 @@ expr_ref context::get_constraints (unsigned level)
|
||||||
expr_ref res(m);
|
expr_ref res(m);
|
||||||
expr_ref_vector constraints(m);
|
expr_ref_vector constraints(m);
|
||||||
|
|
||||||
decl2rel::iterator it = m_rels.begin(), end = m_rels.end();
|
for (auto & kv : m_rels) {
|
||||||
for (; it != end; ++it) {
|
pred_transformer& r = *kv.m_value;
|
||||||
pred_transformer& r = *it->m_value;
|
|
||||||
expr_ref c = r.get_formulas(level);
|
expr_ref c = r.get_formulas(level);
|
||||||
|
|
||||||
if (m.is_true(c)) { continue; }
|
if (m.is_true(c)) { continue; }
|
||||||
|
|
|
@ -176,7 +176,7 @@ public:
|
||||||
void dec_ref () {
|
void dec_ref () {
|
||||||
SASSERT (m_ref_count > 0);
|
SASSERT (m_ref_count > 0);
|
||||||
--m_ref_count;
|
--m_ref_count;
|
||||||
if(m_ref_count == 0) {dealloc(this);}
|
if (m_ref_count == 0) {dealloc(this);}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -242,7 +242,7 @@ class pred_transformer {
|
||||||
}
|
}
|
||||||
void get_frame_geq_lemmas (unsigned level, expr_ref_vector &out) const {
|
void get_frame_geq_lemmas (unsigned level, expr_ref_vector &out) const {
|
||||||
for (auto &lemma : m_lemmas) {
|
for (auto &lemma : m_lemmas) {
|
||||||
if(lemma->level() >= level) {
|
if (lemma->level() >= level) {
|
||||||
out.push_back(lemma->get_expr());
|
out.push_back(lemma->get_expr());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -362,7 +362,7 @@ public:
|
||||||
void find_predecessors(datalog::rule const& r, ptr_vector<func_decl>& predicates) const;
|
void find_predecessors(datalog::rule const& r, ptr_vector<func_decl>& predicates) const;
|
||||||
|
|
||||||
void add_rule(datalog::rule* r) {m_rules.push_back(r);}
|
void add_rule(datalog::rule* r) {m_rules.push_back(r);}
|
||||||
void add_use(pred_transformer* pt) {if(!m_use.contains(pt)) {m_use.insert(pt);}}
|
void add_use(pred_transformer* pt) {if (!m_use.contains(pt)) {m_use.insert(pt);}}
|
||||||
void initialize(decl2rel const& pts);
|
void initialize(decl2rel const& pts);
|
||||||
|
|
||||||
func_decl* head() const {return m_head;}
|
func_decl* head() const {return m_head;}
|
||||||
|
@ -528,7 +528,7 @@ public:
|
||||||
pob (pob* parent, pred_transformer& pt,
|
pob (pob* parent, pred_transformer& pt,
|
||||||
unsigned level, unsigned depth=0, bool add_to_parent=true);
|
unsigned level, unsigned depth=0, bool add_to_parent=true);
|
||||||
|
|
||||||
~pob() {if(m_parent) { m_parent->erase_child(*this); }}
|
~pob() {if (m_parent) { m_parent->erase_child(*this); }}
|
||||||
|
|
||||||
unsigned weakness() {return m_weakness;}
|
unsigned weakness() {return m_weakness;}
|
||||||
void bump_weakness() {m_weakness++;}
|
void bump_weakness() {m_weakness++;}
|
||||||
|
@ -564,7 +564,7 @@ public:
|
||||||
void set_post(expr *post, app_ref_vector const &binding);
|
void set_post(expr *post, app_ref_vector const &binding);
|
||||||
|
|
||||||
/// indicate that a new post should be set for the node
|
/// indicate that a new post should be set for the node
|
||||||
void new_post(expr *post) {if(post != m_post) {m_new_post = post;}}
|
void new_post(expr *post) {if (post != m_post) {m_new_post = post;}}
|
||||||
/// true if the node needs to be updated outside of the priority queue
|
/// true if the node needs to be updated outside of the priority queue
|
||||||
bool is_dirty () {return m_new_post;}
|
bool is_dirty () {return m_new_post;}
|
||||||
/// clean a dirty node
|
/// clean a dirty node
|
||||||
|
@ -592,14 +592,14 @@ public:
|
||||||
*/
|
*/
|
||||||
void get_skolems(app_ref_vector& v);
|
void get_skolems(app_ref_vector& v);
|
||||||
|
|
||||||
void on_expand() { m_expand_watches[m_depth].start(); if(m_parent.get()){m_parent.get()->on_expand();} }
|
void on_expand() { m_expand_watches[m_depth].start(); if (m_parent.get()){m_parent.get()->on_expand();} }
|
||||||
void off_expand() { m_expand_watches[m_depth].stop(); if(m_parent.get()){m_parent.get()->off_expand();} };
|
void off_expand() { m_expand_watches[m_depth].stop(); if (m_parent.get()){m_parent.get()->off_expand();} };
|
||||||
double get_expand_time(unsigned depth) { return m_expand_watches[depth].get_seconds();}
|
double get_expand_time(unsigned depth) { return m_expand_watches[depth].get_seconds();}
|
||||||
|
|
||||||
void inc_ref () {++m_ref_count;}
|
void inc_ref () {++m_ref_count;}
|
||||||
void dec_ref () {
|
void dec_ref () {
|
||||||
--m_ref_count;
|
--m_ref_count;
|
||||||
if(m_ref_count == 0) {dealloc(this);}
|
if (m_ref_count == 0) {dealloc(this);}
|
||||||
}
|
}
|
||||||
|
|
||||||
class on_expand_event
|
class on_expand_event
|
||||||
|
@ -727,7 +727,7 @@ public:
|
||||||
SASSERT (!m_obligations.empty () || m_root);
|
SASSERT (!m_obligations.empty () || m_root);
|
||||||
m_max_level++;
|
m_max_level++;
|
||||||
m_min_depth++;
|
m_min_depth++;
|
||||||
if(m_root && m_obligations.empty()) { m_obligations.push(m_root); }
|
if (m_root && m_obligations.empty()) { m_obligations.push(m_root); }
|
||||||
}
|
}
|
||||||
|
|
||||||
pob& get_root() const {return *m_root.get ();}
|
pob& get_root() const {return *m_root.get ();}
|
||||||
|
|
|
@ -99,8 +99,9 @@ void iuc_solver::pop_bg (unsigned n)
|
||||||
{
|
{
|
||||||
if (n == 0) { return; }
|
if (n == 0) { return; }
|
||||||
|
|
||||||
if (m_assumptions.size () > m_first_assumption)
|
if (m_assumptions.size () > m_first_assumption) {
|
||||||
{ m_assumptions.shrink(m_first_assumption); }
|
m_assumptions.shrink(m_first_assumption);
|
||||||
|
}
|
||||||
m_first_assumption = m_first_assumption > n ? m_first_assumption - n : 0;
|
m_first_assumption = m_first_assumption > n ? m_first_assumption - n : 0;
|
||||||
m_assumptions.shrink (m_first_assumption);
|
m_assumptions.shrink (m_first_assumption);
|
||||||
}
|
}
|
||||||
|
@ -110,9 +111,8 @@ unsigned iuc_solver::get_num_bg () {return m_first_assumption;}
|
||||||
lbool iuc_solver::check_sat (unsigned num_assumptions, expr * const *assumptions)
|
lbool iuc_solver::check_sat (unsigned num_assumptions, expr * const *assumptions)
|
||||||
{
|
{
|
||||||
// -- remove any old assumptions
|
// -- remove any old assumptions
|
||||||
if (m_assumptions.size () > m_first_assumption)
|
m_assumptions.shrink(m_first_assumption);
|
||||||
{ m_assumptions.shrink(m_first_assumption); }
|
|
||||||
|
|
||||||
// -- replace theory literals in background assumptions with proxies
|
// -- replace theory literals in background assumptions with proxies
|
||||||
mk_proxies (m_assumptions);
|
mk_proxies (m_assumptions);
|
||||||
// -- in case mk_proxies added new literals, they are all background
|
// -- in case mk_proxies added new literals, they are all background
|
||||||
|
@ -121,20 +121,17 @@ lbool iuc_solver::check_sat (unsigned num_assumptions, expr * const *assumptions
|
||||||
m_assumptions.append (num_assumptions, assumptions);
|
m_assumptions.append (num_assumptions, assumptions);
|
||||||
m_is_proxied = mk_proxies (m_assumptions, m_first_assumption);
|
m_is_proxied = mk_proxies (m_assumptions, m_first_assumption);
|
||||||
|
|
||||||
lbool res;
|
return set_status (m_solver.check_sat (m_assumptions));
|
||||||
res = m_solver.check_sat (m_assumptions.size (), m_assumptions.c_ptr ());
|
|
||||||
set_status (res);
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lbool iuc_solver::check_sat_cc(const expr_ref_vector &cube,
|
lbool iuc_solver::check_sat_cc(const expr_ref_vector &cube,
|
||||||
vector<expr_ref_vector> const & clauses) {
|
vector<expr_ref_vector> const & clauses) {
|
||||||
if (clauses.empty()) {return check_sat(cube.size(), cube.c_ptr());}
|
if (clauses.empty())
|
||||||
|
return check_sat(cube.size(), cube.c_ptr());
|
||||||
|
|
||||||
// -- remove any old assumptions
|
// -- remove any old assumptions
|
||||||
if (m_assumptions.size() > m_first_assumption)
|
m_assumptions.shrink(m_first_assumption);
|
||||||
{ m_assumptions.shrink(m_first_assumption); }
|
|
||||||
|
|
||||||
// -- replace theory literals in background assumptions with proxies
|
// -- replace theory literals in background assumptions with proxies
|
||||||
mk_proxies(m_assumptions);
|
mk_proxies(m_assumptions);
|
||||||
// -- in case mk_proxies added new literals, they are all background
|
// -- in case mk_proxies added new literals, they are all background
|
||||||
|
@ -143,28 +140,24 @@ lbool iuc_solver::check_sat_cc(const expr_ref_vector &cube,
|
||||||
m_assumptions.append(cube);
|
m_assumptions.append(cube);
|
||||||
m_is_proxied = mk_proxies(m_assumptions, m_first_assumption);
|
m_is_proxied = mk_proxies(m_assumptions, m_first_assumption);
|
||||||
|
|
||||||
lbool res;
|
return set_status (m_solver.check_sat_cc(m_assumptions, clauses));
|
||||||
res = m_solver.check_sat_cc(m_assumptions, clauses);
|
|
||||||
set_status (res);
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
app* iuc_solver::def_manager::mk_proxy (expr *v)
|
app* iuc_solver::def_manager::mk_proxy (expr *v)
|
||||||
{
|
{
|
||||||
app* r;
|
app* r;
|
||||||
if (m_expr2proxy.find(v, r)) { return r; }
|
if (m_expr2proxy.find(v, r))
|
||||||
|
return r;
|
||||||
|
|
||||||
ast_manager &m = m_parent.m;
|
ast_manager &m = m_parent.m;
|
||||||
app_ref proxy(m);
|
app* proxy = m_parent.fresh_proxy ();
|
||||||
app_ref def(m);
|
app* def = m.mk_or (m.mk_not (proxy), v);
|
||||||
proxy = m_parent.fresh_proxy ();
|
|
||||||
def = m.mk_or (m.mk_not (proxy), v);
|
|
||||||
m_defs.push_back (def);
|
m_defs.push_back (def);
|
||||||
m_expr2proxy.insert (v, proxy);
|
m_expr2proxy.insert (v, proxy);
|
||||||
m_proxy2def.insert (proxy, def);
|
m_proxy2def.insert (proxy, def);
|
||||||
|
|
||||||
m_parent.assert_expr (def.get ());
|
m_parent.assert_expr (def);
|
||||||
return proxy;
|
return proxy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,18 +184,16 @@ bool iuc_solver::def_manager::is_proxy_def (expr *v)
|
||||||
|
|
||||||
bool iuc_solver::is_proxy(expr *e, app_ref &def)
|
bool iuc_solver::is_proxy(expr *e, app_ref &def)
|
||||||
{
|
{
|
||||||
if (!is_uninterp_const(e)) { return false; }
|
if (!is_uninterp_const(e))
|
||||||
|
return false;
|
||||||
|
|
||||||
app *a = to_app (e);
|
app* a = to_app (e);
|
||||||
|
|
||||||
for (int i = m_defs.size (); i > 0; --i)
|
for (int i = m_defs.size (); i-- > 0; )
|
||||||
if (m_defs[i-1].is_proxy (a, def))
|
if (m_defs[i].is_proxy (a, def))
|
||||||
{ return true; }
|
return true;
|
||||||
|
|
||||||
if (m_base_defs.is_proxy (a, def))
|
return m_base_defs.is_proxy (a, def);
|
||||||
{ return true; }
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void iuc_solver::collect_statistics (statistics &st) const
|
void iuc_solver::collect_statistics (statistics &st) const
|
||||||
|
@ -233,21 +224,25 @@ void iuc_solver::undo_proxies_in_core (ptr_vector<expr> &r)
|
||||||
{
|
{
|
||||||
app_ref e(m);
|
app_ref e(m);
|
||||||
expr_fast_mark1 bg;
|
expr_fast_mark1 bg;
|
||||||
for (unsigned i = 0; i < m_first_assumption; ++i)
|
for (unsigned i = 0; i < m_first_assumption; ++i) {
|
||||||
{ bg.mark(m_assumptions.get(i)); }
|
bg.mark(m_assumptions.get(i));
|
||||||
|
}
|
||||||
|
|
||||||
// expand proxies
|
// expand proxies
|
||||||
unsigned j = 0;
|
unsigned j = 0;
|
||||||
for (unsigned i = 0, sz = r.size(); i < sz; ++i) {
|
for (expr* rr : r) {
|
||||||
// skip background assumptions
|
// skip background assumptions
|
||||||
if (bg.is_marked(r[i])) { continue; }
|
if (bg.is_marked(rr))
|
||||||
|
continue;
|
||||||
|
|
||||||
// -- undo proxies, but only if they were introduced in check_sat
|
// -- undo proxies, but only if they were introduced in check_sat
|
||||||
if (m_is_proxied && is_proxy(r[i], e)) {
|
if (m_is_proxied && is_proxy(rr, e)) {
|
||||||
SASSERT (m.is_or (e));
|
SASSERT (m.is_or (e));
|
||||||
r[j] = e->get_arg (1);
|
r[j++] = e->get_arg (1);
|
||||||
} else if (i != j) { r[j] = r[i]; }
|
}
|
||||||
j++;
|
else {
|
||||||
|
r[j++] = rr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
r.shrink (j);
|
r.shrink (j);
|
||||||
}
|
}
|
||||||
|
@ -370,65 +365,66 @@ void iuc_solver::get_iuc(expr_ref_vector &core)
|
||||||
|
|
||||||
unsat_core_learner learner(m, iuc_pf);
|
unsat_core_learner learner(m, iuc_pf);
|
||||||
|
|
||||||
|
unsat_core_plugin* plugin;
|
||||||
// -- register iuc plugins
|
// -- register iuc plugins
|
||||||
if (m_iuc_arith == 0 || m_iuc_arith == 1) {
|
switch (m_iuc_arith) {
|
||||||
unsat_core_plugin_farkas_lemma* plugin =
|
case 0:
|
||||||
|
case 1:
|
||||||
|
plugin =
|
||||||
alloc(unsat_core_plugin_farkas_lemma,
|
alloc(unsat_core_plugin_farkas_lemma,
|
||||||
learner, m_split_literals,
|
learner, m_split_literals,
|
||||||
(m_iuc_arith == 1) /* use constants from A */);
|
(m_iuc_arith == 1) /* use constants from A */);
|
||||||
learner.register_plugin(plugin);
|
learner.register_plugin(plugin);
|
||||||
}
|
break;
|
||||||
else if (m_iuc_arith == 2) {
|
case 2:
|
||||||
SASSERT(false && "Broken");
|
SASSERT(false && "Broken");
|
||||||
unsat_core_plugin_farkas_lemma_optimized* plugin =
|
plugin = alloc(unsat_core_plugin_farkas_lemma_optimized, learner, m);
|
||||||
alloc(unsat_core_plugin_farkas_lemma_optimized, learner, m);
|
|
||||||
learner.register_plugin(plugin);
|
learner.register_plugin(plugin);
|
||||||
}
|
break;
|
||||||
else if(m_iuc_arith == 3) {
|
case 3:
|
||||||
unsat_core_plugin_farkas_lemma_bounded* plugin =
|
plugin = alloc(unsat_core_plugin_farkas_lemma_bounded, learner, m);
|
||||||
alloc(unsat_core_plugin_farkas_lemma_bounded, learner, m);
|
|
||||||
learner.register_plugin(plugin);
|
learner.register_plugin(plugin);
|
||||||
}
|
break;
|
||||||
else {
|
default:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_iuc == 1) {
|
switch (m_iuc) {
|
||||||
|
case 1:
|
||||||
// -- iuc based on the lowest cut in the proof
|
// -- iuc based on the lowest cut in the proof
|
||||||
unsat_core_plugin_lemma* plugin =
|
plugin = alloc(unsat_core_plugin_lemma, learner);
|
||||||
alloc(unsat_core_plugin_lemma, learner);
|
|
||||||
learner.register_plugin(plugin);
|
learner.register_plugin(plugin);
|
||||||
}
|
break;
|
||||||
else if (m_iuc == 2) {
|
case 2:
|
||||||
// -- iuc based on the smallest cut in the proof
|
// -- iuc based on the smallest cut in the proof
|
||||||
unsat_core_plugin_min_cut* plugin =
|
plugin = alloc(unsat_core_plugin_min_cut, learner, m);
|
||||||
alloc(unsat_core_plugin_min_cut, learner, m);
|
|
||||||
learner.register_plugin(plugin);
|
learner.register_plugin(plugin);
|
||||||
}
|
break;
|
||||||
else {
|
default:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
scoped_watch _t_ (m_learn_core_sw);
|
scoped_watch _t_ (m_learn_core_sw);
|
||||||
// compute interpolating unsat core
|
// compute interpolating unsat core
|
||||||
learner.compute_unsat_core(core);
|
learner.compute_unsat_core(core);
|
||||||
}
|
}
|
||||||
|
|
||||||
elim_proxies (core);
|
elim_proxies (core);
|
||||||
// AG: this should be taken care of by minimizing the iuc cut
|
// AG: this should be taken care of by minimizing the iuc cut
|
||||||
simplify_bounds (core);
|
simplify_bounds (core);
|
||||||
}
|
}
|
||||||
|
|
||||||
IF_VERBOSE(2,
|
IF_VERBOSE(2,
|
||||||
verbose_stream () << "IUC Core:\n"
|
verbose_stream () << "IUC Core:\n" << core << "\n";);
|
||||||
<< mk_and(core) << "\n";);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void iuc_solver::refresh ()
|
void iuc_solver::refresh ()
|
||||||
{
|
{
|
||||||
// only refresh in non-pushed state
|
// only refresh in non-pushed state
|
||||||
SASSERT (m_defs.size () == 0);
|
SASSERT (m_defs.empty());
|
||||||
expr_ref_vector assertions (m);
|
expr_ref_vector assertions (m);
|
||||||
for (unsigned i = 0, e = m_solver.get_num_assertions(); i < e; ++i) {
|
for (unsigned i = 0, e = m_solver.get_num_assertions(); i < e; ++i) {
|
||||||
expr* a = m_solver.get_assertion (i);
|
expr* a = m_solver.get_assertion (i);
|
||||||
|
|
|
@ -26,11 +26,10 @@ namespace spacer {
|
||||||
class iuc_solver : public solver {
|
class iuc_solver : public solver {
|
||||||
private:
|
private:
|
||||||
struct def_manager {
|
struct def_manager {
|
||||||
iuc_solver &m_parent;
|
iuc_solver & m_parent;
|
||||||
|
expr_ref_vector m_defs;
|
||||||
obj_map<expr, app*> m_expr2proxy;
|
obj_map<expr, app*> m_expr2proxy;
|
||||||
obj_map<app, app*> m_proxy2def;
|
obj_map<app, app*> m_proxy2def;
|
||||||
|
|
||||||
expr_ref_vector m_defs;
|
|
||||||
|
|
||||||
def_manager(iuc_solver &parent) :
|
def_manager(iuc_solver &parent) :
|
||||||
m_parent(parent), m_defs(m_parent.m)
|
m_parent(parent), m_defs(m_parent.m)
|
||||||
|
@ -44,15 +43,15 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
friend struct def_manager;
|
friend struct def_manager;
|
||||||
ast_manager &m;
|
ast_manager& m;
|
||||||
solver &m_solver;
|
solver& m_solver;
|
||||||
app_ref_vector m_proxies;
|
app_ref_vector m_proxies;
|
||||||
unsigned m_num_proxies;
|
unsigned m_num_proxies;
|
||||||
vector<def_manager> m_defs;
|
vector<def_manager> m_defs;
|
||||||
def_manager m_base_defs;
|
def_manager m_base_defs;
|
||||||
expr_ref_vector m_assumptions;
|
expr_ref_vector m_assumptions;
|
||||||
unsigned m_first_assumption;
|
unsigned m_first_assumption;
|
||||||
bool m_is_proxied;
|
bool m_is_proxied;
|
||||||
|
|
||||||
stopwatch m_iuc_sw;
|
stopwatch m_iuc_sw;
|
||||||
stopwatch m_hyp_reduce1_sw;
|
stopwatch m_hyp_reduce1_sw;
|
||||||
|
@ -95,7 +94,7 @@ public:
|
||||||
/* iuc solver specific */
|
/* iuc solver specific */
|
||||||
void get_unsat_core(expr_ref_vector &core) override;
|
void get_unsat_core(expr_ref_vector &core) override;
|
||||||
virtual void get_iuc(expr_ref_vector &core);
|
virtual void get_iuc(expr_ref_vector &core);
|
||||||
void set_split_literals(bool v) {m_split_literals = v;}
|
void set_split_literals(bool v) { m_split_literals = v; }
|
||||||
bool mk_proxies(expr_ref_vector &v, unsigned from = 0);
|
bool mk_proxies(expr_ref_vector &v, unsigned from = 0);
|
||||||
void undo_proxies(expr_ref_vector &v);
|
void undo_proxies(expr_ref_vector &v);
|
||||||
|
|
||||||
|
@ -103,42 +102,40 @@ public:
|
||||||
void pop_bg(unsigned n);
|
void pop_bg(unsigned n);
|
||||||
unsigned get_num_bg();
|
unsigned get_num_bg();
|
||||||
|
|
||||||
void get_full_unsat_core(ptr_vector<expr> &core)
|
void get_full_unsat_core(ptr_vector<expr> &core) { m_solver.get_unsat_core(core); }
|
||||||
{m_solver.get_unsat_core(core);}
|
|
||||||
|
|
||||||
/* solver interface */
|
/* solver interface */
|
||||||
|
|
||||||
solver* translate(ast_manager &m, params_ref const &p) override { return m_solver.translate(m, p);}
|
solver* translate(ast_manager &m, params_ref const &p) override {
|
||||||
void updt_params(params_ref const &p) override {m_solver.updt_params(p);}
|
return m_solver.translate(m, p);
|
||||||
void reset_params(params_ref const &p) override {m_solver.reset_params(p);}
|
}
|
||||||
const params_ref &get_params() const override {return m_solver.get_params();}
|
void updt_params(params_ref const &p) override { m_solver.updt_params(p); }
|
||||||
void push_params() override {m_solver.push_params();}
|
void reset_params(params_ref const &p) override { m_solver.reset_params(p); }
|
||||||
void pop_params() override {m_solver.pop_params();}
|
const params_ref &get_params() const override { return m_solver.get_params(); }
|
||||||
void collect_param_descrs(param_descrs &r) override { m_solver.collect_param_descrs(r);}
|
void push_params() override { m_solver.push_params(); }
|
||||||
void set_produce_models(bool f) override { m_solver.set_produce_models(f);}
|
void pop_params() override { m_solver.pop_params(); }
|
||||||
void assert_expr_core(expr *t) override { m_solver.assert_expr(t);}
|
void collect_param_descrs(param_descrs &r) override { m_solver.collect_param_descrs(r); }
|
||||||
void assert_expr_core2(expr *t, expr *a) override { NOT_IMPLEMENTED_YET();}
|
void set_produce_models(bool f) override { m_solver.set_produce_models(f); }
|
||||||
|
void assert_expr_core(expr *t) override { m_solver.assert_expr(t); }
|
||||||
|
void assert_expr_core2(expr *t, expr *a) override { NOT_IMPLEMENTED_YET(); }
|
||||||
expr_ref_vector cube(expr_ref_vector&, unsigned) override { return expr_ref_vector(m); }
|
expr_ref_vector cube(expr_ref_vector&, unsigned) override { return expr_ref_vector(m); }
|
||||||
|
|
||||||
void push() override;
|
void push() override;
|
||||||
void pop(unsigned n) override;
|
void pop(unsigned n) override;
|
||||||
unsigned get_scope_level() const override
|
unsigned get_scope_level() const override { return m_solver.get_scope_level(); }
|
||||||
{return m_solver.get_scope_level();}
|
|
||||||
|
|
||||||
lbool check_sat(unsigned num_assumptions, expr * const *assumptions) override;
|
lbool check_sat(unsigned num_assumptions, expr * const *assumptions) override;
|
||||||
lbool check_sat_cc(const expr_ref_vector &cube, vector<expr_ref_vector> const & clauses) override;
|
lbool check_sat_cc(const expr_ref_vector &cube, vector<expr_ref_vector> const & clauses) override;
|
||||||
void set_progress_callback(progress_callback *callback) override
|
void set_progress_callback(progress_callback *callback) override {
|
||||||
{m_solver.set_progress_callback(callback);}
|
m_solver.set_progress_callback(callback);
|
||||||
unsigned get_num_assertions() const override
|
}
|
||||||
{return m_solver.get_num_assertions();}
|
unsigned get_num_assertions() const override { return m_solver.get_num_assertions(); }
|
||||||
expr * get_assertion(unsigned idx) const override
|
expr * get_assertion(unsigned idx) const override { return m_solver.get_assertion(idx); }
|
||||||
{return m_solver.get_assertion(idx);}
|
unsigned get_num_assumptions() const override { return m_solver.get_num_assumptions(); }
|
||||||
unsigned get_num_assumptions() const override
|
expr * get_assumption(unsigned idx) const override { return m_solver.get_assumption(idx); }
|
||||||
{return m_solver.get_num_assumptions();}
|
std::ostream &display(std::ostream &out, unsigned n, expr* const* es) const override {
|
||||||
expr * get_assumption(unsigned idx) const override
|
return m_solver.display(out, n, es);
|
||||||
{return m_solver.get_assumption(idx);}
|
}
|
||||||
std::ostream &display(std::ostream &out, unsigned n, expr* const* es) const override
|
|
||||||
{ return m_solver.display(out, n, es); }
|
|
||||||
|
|
||||||
/* check_sat_result interface */
|
/* check_sat_result interface */
|
||||||
|
|
||||||
|
@ -148,13 +145,10 @@ public:
|
||||||
void get_unsat_core(ptr_vector<expr> &r) override;
|
void get_unsat_core(ptr_vector<expr> &r) override;
|
||||||
void get_model_core(model_ref &m) override {m_solver.get_model(m);}
|
void get_model_core(model_ref &m) override {m_solver.get_model(m);}
|
||||||
proof *get_proof() override {return m_solver.get_proof();}
|
proof *get_proof() override {return m_solver.get_proof();}
|
||||||
std::string reason_unknown() const override
|
std::string reason_unknown() const override { return m_solver.reason_unknown(); }
|
||||||
{return m_solver.reason_unknown();}
|
void set_reason_unknown(char const* msg) override { m_solver.set_reason_unknown(msg); }
|
||||||
void set_reason_unknown(char const* msg) override
|
void get_labels(svector<symbol> &r) override { m_solver.get_labels(r); }
|
||||||
{m_solver.set_reason_unknown(msg);}
|
ast_manager& get_manager() const override { return m; }
|
||||||
void get_labels(svector<symbol> &r) override
|
|
||||||
{m_solver.get_labels(r);}
|
|
||||||
ast_manager &get_manager() const override {return m;}
|
|
||||||
|
|
||||||
virtual void refresh();
|
virtual void refresh();
|
||||||
|
|
||||||
|
@ -162,10 +156,10 @@ public:
|
||||||
iuc_solver &m_s;
|
iuc_solver &m_s;
|
||||||
expr_ref_vector &m_v;
|
expr_ref_vector &m_v;
|
||||||
public:
|
public:
|
||||||
scoped_mk_proxy(iuc_solver &s, expr_ref_vector &v) : m_s(s), m_v(v)
|
scoped_mk_proxy(iuc_solver &s, expr_ref_vector &v) : m_s(s), m_v(v) {
|
||||||
{m_s.mk_proxies(m_v);}
|
m_s.mk_proxies(m_v);
|
||||||
~scoped_mk_proxy()
|
}
|
||||||
{m_s.undo_proxies(m_v);}
|
~scoped_mk_proxy() { m_s.undo_proxies(m_v); }
|
||||||
};
|
};
|
||||||
|
|
||||||
class scoped_bg {
|
class scoped_bg {
|
||||||
|
@ -173,8 +167,11 @@ public:
|
||||||
unsigned m_bg_sz;
|
unsigned m_bg_sz;
|
||||||
public:
|
public:
|
||||||
scoped_bg(iuc_solver &s) : m_s(s), m_bg_sz(m_s.get_num_bg()) {}
|
scoped_bg(iuc_solver &s) : m_s(s), m_bg_sz(m_s.get_num_bg()) {}
|
||||||
~scoped_bg()
|
~scoped_bg() {
|
||||||
{if(m_s.get_num_bg() > m_bg_sz) { m_s.pop_bg(m_s.get_num_bg() - m_bg_sz); }}
|
if (m_s.get_num_bg() > m_bg_sz) {
|
||||||
|
m_s.pop_bg(m_s.get_num_bg() - m_bg_sz);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,14 +28,14 @@ model_node::model_node(model_node* parent, class pob *pob):
|
||||||
m_orig_level(m_pob->level()), m_depth(0),
|
m_orig_level(m_pob->level()), m_depth(0),
|
||||||
m_closed(false) {
|
m_closed(false) {
|
||||||
SASSERT(m_pob);
|
SASSERT(m_pob);
|
||||||
if (m_parent) m_parent->add_child(*this);
|
if (m_parent) m_parent->add_child(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void model_node::add_child(model_node &kid) {
|
void model_node::add_child(model_node* kid) {
|
||||||
m_children.push_back(&kid);
|
m_children.push_back(kid);
|
||||||
SASSERT(level() == kid.level() + 1);
|
SASSERT(level() == kid->level() + 1);
|
||||||
SASSERT(level() > 0);
|
SASSERT(level() > 0);
|
||||||
kid.m_depth = m_depth + 1;
|
kid->m_depth = m_depth + 1;
|
||||||
if (is_closed()) set_open();
|
if (is_closed()) set_open();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,7 +109,7 @@ void model_node::insert_after(model_node* n) {
|
||||||
void model_search::reset() {
|
void model_search::reset() {
|
||||||
if (m_root) {
|
if (m_root) {
|
||||||
erase_children(*m_root, false);
|
erase_children(*m_root, false);
|
||||||
remove_node(*m_root, false);
|
remove_node(m_root, false);
|
||||||
dealloc(m_root);
|
dealloc(m_root);
|
||||||
m_root = nullptr;
|
m_root = nullptr;
|
||||||
}
|
}
|
||||||
|
@ -117,24 +117,28 @@ void model_search::reset() {
|
||||||
}
|
}
|
||||||
|
|
||||||
model_node* model_search::pop_front() {
|
model_node* model_search::pop_front() {
|
||||||
if (!m_qhead) return nullptr;
|
|
||||||
model_node *res = m_qhead;
|
model_node *res = m_qhead;
|
||||||
res->detach(m_qhead);
|
if (res) {
|
||||||
|
res->detach(m_qhead);
|
||||||
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
void model_search::add_leaf(model_node& n) {
|
void model_search::add_leaf(model_node* _n) {
|
||||||
|
model_node& n = *_n;
|
||||||
SASSERT(n.children().empty());
|
SASSERT(n.children().empty());
|
||||||
model_nodes ns;
|
model_nodes ns;
|
||||||
model_nodes& nodes = cache(n).insert_if_not_there2(n.post(), ns)->get_data().m_value;
|
model_nodes& nodes = cache(n).insert_if_not_there2(n.post(), ns)->get_data().m_value;
|
||||||
if (nodes.contains(&n)) return;
|
if (nodes.contains(&n)) return;
|
||||||
|
|
||||||
nodes.push_back(&n);
|
nodes.push_back(_n);
|
||||||
if (nodes.size() == 1) {
|
if (nodes.size() == 1) {
|
||||||
SASSERT(n.is_open());
|
SASSERT(n.is_open());
|
||||||
enqueue_leaf(n);
|
enqueue_leaf(n);
|
||||||
}
|
}
|
||||||
else n.set_pre_closed();
|
else {
|
||||||
|
n.set_pre_closed();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void model_search::enqueue_leaf(model_node& n) {
|
void model_search::enqueue_leaf(model_node& n) {
|
||||||
|
@ -162,7 +166,7 @@ void model_search::set_root(model_node* root) {
|
||||||
m_root = root;
|
m_root = root;
|
||||||
SASSERT(m_root);
|
SASSERT(m_root);
|
||||||
SASSERT(m_root->children().empty());
|
SASSERT(m_root->children().empty());
|
||||||
add_leaf(*root);
|
add_leaf(root);
|
||||||
}
|
}
|
||||||
|
|
||||||
void model_search::backtrack_level(bool uses_level, model_node& n) {
|
void model_search::backtrack_level(bool uses_level, model_node& n) {
|
||||||
|
@ -198,15 +202,16 @@ void model_search::erase_children(model_node& n, bool backtrack) {
|
||||||
todo.pop_back();
|
todo.pop_back();
|
||||||
nodes.push_back(m);
|
nodes.push_back(m);
|
||||||
todo.append(m->children());
|
todo.append(m->children());
|
||||||
remove_node(*m, backtrack);
|
remove_node(m, backtrack);
|
||||||
}
|
}
|
||||||
std::for_each(nodes.begin(), nodes.end(), delete_proc<model_node>());
|
std::for_each(nodes.begin(), nodes.end(), delete_proc<model_node>());
|
||||||
}
|
}
|
||||||
|
|
||||||
// removes node from the search tree and from the cache
|
// removes node from the search tree and from the cache
|
||||||
void model_search::remove_node(model_node& n, bool backtrack) {
|
void model_search::remove_node(model_node* _n, bool backtrack) {
|
||||||
|
model_node& n = *_n;
|
||||||
model_nodes& nodes = cache(n).find(n.post());
|
model_nodes& nodes = cache(n).find(n.post());
|
||||||
nodes.erase(&n);
|
nodes.erase(_n);
|
||||||
if (n.in_queue()) n.detach(m_qhead);
|
if (n.in_queue()) n.detach(m_qhead);
|
||||||
// TBD: siblings would also fail if n is not a goal.
|
// TBD: siblings would also fail if n is not a goal.
|
||||||
if (!nodes.empty() && backtrack &&
|
if (!nodes.empty() && backtrack &&
|
||||||
|
@ -241,9 +246,10 @@ lbool context::gpdr_solve_core() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// communicate failure to datalog::context
|
// communicate failure to datalog::context
|
||||||
if (m_context) { m_context->set_status(datalog::BOUNDED); }
|
if (m_context) {
|
||||||
|
m_context->set_status(datalog::BOUNDED);
|
||||||
|
}
|
||||||
return l_undef;
|
return l_undef;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool context::gpdr_check_reachability(unsigned lvl, model_search &ms) {
|
bool context::gpdr_check_reachability(unsigned lvl, model_search &ms) {
|
||||||
|
@ -273,9 +279,8 @@ bool context::gpdr_check_reachability(unsigned lvl, model_search &ms) {
|
||||||
TRACE("spacer_pdr",
|
TRACE("spacer_pdr",
|
||||||
tout << "looking at pob at level " << pob->level() << " "
|
tout << "looking at pob at level " << pob->level() << " "
|
||||||
<< mk_pp(pob->post(), m) << "\n";);
|
<< mk_pp(pob->post(), m) << "\n";);
|
||||||
if (pob == node->pob()) {continue;}
|
if (pob != node->pob())
|
||||||
model_node *kid = alloc(model_node, node, pob);
|
ms.add_leaf(alloc(model_node, node, pob));
|
||||||
ms.add_leaf(*kid);
|
|
||||||
}
|
}
|
||||||
node->check_pre_closed();
|
node->check_pre_closed();
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -36,9 +36,9 @@ class model_node {
|
||||||
bool m_closed; // whether the pob is derivable
|
bool m_closed; // whether the pob is derivable
|
||||||
public:
|
public:
|
||||||
model_node(model_node* parent, pob* pob);
|
model_node(model_node* parent, pob* pob);
|
||||||
void add_child(model_node &kid);
|
void add_child(model_node* kid);
|
||||||
|
|
||||||
expr *post() const {return m_pob->post();}
|
expr *post() const { return m_pob->post(); }
|
||||||
unsigned level() const { return m_pob->level(); }
|
unsigned level() const { return m_pob->level(); }
|
||||||
unsigned orig_level() const { return m_orig_level; }
|
unsigned orig_level() const { return m_orig_level; }
|
||||||
unsigned depth() const { return m_depth; }
|
unsigned depth() const { return m_depth; }
|
||||||
|
@ -57,24 +57,25 @@ public:
|
||||||
bool is_1closed() {
|
bool is_1closed() {
|
||||||
if (is_closed()) return true;
|
if (is_closed()) return true;
|
||||||
if (m_children.empty()) return false;
|
if (m_children.empty()) return false;
|
||||||
for (auto kid : m_children) {if (kid->is_open()) return false;}
|
for (auto kid : m_children)
|
||||||
|
if (kid->is_open()) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void check_pre_closed();
|
void check_pre_closed();
|
||||||
void set_pre_closed() {m_closed = true;}
|
void set_pre_closed() { m_closed = true; }
|
||||||
|
|
||||||
void set_closed() {m_closed = true;}
|
void set_closed() { m_closed = true; }
|
||||||
void set_open();
|
void set_open();
|
||||||
void reset_children() {m_children.reset();}
|
void reset_children() { m_children.reset(); }
|
||||||
|
|
||||||
/// queue
|
/// queue
|
||||||
|
|
||||||
// remove this node from the given queue
|
// remove this node from the given queue
|
||||||
void detach(model_node*& qhead);
|
void detach(model_node*& qhead);
|
||||||
void insert_after(model_node* n);
|
void insert_after(model_node* n);
|
||||||
model_node* next() const {return m_next;}
|
model_node* next() const { return m_next; }
|
||||||
bool in_queue() {return m_next && m_prev;}
|
bool in_queue() { return m_next && m_prev; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class model_search {
|
class model_search {
|
||||||
|
@ -85,8 +86,7 @@ class model_search {
|
||||||
vector<obj_map<expr, model_nodes > > m_cache;
|
vector<obj_map<expr, model_nodes > > m_cache;
|
||||||
obj_map<expr, model_nodes>& cache(model_node const& n);
|
obj_map<expr, model_nodes>& cache(model_node const& n);
|
||||||
void erase_children(model_node& n, bool backtrack);
|
void erase_children(model_node& n, bool backtrack);
|
||||||
void remove_node(model_node& n, bool backtrack);
|
void remove_node(model_node* _n, bool backtrack);
|
||||||
void add_leaf(model_node* n); // add leaf to priority queue.
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
model_search(bool bfs): m_bfs(bfs), m_root(nullptr), m_qhead(nullptr) {}
|
model_search(bool bfs): m_bfs(bfs), m_root(nullptr), m_qhead(nullptr) {}
|
||||||
|
@ -96,7 +96,7 @@ public:
|
||||||
|
|
||||||
void reset();
|
void reset();
|
||||||
model_node* pop_front();
|
model_node* pop_front();
|
||||||
void add_leaf(model_node& n); // add fresh node.
|
void add_leaf(model_node* n); // add fresh node.
|
||||||
model_node& get_root() const { return *m_root; }
|
model_node& get_root() const { return *m_root; }
|
||||||
void backtrack_level(bool uses_level, model_node& n);
|
void backtrack_level(bool uses_level, model_node& n);
|
||||||
void remove_goal(model_node& n);
|
void remove_goal(model_node& n);
|
||||||
|
|
|
@ -132,14 +132,13 @@ void lemma_quantifier_generalizer::find_candidates(expr *e,
|
||||||
<< " in " << mk_pp(e, m) << "\n";);
|
<< " in " << mk_pp(e, m) << "\n";);
|
||||||
extra.push_back(index);
|
extra.push_back(index);
|
||||||
if (m_arith.is_add(index)) {
|
if (m_arith.is_add(index)) {
|
||||||
for (unsigned j = 0, asz = index->get_num_args(); j < asz; j++) {
|
for (expr * arg : *index) {
|
||||||
expr *arg = index->get_arg(j);
|
if (!is_app(arg) || marked_args.is_marked(arg)) {continue;}
|
||||||
if (!is_app(arg) || marked_args.is_marked(arg)) {continue;}
|
marked_args.mark(arg);
|
||||||
marked_args.mark(arg);
|
candidates.push_back (to_app(arg));
|
||||||
candidates.push_back (to_app(arg));
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
std::sort(candidates.c_ptr(), candidates.c_ptr() + candidates.size(),
|
std::sort(candidates.c_ptr(), candidates.c_ptr() + candidates.size(),
|
||||||
index_lt_proc(m));
|
index_lt_proc(m));
|
||||||
|
@ -214,15 +213,15 @@ void lemma_quantifier_generalizer::cleanup(expr_ref_vector &cube, app_ref_vector
|
||||||
bool found = false;
|
bool found = false;
|
||||||
expr_ref_vector kids(m);
|
expr_ref_vector kids(m);
|
||||||
expr_ref_vector kids_bind(m);
|
expr_ref_vector kids_bind(m);
|
||||||
for (unsigned i = 0, sz = a->get_num_args(); i < sz; ++i) {
|
for (expr* arg : *a) {
|
||||||
if (a->get_arg(i) == sk) {
|
if (arg == sk) {
|
||||||
found = true;
|
found = true;
|
||||||
kids.push_back(a->get_arg(i));
|
kids.push_back(arg);
|
||||||
kids_bind.push_back(bind);
|
kids_bind.push_back(bind);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
kids.push_back (times_minus_one(a->get_arg(i), arith));
|
kids.push_back (times_minus_one(arg, arith));
|
||||||
kids_bind.push_back (times_minus_one(a->get_arg(i), arith));
|
kids_bind.push_back (times_minus_one(arg, arith));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!found) continue;
|
if (!found) continue;
|
||||||
|
@ -292,7 +291,7 @@ void lemma_quantifier_generalizer::mk_abs_cube(lemma_ref &lemma, app *term, var
|
||||||
gnd_cube.push_back(lit);
|
gnd_cube.push_back(lit);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
expr *e1, *e2;
|
expr *e1, *e2;
|
||||||
// generalize v=num into v>=num
|
// generalize v=num into v>=num
|
||||||
if (m.is_eq(abs_lit, e1, e2) && (e1 == var || e2 == var)) {
|
if (m.is_eq(abs_lit, e1, e2) && (e1 == var || e2 == var)) {
|
||||||
if (m_arith.is_numeral(e1)) {
|
if (m_arith.is_numeral(e1)) {
|
||||||
|
@ -310,13 +309,13 @@ void lemma_quantifier_generalizer::mk_abs_cube(lemma_ref &lemma, app *term, var
|
||||||
|
|
||||||
if (!lb && is_lb(var, abs_lit)) {
|
if (!lb && is_lb(var, abs_lit)) {
|
||||||
lb = abs_lit;
|
lb = abs_lit;
|
||||||
}
|
}
|
||||||
else if (!ub && is_ub(var, abs_lit)) {
|
else if (!ub && is_ub(var, abs_lit)) {
|
||||||
ub = abs_lit;
|
ub = abs_lit;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// -- returns true if e is an upper bound for var
|
// -- returns true if e is an upper bound for var
|
||||||
bool lemma_quantifier_generalizer::is_ub(var *var, expr *e) {
|
bool lemma_quantifier_generalizer::is_ub(var *var, expr *e) {
|
||||||
|
@ -348,38 +347,34 @@ bool lemma_quantifier_generalizer::is_ub(var *var, expr *e) {
|
||||||
if ((m_arith.is_le(e, e1, e2) || m_arith.is_lt(e, e1, e2)) &&
|
if ((m_arith.is_le(e, e1, e2) || m_arith.is_lt(e, e1, e2)) &&
|
||||||
m_arith.is_add(e1)) {
|
m_arith.is_add(e1)) {
|
||||||
app *a = to_app(e1);
|
app *a = to_app(e1);
|
||||||
for (unsigned i = 0, sz = a->get_num_args(); i < sz; ++i) {
|
for (expr* arg : *a) {
|
||||||
expr *arg = a->get_arg(i);
|
if (arg == var) return true;
|
||||||
if (arg == var) {return true;}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// t1 <= t2 + -1*var
|
// t1 <= t2 + -1*var
|
||||||
if ((m_arith.is_le(e, e1, e2) || m_arith.is_lt(e, e1, e2)) &&
|
if ((m_arith.is_le(e, e1, e2) || m_arith.is_lt(e, e1, e2)) &&
|
||||||
m_arith.is_add(e2)) {
|
m_arith.is_add(e2)) {
|
||||||
app *a = to_app(e2);
|
app *a = to_app(e2);
|
||||||
for (unsigned i = 0, sz = a->get_num_args(); i < sz; ++i) {
|
for (expr* arg : *a) {
|
||||||
expr *arg = a->get_arg(i);
|
|
||||||
if (m_arith.is_times_minus_one(arg, arg) && arg == var)
|
if (m_arith.is_times_minus_one(arg, arg) && arg == var)
|
||||||
{return true;}
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// t1 >= t2 + var
|
// t1 >= t2 + var
|
||||||
if ((m_arith.is_ge(e, e1, e2) || m_arith.is_gt(e, e1, e2)) &&
|
if ((m_arith.is_ge(e, e1, e2) || m_arith.is_gt(e, e1, e2)) &&
|
||||||
m_arith.is_add(e2)) {
|
m_arith.is_add(e2)) {
|
||||||
app *a = to_app(e2);
|
app *a = to_app(e2);
|
||||||
for (unsigned i = 0, sz = a->get_num_args(); i < sz; ++i) {
|
for (expr * arg : *a) {
|
||||||
expr *arg = a->get_arg(i);
|
if (arg == var) return true;
|
||||||
if (arg == var) {return true;}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// -1*var + t1 >= t2
|
// -1*var + t1 >= t2
|
||||||
if ((m_arith.is_ge(e, e1, e2) || m_arith.is_gt(e, e1, e2)) &&
|
if ((m_arith.is_ge(e, e1, e2) || m_arith.is_gt(e, e1, e2)) &&
|
||||||
m_arith.is_add(e1)) {
|
m_arith.is_add(e1)) {
|
||||||
app *a = to_app(e1);
|
app *a = to_app(e1);
|
||||||
for (unsigned i = 0, sz = a->get_num_args(); i < sz; ++i) {
|
for (expr * arg : *a) {
|
||||||
expr *arg = a->get_arg(i);
|
|
||||||
if (m_arith.is_times_minus_one(arg, arg) && arg == var)
|
if (m_arith.is_times_minus_one(arg, arg) && arg == var)
|
||||||
{return true;}
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -414,38 +409,34 @@ bool lemma_quantifier_generalizer::is_lb(var *var, expr *e) {
|
||||||
if ((m_arith.is_ge(e, e1, e2) || m_arith.is_gt(e, e1, e2)) &&
|
if ((m_arith.is_ge(e, e1, e2) || m_arith.is_gt(e, e1, e2)) &&
|
||||||
m_arith.is_add(e1)) {
|
m_arith.is_add(e1)) {
|
||||||
app *a = to_app(e1);
|
app *a = to_app(e1);
|
||||||
for (unsigned i = 0, sz = a->get_num_args(); i < sz; ++i) {
|
for (expr * arg : *a) {
|
||||||
expr *arg = a->get_arg(i);
|
if (arg == var) return true;
|
||||||
if (arg == var) {return true;}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// t1 >= t2 + -1*var
|
// t1 >= t2 + -1*var
|
||||||
if ((m_arith.is_ge(e, e1, e2) || m_arith.is_gt(e, e1, e2)) &&
|
if ((m_arith.is_ge(e, e1, e2) || m_arith.is_gt(e, e1, e2)) &&
|
||||||
m_arith.is_add(e2)) {
|
m_arith.is_add(e2)) {
|
||||||
app *a = to_app(e2);
|
app *a = to_app(e2);
|
||||||
for (unsigned i = 0, sz = a->get_num_args(); i < sz; ++i) {
|
for (expr * arg : *a) {
|
||||||
expr *arg = a->get_arg(i);
|
|
||||||
if (m_arith.is_times_minus_one(arg, arg) && arg == var)
|
if (m_arith.is_times_minus_one(arg, arg) && arg == var)
|
||||||
{return true;}
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// t1 <= t2 + var
|
// t1 <= t2 + var
|
||||||
if ((m_arith.is_le(e, e1, e2) || m_arith.is_lt(e, e1, e2)) &&
|
if ((m_arith.is_le(e, e1, e2) || m_arith.is_lt(e, e1, e2)) &&
|
||||||
m_arith.is_add(e2)) {
|
m_arith.is_add(e2)) {
|
||||||
app *a = to_app(e2);
|
app *a = to_app(e2);
|
||||||
for (unsigned i = 0, sz = a->get_num_args(); i < sz; ++i) {
|
for (expr * arg : *a) {
|
||||||
expr *arg = a->get_arg(i);
|
if (arg == var) return true;
|
||||||
if (arg == var) {return true;}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// -1*var + t1 <= t2
|
// -1*var + t1 <= t2
|
||||||
if ((m_arith.is_le(e, e1, e2) || m_arith.is_lt(e, e1, e2)) &&
|
if ((m_arith.is_le(e, e1, e2) || m_arith.is_lt(e, e1, e2)) &&
|
||||||
m_arith.is_add(e1)) {
|
m_arith.is_add(e1)) {
|
||||||
app *a = to_app(e1);
|
app *a = to_app(e1);
|
||||||
for (unsigned i = 0, sz = a->get_num_args(); i < sz; ++i) {
|
for (expr * arg : *a) {
|
||||||
expr *arg = a->get_arg(i);
|
|
||||||
if (m_arith.is_times_minus_one(arg, arg) && arg == var)
|
if (m_arith.is_times_minus_one(arg, arg) && arg == var)
|
||||||
{return true;}
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -470,22 +461,22 @@ bool lemma_quantifier_generalizer::generalize (lemma_ref &lemma, app *term) {
|
||||||
tout << "lb = ";
|
tout << "lb = ";
|
||||||
if (lb) tout << mk_pp(lb, m); else tout << "none";
|
if (lb) tout << mk_pp(lb, m); else tout << "none";
|
||||||
tout << "\n";
|
tout << "\n";
|
||||||
|
|
||||||
tout << "ub = ";
|
tout << "ub = ";
|
||||||
if (ub) tout << mk_pp(ub, m); else tout << "none";
|
if (ub) tout << mk_pp(ub, m); else tout << "none";
|
||||||
tout << "\n";);
|
tout << "\n";);
|
||||||
|
|
||||||
if (!lb && !ub) {return false;}
|
if (!lb && !ub)
|
||||||
|
return false;
|
||||||
|
|
||||||
// -- guess lower or upper bound if missing
|
// -- guess lower or upper bound if missing
|
||||||
if (!lb) {
|
if (!lb) {
|
||||||
abs_cube.push_back (m_arith.mk_ge (var, term));
|
abs_cube.push_back (m_arith.mk_ge (var, term));
|
||||||
lb = abs_cube.back();
|
lb = abs_cube.back();
|
||||||
}
|
}
|
||||||
if (!ub) {
|
if (!ub) {
|
||||||
abs_cube.push_back (m_arith.mk_lt(var, term));
|
abs_cube.push_back (m_arith.mk_lt(var, term));
|
||||||
ub = abs_cube.back();
|
ub = abs_cube.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
rational init;
|
rational init;
|
||||||
expr_ref constant(m);
|
expr_ref constant(m);
|
||||||
|
@ -511,7 +502,7 @@ bool lemma_quantifier_generalizer::generalize (lemma_ref &lemma, app *term) {
|
||||||
flatten_and(gnd, gnd_cube);
|
flatten_and(gnd, gnd_cube);
|
||||||
|
|
||||||
TRACE("spacer_qgen",
|
TRACE("spacer_qgen",
|
||||||
tout << "New CUBE is: " << mk_pp(mk_and(gnd_cube),m) << "\n";);
|
tout << "New CUBE is: " << gnd_cube << "\n";);
|
||||||
|
|
||||||
// check if the result is a true lemma
|
// check if the result is a true lemma
|
||||||
unsigned uses_level = 0;
|
unsigned uses_level = 0;
|
||||||
|
@ -519,8 +510,8 @@ bool lemma_quantifier_generalizer::generalize (lemma_ref &lemma, app *term) {
|
||||||
if (pt.check_inductive(lemma->level(), gnd_cube, uses_level, lemma->weakness())) {
|
if (pt.check_inductive(lemma->level(), gnd_cube, uses_level, lemma->weakness())) {
|
||||||
TRACE("spacer_qgen",
|
TRACE("spacer_qgen",
|
||||||
tout << "Quantifier Generalization Succeeded!\n"
|
tout << "Quantifier Generalization Succeeded!\n"
|
||||||
<< "New CUBE is: " << mk_pp(mk_and(gnd_cube),m) << "\n";);
|
<< "New CUBE is: " << gnd_cube << "\n";);
|
||||||
SASSERT(zks.size() >= m_offset);
|
SASSERT(zks.size() >= static_cast<unsigned>(m_offset));
|
||||||
|
|
||||||
// lift quantified variables to top of select
|
// lift quantified variables to top of select
|
||||||
expr_ref ext_bind(m);
|
expr_ref ext_bind(m);
|
||||||
|
@ -541,7 +532,7 @@ bool lemma_quantifier_generalizer::generalize (lemma_ref &lemma, app *term) {
|
||||||
}
|
}
|
||||||
|
|
||||||
lemma->update_cube(lemma->get_pob(), gnd_cube);
|
lemma->update_cube(lemma->get_pob(), gnd_cube);
|
||||||
lemma->set_level(uses_level);
|
lemma->set_level(uses_level);
|
||||||
|
|
||||||
SASSERT(var->get_idx() < zks.size());
|
SASSERT(var->get_idx() < zks.size());
|
||||||
SASSERT(is_app(ext_bind));
|
SASSERT(is_app(ext_bind));
|
||||||
|
@ -570,8 +561,7 @@ bool lemma_quantifier_generalizer::find_stride(expr_ref_vector &c, expr_ref &pat
|
||||||
if (is_var(p_index)) return false;
|
if (is_var(p_index)) return false;
|
||||||
|
|
||||||
std::vector<unsigned> instances;
|
std::vector<unsigned> instances;
|
||||||
for (unsigned i=0; i < c.size(); i++) {
|
for (expr* lit : c) {
|
||||||
expr *lit = c.get(i);
|
|
||||||
|
|
||||||
if (!contains_selects(lit, m))
|
if (!contains_selects(lit, m))
|
||||||
continue;
|
continue;
|
||||||
|
@ -589,16 +579,17 @@ bool lemma_quantifier_generalizer::find_stride(expr_ref_vector &c, expr_ref &pat
|
||||||
unsigned matched = 0;
|
unsigned matched = 0;
|
||||||
for (unsigned p=0; p < size; p++) {
|
for (unsigned p=0; p < size; p++) {
|
||||||
expr *arg = p_index->get_arg(p);
|
expr *arg = p_index->get_arg(p);
|
||||||
if (is_var(arg))
|
if (is_var(arg)) {
|
||||||
{
|
|
||||||
rational val;
|
rational val;
|
||||||
if (p < candidate->get_num_args() && m_arith.is_numeral(candidate->get_arg(p), val)) {
|
if (p < candidate->get_num_args() &&
|
||||||
|
m_arith.is_numeral(candidate->get_arg(p), val) &&
|
||||||
|
val.is_unsigned()) {
|
||||||
instances.push_back(val.get_unsigned());
|
instances.push_back(val.get_unsigned());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
for (unsigned j=0; j < candidate->get_num_args(); j++) {
|
for (expr* cand : *candidate) {
|
||||||
if (candidate->get_arg(j) == arg) {
|
if (cand == arg) {
|
||||||
matched++;
|
matched++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,46 +17,36 @@ Revision History:
|
||||||
--*/
|
--*/
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
|
#include "ast/for_each_expr.h"
|
||||||
|
#include "ast/proofs/proof_utils.h"
|
||||||
#include "muz/spacer/spacer_unsat_core_learner.h"
|
#include "muz/spacer/spacer_unsat_core_learner.h"
|
||||||
#include "muz/spacer/spacer_unsat_core_plugin.h"
|
#include "muz/spacer/spacer_unsat_core_plugin.h"
|
||||||
#include "muz/spacer/spacer_iuc_proof.h"
|
#include "muz/spacer/spacer_iuc_proof.h"
|
||||||
#include "ast/for_each_expr.h"
|
|
||||||
|
|
||||||
#include "ast/proofs/proof_utils.h"
|
|
||||||
#include "muz/spacer/spacer_util.h"
|
#include "muz/spacer/spacer_util.h"
|
||||||
|
|
||||||
|
|
||||||
namespace spacer
|
namespace spacer {
|
||||||
{
|
|
||||||
|
|
||||||
unsat_core_learner::~unsat_core_learner()
|
unsat_core_learner::~unsat_core_learner() {
|
||||||
{
|
|
||||||
std::for_each(m_plugins.begin(), m_plugins.end(), delete_proc<unsat_core_plugin>());
|
std::for_each(m_plugins.begin(), m_plugins.end(), delete_proc<unsat_core_plugin>());
|
||||||
}
|
}
|
||||||
|
|
||||||
void unsat_core_learner::register_plugin(unsat_core_plugin* plugin)
|
void unsat_core_learner::register_plugin(unsat_core_plugin* plugin) {
|
||||||
{
|
|
||||||
m_plugins.push_back(plugin);
|
m_plugins.push_back(plugin);
|
||||||
}
|
}
|
||||||
|
|
||||||
void unsat_core_learner::compute_unsat_core(expr_ref_vector& unsat_core)
|
void unsat_core_learner::compute_unsat_core(expr_ref_vector& unsat_core) {
|
||||||
{
|
|
||||||
// traverse proof
|
// traverse proof
|
||||||
proof_post_order it(m_pr.get(), m);
|
proof_post_order it(m_pr.get(), m);
|
||||||
while (it.hasNext())
|
while (it.hasNext()) {
|
||||||
{
|
|
||||||
proof* currentNode = it.next();
|
proof* currentNode = it.next();
|
||||||
|
|
||||||
if (m.get_num_parents(currentNode) > 0)
|
if (m.get_num_parents(currentNode) > 0) {
|
||||||
{
|
|
||||||
bool need_to_mark_closed = true;
|
bool need_to_mark_closed = true;
|
||||||
|
|
||||||
for (unsigned i = 0; i < m.get_num_parents(currentNode); ++i)
|
for (unsigned i = 0; i < m.get_num_parents(currentNode); ++i) {
|
||||||
{
|
proof* premise = m.get_parent(currentNode, i);
|
||||||
SASSERT(m.is_proof(currentNode->get_arg(i)));
|
need_to_mark_closed &= (!m_pr.is_b_marked(premise) || m_closed.is_marked(premise));
|
||||||
proof* premise = to_app(currentNode->get_arg(i));
|
|
||||||
|
|
||||||
need_to_mark_closed = need_to_mark_closed && (!m_pr.is_b_marked(premise) || m_closed.is_marked(premise));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// save result
|
// save result
|
||||||
|
@ -65,8 +55,9 @@ void unsat_core_learner::compute_unsat_core(expr_ref_vector& unsat_core)
|
||||||
|
|
||||||
// we have now collected all necessary information, so we can visit the node
|
// we have now collected all necessary information, so we can visit the node
|
||||||
// if the node mixes A-reasoning and B-reasoning and contains non-closed premises
|
// if the node mixes A-reasoning and B-reasoning and contains non-closed premises
|
||||||
if (m_pr.is_a_marked(currentNode) && m_pr.is_b_marked(currentNode) && !m_closed.is_marked(currentNode))
|
if (m_pr.is_a_marked(currentNode) &&
|
||||||
{
|
m_pr.is_b_marked(currentNode) &&
|
||||||
|
!m_closed.is_marked(currentNode)) {
|
||||||
compute_partial_core(currentNode); // then we need to compute a partial core
|
compute_partial_core(currentNode); // then we need to compute a partial core
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -77,46 +68,38 @@ void unsat_core_learner::compute_unsat_core(expr_ref_vector& unsat_core)
|
||||||
// TODO: remove duplicates from unsat core?
|
// TODO: remove duplicates from unsat core?
|
||||||
|
|
||||||
// move all lemmas into vector
|
// move all lemmas into vector
|
||||||
for (expr* const* it = m_unsat_core.begin(); it != m_unsat_core.end(); ++it)
|
for (expr* e : m_unsat_core) {
|
||||||
{
|
unsat_core.push_back(e);
|
||||||
unsat_core.push_back(*it);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void unsat_core_learner::compute_partial_core(proof* step)
|
void unsat_core_learner::compute_partial_core(proof* step) {
|
||||||
{
|
for (unsat_core_plugin* plugin : m_plugins) {
|
||||||
for (unsat_core_plugin** it=m_plugins.begin(), **end = m_plugins.end (); it != end && !m_closed.is_marked(step); ++it)
|
if (m_closed.is_marked(step)) break;
|
||||||
{
|
|
||||||
unsat_core_plugin* plugin = *it;
|
|
||||||
plugin->compute_partial_core(step);
|
plugin->compute_partial_core(step);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void unsat_core_learner::finalize()
|
void unsat_core_learner::finalize() {
|
||||||
{
|
for (unsat_core_plugin* plugin : m_plugins) {
|
||||||
for (unsat_core_plugin** it=m_plugins.begin(); it != m_plugins.end(); ++it)
|
|
||||||
{
|
|
||||||
unsat_core_plugin* plugin = *it;
|
|
||||||
plugin->finalize();
|
plugin->finalize();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool unsat_core_learner::is_closed(proof*p)
|
bool unsat_core_learner::is_closed(proof* p) {
|
||||||
{
|
|
||||||
return m_closed.is_marked(p);
|
return m_closed.is_marked(p);
|
||||||
}
|
}
|
||||||
void unsat_core_learner::set_closed(proof* p, bool value)
|
|
||||||
{
|
void unsat_core_learner::set_closed(proof* p, bool value) {
|
||||||
m_closed.mark(p, value);
|
m_closed.mark(p, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool unsat_core_learner::is_b_open(proof *p)
|
bool unsat_core_learner::is_b_open(proof *p) {
|
||||||
{
|
return m_pr.is_b_marked(p) && !is_closed (p);
|
||||||
return m_pr.is_b_marked(p) && !is_closed (p);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void unsat_core_learner::add_lemma_to_core(expr* lemma)
|
void unsat_core_learner::add_lemma_to_core(expr* lemma) {
|
||||||
{
|
|
||||||
m_unsat_core.push_back(lemma);
|
m_unsat_core.push_back(lemma);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,8 @@ Module Name:
|
||||||
spacer_unsat_core_learner.h
|
spacer_unsat_core_learner.h
|
||||||
|
|
||||||
Abstract:
|
Abstract:
|
||||||
itp cores
|
|
||||||
|
itp cores
|
||||||
|
|
||||||
Author:
|
Author:
|
||||||
Bernhard Gleiss
|
Bernhard Gleiss
|
||||||
|
@ -27,8 +28,7 @@ namespace spacer {
|
||||||
|
|
||||||
class unsat_core_plugin;
|
class unsat_core_plugin;
|
||||||
class iuc_proof;
|
class iuc_proof;
|
||||||
class unsat_core_learner
|
class unsat_core_learner {
|
||||||
{
|
|
||||||
typedef obj_hashtable<expr> expr_set;
|
typedef obj_hashtable<expr> expr_set;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -37,7 +37,7 @@ namespace spacer {
|
||||||
virtual ~unsat_core_learner();
|
virtual ~unsat_core_learner();
|
||||||
|
|
||||||
ast_manager& m;
|
ast_manager& m;
|
||||||
iuc_proof& m_pr;
|
iuc_proof& m_pr;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* register a plugin for computation of partial unsat cores
|
* register a plugin for computation of partial unsat cores
|
||||||
|
@ -56,7 +56,6 @@ namespace spacer {
|
||||||
* - a node is closed, iff it has already been interpolated, i.e. its contribution is
|
* - a node is closed, iff it has already been interpolated, i.e. its contribution is
|
||||||
* already covered by the unsat-core.
|
* already covered by the unsat-core.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
bool is_closed(proof* p);
|
bool is_closed(proof* p);
|
||||||
void set_closed(proof* p, bool value);
|
void set_closed(proof* p, bool value);
|
||||||
|
|
||||||
|
@ -67,14 +66,14 @@ namespace spacer {
|
||||||
*/
|
*/
|
||||||
void add_lemma_to_core(expr* lemma);
|
void add_lemma_to_core(expr* lemma);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ptr_vector<unsat_core_plugin> m_plugins;
|
ptr_vector<unsat_core_plugin> m_plugins;
|
||||||
ast_mark m_closed;
|
ast_mark m_closed;
|
||||||
|
|
||||||
// collects the lemmas of the unsat-core
|
/*
|
||||||
// will at the end be inserted into unsat_core.
|
* collects the lemmas of the unsat-core
|
||||||
|
* will at the end be inserted into unsat_core.
|
||||||
|
*/
|
||||||
expr_ref_vector m_unsat_core;
|
expr_ref_vector m_unsat_core;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -86,9 +85,7 @@ namespace spacer {
|
||||||
* finalize computation of unsat-core
|
* finalize computation of unsat-core
|
||||||
*/
|
*/
|
||||||
void finalize();
|
void finalize();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -6,7 +6,7 @@ Module Name:
|
||||||
spacer_unsat_core_plugin.cpp
|
spacer_unsat_core_plugin.cpp
|
||||||
|
|
||||||
Abstract:
|
Abstract:
|
||||||
plugin for itp cores
|
plugin for itp cores
|
||||||
|
|
||||||
Author:
|
Author:
|
||||||
Bernhard Gleiss
|
Bernhard Gleiss
|
||||||
|
@ -32,259 +32,213 @@ Revision History:
|
||||||
#include "muz/spacer/spacer_unsat_core_learner.h"
|
#include "muz/spacer/spacer_unsat_core_learner.h"
|
||||||
#include "muz/spacer/spacer_iuc_proof.h"
|
#include "muz/spacer/spacer_iuc_proof.h"
|
||||||
|
|
||||||
namespace spacer
|
namespace spacer {
|
||||||
{
|
|
||||||
|
unsat_core_plugin::unsat_core_plugin(unsat_core_learner& learner):
|
||||||
|
m(learner.m), m_learner(learner) {};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void unsat_core_plugin_lemma::compute_partial_core(proof* step)
|
void unsat_core_plugin_lemma::compute_partial_core(proof* step) {
|
||||||
{
|
SASSERT(m_learner.m_pr.is_a_marked(step));
|
||||||
SASSERT(m_learner.m_pr.is_a_marked(step));
|
SASSERT(m_learner.m_pr.is_b_marked(step));
|
||||||
SASSERT(m_learner.m_pr.is_b_marked(step));
|
|
||||||
|
for (proof* premise : m.get_parents(step)) {
|
||||||
for (unsigned i = 0; i < m_learner.m.get_num_parents(step); ++i)
|
|
||||||
{
|
if (m_learner.is_b_open (premise)) {
|
||||||
SASSERT(m_learner.m.is_proof(step->get_arg(i)));
|
// by IH, premises that are AB marked are already closed
|
||||||
proof* premise = to_app(step->get_arg(i));
|
|
||||||
|
|
||||||
if (m_learner.is_b_open (premise))
|
|
||||||
{
|
|
||||||
// by IH, premises that are AB marked are already closed
|
|
||||||
SASSERT(!m_learner.m_pr.is_a_marked(premise));
|
|
||||||
add_lowest_split_to_core(premise);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_learner.set_closed(step, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void unsat_core_plugin_lemma::add_lowest_split_to_core(proof* step) const
|
|
||||||
{
|
|
||||||
SASSERT(m_learner.is_b_open(step));
|
|
||||||
ast_manager &m = m_learner.m;
|
|
||||||
|
|
||||||
ptr_vector<proof> todo;
|
|
||||||
todo.push_back(step);
|
|
||||||
|
|
||||||
while (!todo.empty())
|
|
||||||
{
|
|
||||||
proof* pf = todo.back();
|
|
||||||
todo.pop_back();
|
|
||||||
|
|
||||||
// if current step hasn't been processed,
|
|
||||||
if (!m_learner.is_closed(pf))
|
|
||||||
{
|
|
||||||
m_learner.set_closed(pf, true);
|
|
||||||
// the step is b-marked and not closed.
|
|
||||||
// by I.H. the step must be already visited
|
|
||||||
// so if it is also a-marked, it must be closed
|
|
||||||
SASSERT(m_learner.m_pr.is_b_marked(pf));
|
|
||||||
SASSERT(!m_learner.m_pr.is_a_marked(pf));
|
|
||||||
|
|
||||||
// the current step needs to be interpolated:
|
|
||||||
expr* fact = m_learner.m.get_fact(pf);
|
|
||||||
// if we trust the current step and we are able to use it
|
|
||||||
if (m_learner.m_pr.is_b_pure (pf) &&
|
|
||||||
(m.is_asserted(pf) || is_literal(m, fact)))
|
|
||||||
{
|
|
||||||
// just add it to the core
|
|
||||||
m_learner.add_lemma_to_core(fact);
|
|
||||||
}
|
|
||||||
// otherwise recurse on premises
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (unsigned i = 0, sz = m_learner.m.get_num_parents(pf);
|
|
||||||
i < sz; ++i)
|
|
||||||
{
|
|
||||||
SASSERT(m_learner.m.is_proof(pf->get_arg(i)));
|
|
||||||
proof* premise = m.get_parent (pf, i);
|
|
||||||
if (m_learner.is_b_open(premise)) {
|
|
||||||
todo.push_back(premise);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void unsat_core_plugin_farkas_lemma::compute_partial_core(proof* step)
|
|
||||||
{
|
|
||||||
ast_manager &m = m_learner.m;
|
|
||||||
SASSERT(m_learner.m_pr.is_a_marked(step));
|
|
||||||
SASSERT(m_learner.m_pr.is_b_marked(step));
|
|
||||||
// XXX this assertion should be true so there is no need to check for it
|
|
||||||
SASSERT (!m_learner.is_closed (step));
|
|
||||||
func_decl* d = step->get_decl();
|
|
||||||
symbol sym;
|
|
||||||
if(!m_learner.is_closed(step) && // if step is not already interpolated
|
|
||||||
step->get_decl_kind() == PR_TH_LEMMA && // and step is a Farkas lemma
|
|
||||||
d->get_num_parameters() >= 2 && // the Farkas coefficients are saved in the parameters of step
|
|
||||||
d->get_parameter(0).is_symbol(sym) && sym == "arith" && // the first two parameters are "arith", "farkas",
|
|
||||||
d->get_parameter(1).is_symbol(sym) && sym == "farkas" &&
|
|
||||||
d->get_num_parameters() >= m_learner.m.get_num_parents(step) + 2) // the following parameters are the Farkas coefficients
|
|
||||||
{
|
|
||||||
SASSERT(m_learner.m.has_fact(step));
|
|
||||||
|
|
||||||
ptr_vector<app> literals;
|
|
||||||
vector<rational> coefficients;
|
|
||||||
|
|
||||||
/* The farkas lemma represents a subproof starting from premise(-set)s A, BNP and BP(ure) and
|
|
||||||
* ending in a disjunction D. We need to compute the contribution of BP, i.e. a formula, which
|
|
||||||
* is entailed by BP and together with A and BNP entails D.
|
|
||||||
*
|
|
||||||
* Let Fark(F) be the farkas coefficient for F. We can use the fact that
|
|
||||||
* (A*Fark(A) + BNP*Fark(BNP) + BP*Fark(BP) + (neg D)*Fark(D)) => false. (E1)
|
|
||||||
* We further have that A+B => C implies (A \land B) => C. (E2)
|
|
||||||
*
|
|
||||||
* Alternative 1:
|
|
||||||
* From (E1) immediately get that BP*Fark(BP) is a solution.
|
|
||||||
*
|
|
||||||
* Alternative 2:
|
|
||||||
* We can rewrite (E2) to rewrite (E1) to
|
|
||||||
* (BP*Fark(BP)) => (neg(A*Fark(A) + BNP*Fark(BNP) + (neg D)*Fark(D))) (E3)
|
|
||||||
* and since we can derive (A*Fark(A) + BNP*Fark(BNP) + (neg D)*Fark(D)) from
|
|
||||||
* A, BNP and D, we also know that it is inconsisent. Therefore
|
|
||||||
* neg(A*Fark(A) + BNP*Fark(BNP) + (neg D)*Fark(D)) is a solution.
|
|
||||||
*
|
|
||||||
* Finally we also need the following workaround:
|
|
||||||
* 1) Although we know from theory, that the Farkas coefficients are always nonnegative,
|
|
||||||
* the Farkas coefficients provided by arith_core are sometimes negative (must be a bug)
|
|
||||||
* as workaround we take the absolute value of the provided coefficients.
|
|
||||||
*/
|
|
||||||
parameter const* params = d->get_parameters() + 2; // point to the first Farkas coefficient
|
|
||||||
|
|
||||||
STRACE("spacer.farkas",
|
|
||||||
verbose_stream() << "Farkas input: "<< "\n";
|
|
||||||
for (unsigned i = 0; i < m_learner.m.get_num_parents(step); ++i)
|
|
||||||
{
|
|
||||||
SASSERT(m_learner.m.is_proof(step->get_arg(i)));
|
|
||||||
proof *prem = m.get_parent (step, i);
|
|
||||||
|
|
||||||
rational coef;
|
|
||||||
VERIFY(params[i].is_rational(coef));
|
|
||||||
|
|
||||||
bool b_pure = m_learner.m_pr.is_b_pure (prem);
|
|
||||||
verbose_stream() << (b_pure?"B":"A") << " " << coef << " " << mk_pp(m_learner.m.get_fact(prem), m_learner.m) << "\n";
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
bool can_be_closed = true;
|
|
||||||
|
|
||||||
for(unsigned i = 0; i < m.get_num_parents(step); ++i)
|
|
||||||
{
|
|
||||||
SASSERT(m_learner.m.is_proof(step->get_arg(i)));
|
|
||||||
proof * premise = m.get_parent (step, i);
|
|
||||||
|
|
||||||
if (m_learner.is_b_open (premise))
|
|
||||||
{
|
|
||||||
SASSERT(!m_learner.m_pr.is_a_marked(premise));
|
SASSERT(!m_learner.m_pr.is_a_marked(premise));
|
||||||
|
add_lowest_split_to_core(premise);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_learner.set_closed(step, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void unsat_core_plugin_lemma::add_lowest_split_to_core(proof* step) const
|
||||||
|
{
|
||||||
|
SASSERT(m_learner.is_b_open(step));
|
||||||
|
|
||||||
|
ptr_buffer<proof> todo;
|
||||||
|
todo.push_back(step);
|
||||||
|
|
||||||
|
while (!todo.empty()) {
|
||||||
|
proof* pf = todo.back();
|
||||||
|
todo.pop_back();
|
||||||
|
|
||||||
|
// if current step hasn't been processed,
|
||||||
|
if (!m_learner.is_closed(pf)) {
|
||||||
|
m_learner.set_closed(pf, true);
|
||||||
|
// the step is b-marked and not closed.
|
||||||
|
// by I.H. the step must be already visited
|
||||||
|
// so if it is also a-marked, it must be closed
|
||||||
|
SASSERT(m_learner.m_pr.is_b_marked(pf));
|
||||||
|
SASSERT(!m_learner.m_pr.is_a_marked(pf));
|
||||||
|
|
||||||
|
// the current step needs to be interpolated:
|
||||||
|
expr* fact = m.get_fact(pf);
|
||||||
|
// if we trust the current step and we are able to use it
|
||||||
|
if (m_learner.m_pr.is_b_pure (pf) &&
|
||||||
|
(m.is_asserted(pf) || is_literal(m, fact))) {
|
||||||
|
// just add it to the core
|
||||||
|
m_learner.add_lemma_to_core(fact);
|
||||||
|
}
|
||||||
|
// otherwise recurse on premises
|
||||||
|
else {
|
||||||
|
for (proof* premise : m.get_parents(pf))
|
||||||
|
if (m_learner.is_b_open(premise))
|
||||||
|
todo.push_back(premise);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (m_learner.m_pr.is_b_pure (step))
|
|
||||||
{
|
void unsat_core_plugin_farkas_lemma::compute_partial_core(proof* step)
|
||||||
if (!m_use_constant_from_a)
|
{
|
||||||
{
|
SASSERT(m_learner.m_pr.is_a_marked(step));
|
||||||
rational coefficient;
|
SASSERT(m_learner.m_pr.is_b_marked(step));
|
||||||
VERIFY(params[i].is_rational(coefficient));
|
// XXX this assertion should be true so there is no need to check for it
|
||||||
literals.push_back(to_app(m_learner.m.get_fact(premise)));
|
SASSERT (!m_learner.is_closed (step));
|
||||||
coefficients.push_back(abs(coefficient));
|
func_decl* d = step->get_decl();
|
||||||
|
symbol sym;
|
||||||
|
if (!m_learner.is_closed(step) && // if step is not already interpolated
|
||||||
|
step->get_decl_kind() == PR_TH_LEMMA && // and step is a Farkas lemma
|
||||||
|
d->get_num_parameters() >= 2 && // the Farkas coefficients are saved in the parameters of step
|
||||||
|
d->get_parameter(0).is_symbol(sym) && sym == "arith" && // the first two parameters are "arith", "farkas",
|
||||||
|
d->get_parameter(1).is_symbol(sym) && sym == "farkas" &&
|
||||||
|
d->get_num_parameters() >= m.get_num_parents(step) + 2) { // the following parameters are the Farkas coefficients
|
||||||
|
|
||||||
|
SASSERT(m.has_fact(step));
|
||||||
|
|
||||||
|
coeff_lits_t coeff_lits;
|
||||||
|
expr_ref_vector pinned(m);
|
||||||
|
|
||||||
|
/* The farkas lemma represents a subproof starting from premise(-set)s A, BNP and BP(ure) and
|
||||||
|
* ending in a disjunction D. We need to compute the contribution of BP, i.e. a formula, which
|
||||||
|
* is entailed by BP and together with A and BNP entails D.
|
||||||
|
*
|
||||||
|
* Let Fark(F) be the farkas coefficient for F. We can use the fact that
|
||||||
|
* (A*Fark(A) + BNP*Fark(BNP) + BP*Fark(BP) + (neg D)*Fark(D)) => false. (E1)
|
||||||
|
* We further have that A+B => C implies (A \land B) => C. (E2)
|
||||||
|
*
|
||||||
|
* Alternative 1:
|
||||||
|
* From (E1) immediately get that BP*Fark(BP) is a solution.
|
||||||
|
*
|
||||||
|
* Alternative 2:
|
||||||
|
* We can rewrite (E2) to rewrite (E1) to
|
||||||
|
* (BP*Fark(BP)) => (neg(A*Fark(A) + BNP*Fark(BNP) + (neg D)*Fark(D))) (E3)
|
||||||
|
* and since we can derive (A*Fark(A) + BNP*Fark(BNP) + (neg D)*Fark(D)) from
|
||||||
|
* A, BNP and D, we also know that it is inconsisent. Therefore
|
||||||
|
* neg(A*Fark(A) + BNP*Fark(BNP) + (neg D)*Fark(D)) is a solution.
|
||||||
|
*
|
||||||
|
* Finally we also need the following workaround:
|
||||||
|
* 1) Although we know from theory, that the Farkas coefficients are always nonnegative,
|
||||||
|
* the Farkas coefficients provided by arith_core are sometimes negative (must be a bug)
|
||||||
|
* as workaround we take the absolute value of the provided coefficients.
|
||||||
|
*/
|
||||||
|
parameter const* params = d->get_parameters() + 2; // point to the first Farkas coefficient
|
||||||
|
|
||||||
|
STRACE("spacer.farkas",
|
||||||
|
verbose_stream() << "Farkas input: "<< "\n";
|
||||||
|
for (unsigned i = 0; i < m.get_num_parents(step); ++i) {
|
||||||
|
proof * prem = m.get_parent(step, i);
|
||||||
|
|
||||||
|
rational coef = params[i].get_rational();
|
||||||
|
|
||||||
|
bool b_pure = m_learner.m_pr.is_b_pure (prem);
|
||||||
|
verbose_stream() << (b_pure?"B":"A") << " " << coef << " " << mk_pp(m.get_fact(prem), m_learner.m) << "\n";
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
bool can_be_closed = true;
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < m.get_num_parents(step); ++i) {
|
||||||
|
proof * premise = m.get_parent(step, i);
|
||||||
|
|
||||||
|
if (m_learner.is_b_open (premise)) {
|
||||||
|
SASSERT(!m_learner.m_pr.is_a_marked(premise));
|
||||||
|
|
||||||
|
if (m_learner.m_pr.is_b_pure (step)) {
|
||||||
|
if (!m_use_constant_from_a) {
|
||||||
|
rational coefficient = params[i].get_rational();
|
||||||
|
coeff_lits.push_back(std::make_pair(abs(coefficient), (app*)m.get_fact(premise)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
can_be_closed = false;
|
||||||
|
|
||||||
|
if (m_use_constant_from_a) {
|
||||||
|
rational coefficient = params[i].get_rational();
|
||||||
|
coeff_lits.push_back(std::make_pair(abs(coefficient), (app*)m.get_fact(premise)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
if (m_use_constant_from_a) {
|
||||||
can_be_closed = false;
|
rational coefficient = params[i].get_rational();
|
||||||
|
coeff_lits.push_back(std::make_pair(abs(coefficient), (app*)m.get_fact(premise)));
|
||||||
if (m_use_constant_from_a)
|
|
||||||
{
|
|
||||||
rational coefficient;
|
|
||||||
VERIFY(params[i].is_rational(coefficient));
|
|
||||||
literals.push_back(to_app(m_learner.m.get_fact(premise)));
|
|
||||||
coefficients.push_back(abs(coefficient));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
if (m_use_constant_from_a) {
|
||||||
if (m_use_constant_from_a)
|
params += m.get_num_parents(step); // point to the first Farkas coefficient, which corresponds to a formula in the conclusion
|
||||||
{
|
|
||||||
rational coefficient;
|
// the conclusion can either be a single formula or a disjunction of several formulas, we have to deal with both situations
|
||||||
VERIFY(params[i].is_rational(coefficient));
|
if (m.get_num_parents(step) + 2 < d->get_num_parameters()) {
|
||||||
literals.push_back(to_app(m_learner.m.get_fact(premise)));
|
unsigned num_args = 1;
|
||||||
coefficients.push_back(abs(coefficient));
|
expr* conclusion = m.get_fact(step);
|
||||||
|
expr* const* args = &conclusion;
|
||||||
|
if (m.is_or(conclusion)) {
|
||||||
|
app* _or = to_app(conclusion);
|
||||||
|
num_args = _or->get_num_args();
|
||||||
|
args = _or->get_args();
|
||||||
|
}
|
||||||
|
SASSERT(m.get_num_parents(step) + 2 + num_args == d->get_num_parameters());
|
||||||
|
|
||||||
|
bool_rewriter brw(m_learner.m);
|
||||||
|
for (unsigned i = 0; i < num_args; ++i) {
|
||||||
|
expr* premise = args[i];
|
||||||
|
|
||||||
|
expr_ref negatedPremise(m_learner.m);
|
||||||
|
brw.mk_not(premise, negatedPremise);
|
||||||
|
pinned.push_back(negatedPremise);
|
||||||
|
rational coefficient = params[i].get_rational();
|
||||||
|
coeff_lits.push_back(std::make_pair(abs(coefficient), to_app(negatedPremise)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (m_use_constant_from_a)
|
// only if all b-premises can be used directly, add the farkas core and close the step
|
||||||
{
|
if (can_be_closed) {
|
||||||
params += m_learner.m.get_num_parents(step); // point to the first Farkas coefficient, which corresponds to a formula in the conclusion
|
m_learner.set_closed(step, true);
|
||||||
|
|
||||||
// the conclusion can either be a single formula or a disjunction of several formulas, we have to deal with both situations
|
expr_ref res = compute_linear_combination(coeff_lits);
|
||||||
if (m_learner.m.get_num_parents(step) + 2 < d->get_num_parameters())
|
|
||||||
{
|
m_learner.add_lemma_to_core(res);
|
||||||
unsigned num_args = 1;
|
|
||||||
expr* conclusion = m_learner.m.get_fact(step);
|
|
||||||
expr* const* args = &conclusion;
|
|
||||||
if (m_learner.m.is_or(conclusion))
|
|
||||||
{
|
|
||||||
app* _or = to_app(conclusion);
|
|
||||||
num_args = _or->get_num_args();
|
|
||||||
args = _or->get_args();
|
|
||||||
}
|
|
||||||
SASSERT(m_learner.m.get_num_parents(step) + 2 + num_args == d->get_num_parameters());
|
|
||||||
|
|
||||||
bool_rewriter brw(m_learner.m);
|
|
||||||
for (unsigned i = 0; i < num_args; ++i)
|
|
||||||
{
|
|
||||||
expr* premise = args[i];
|
|
||||||
|
|
||||||
expr_ref negatedPremise(m_learner.m);
|
|
||||||
brw.mk_not(premise, negatedPremise);
|
|
||||||
literals.push_back(to_app(negatedPremise));
|
|
||||||
|
|
||||||
rational coefficient;
|
|
||||||
VERIFY(params[i].is_rational(coefficient));
|
|
||||||
coefficients.push_back(abs(coefficient));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// only if all b-premises can be used directly, add the farkas core and close the step
|
expr_ref unsat_core_plugin_farkas_lemma::compute_linear_combination(const coeff_lits_t& coeff_lits)
|
||||||
if (can_be_closed)
|
{
|
||||||
{
|
|
||||||
m_learner.set_closed(step, true);
|
|
||||||
|
|
||||||
expr_ref res(m_learner.m);
|
smt::farkas_util util(m);
|
||||||
compute_linear_combination(coefficients, literals, res);
|
if (m_use_constant_from_a) {
|
||||||
|
util.set_split_literals (m_split_literals); // small optimization: if flag m_split_literals is set, then preserve diff constraints
|
||||||
m_learner.add_lemma_to_core(res);
|
}
|
||||||
|
for (auto& p : coeff_lits) {
|
||||||
|
util.add(p.first, p.second);
|
||||||
|
}
|
||||||
|
if (m_use_constant_from_a) {
|
||||||
|
return util.get();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
expr_ref negated_linear_combination = util.get();
|
||||||
|
return expr_ref(mk_not(m, negated_linear_combination), m);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void unsat_core_plugin_farkas_lemma::compute_linear_combination(const vector<rational>& coefficients, const ptr_vector<app>& literals, expr_ref& res)
|
|
||||||
{
|
|
||||||
SASSERT(literals.size() == coefficients.size());
|
|
||||||
|
|
||||||
ast_manager& m = res.get_manager();
|
|
||||||
smt::farkas_util util(m);
|
|
||||||
if (m_use_constant_from_a)
|
|
||||||
{
|
|
||||||
util.set_split_literals (m_split_literals); // small optimization: if flag m_split_literals is set, then preserve diff constraints
|
|
||||||
}
|
|
||||||
for(unsigned i = 0; i < literals.size(); ++i)
|
|
||||||
{
|
|
||||||
util.add(coefficients[i], literals[i]);
|
|
||||||
}
|
|
||||||
if (m_use_constant_from_a)
|
|
||||||
{
|
|
||||||
res = util.get();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
expr_ref negated_linear_combination = util.get();
|
|
||||||
res = mk_not(m, negated_linear_combination);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void unsat_core_plugin_farkas_lemma_optimized::compute_partial_core(proof* step)
|
void unsat_core_plugin_farkas_lemma_optimized::compute_partial_core(proof* step)
|
||||||
{
|
{
|
||||||
|
@ -298,34 +252,29 @@ void unsat_core_plugin_farkas_lemma::compute_linear_combination(const vector<rat
|
||||||
d->get_num_parameters() >= 2 && // the Farkas coefficients are saved in the parameters of step
|
d->get_num_parameters() >= 2 && // the Farkas coefficients are saved in the parameters of step
|
||||||
d->get_parameter(0).is_symbol(sym) && sym == "arith" && // the first two parameters are "arith", "farkas",
|
d->get_parameter(0).is_symbol(sym) && sym == "arith" && // the first two parameters are "arith", "farkas",
|
||||||
d->get_parameter(1).is_symbol(sym) && sym == "farkas" &&
|
d->get_parameter(1).is_symbol(sym) && sym == "farkas" &&
|
||||||
d->get_num_parameters() >= m_learner.m.get_num_parents(step) + 2) // the following parameters are the Farkas coefficients
|
d->get_num_parameters() >= m.get_num_parents(step) + 2) // the following parameters are the Farkas coefficients
|
||||||
{
|
{
|
||||||
SASSERT(m_learner.m.has_fact(step));
|
SASSERT(m.has_fact(step));
|
||||||
|
|
||||||
vector<std::pair<app*,rational> > linear_combination; // collects all summands of the linear combination
|
vector<std::pair<app*,rational> > linear_combination; // collects all summands of the linear combination
|
||||||
|
|
||||||
parameter const* params = d->get_parameters() + 2; // point to the first Farkas coefficient
|
parameter const* params = d->get_parameters() + 2; // point to the first Farkas coefficient
|
||||||
|
|
||||||
STRACE("spacer.farkas",
|
STRACE("spacer.farkas",
|
||||||
verbose_stream() << "Farkas input: "<< "\n";
|
verbose_stream() << "Farkas input: "<< "\n";
|
||||||
for (unsigned i = 0; i < m_learner.m.get_num_parents(step); ++i)
|
for (unsigned i = 0; i < m.get_num_parents(step); ++i) {
|
||||||
{
|
proof * prem = m.get_parent(step, i);
|
||||||
SASSERT(m_learner.m.is_proof(step->get_arg(i)));
|
|
||||||
proof *prem = m.get_parent (step, i);
|
|
||||||
|
|
||||||
rational coef;
|
rational coef = params[i].get_rational();
|
||||||
VERIFY(params[i].is_rational(coef));
|
|
||||||
|
bool b_pure = m_learner.m_pr.is_b_pure (prem);
|
||||||
bool b_pure = m_learner.m_pr.is_b_pure (prem);
|
verbose_stream() << (b_pure?"B":"A") << " " << coef << " " << mk_pp(m.get_fact(prem), m_learner.m) << "\n";
|
||||||
verbose_stream() << (b_pure?"B":"A") << " " << coef << " " << mk_pp(m_learner.m.get_fact(prem), m_learner.m) << "\n";
|
}
|
||||||
}
|
);
|
||||||
);
|
|
||||||
|
|
||||||
bool can_be_closed = true;
|
bool can_be_closed = true;
|
||||||
for(unsigned i = 0; i < m_learner.m.get_num_parents(step); ++i)
|
for (unsigned i = 0; i < m.get_num_parents(step); ++i) {
|
||||||
{
|
proof * premise = m.get_parent(step, i);
|
||||||
SASSERT(m_learner.m.is_proof(step->get_arg(i)));
|
|
||||||
proof * premise = m.get_parent (step, i);
|
|
||||||
|
|
||||||
if (m_learner.m_pr.is_b_marked(premise) && !m_learner.is_closed(premise))
|
if (m_learner.m_pr.is_b_marked(premise) && !m_learner.is_closed(premise))
|
||||||
{
|
{
|
||||||
|
@ -333,10 +282,9 @@ void unsat_core_plugin_farkas_lemma::compute_linear_combination(const vector<rat
|
||||||
|
|
||||||
if (m_learner.m_pr.is_b_pure(premise))
|
if (m_learner.m_pr.is_b_pure(premise))
|
||||||
{
|
{
|
||||||
rational coefficient;
|
rational coefficient = params[i].get_rational();
|
||||||
VERIFY(params[i].is_rational(coefficient));
|
|
||||||
linear_combination.push_back
|
linear_combination.push_back
|
||||||
(std::make_pair(to_app(m_learner.m.get_fact(premise)),
|
(std::make_pair(to_app(m.get_fact(premise)),
|
||||||
abs(coefficient)));
|
abs(coefficient)));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -374,19 +322,16 @@ void unsat_core_plugin_farkas_lemma::compute_linear_combination(const vector<rat
|
||||||
}
|
}
|
||||||
DEBUG_CODE(
|
DEBUG_CODE(
|
||||||
for (auto& linear_combination : m_linear_combinations) {
|
for (auto& linear_combination : m_linear_combinations) {
|
||||||
SASSERT(linear_combination.size() > 0);
|
SASSERT(!linear_combination.empty());
|
||||||
});
|
});
|
||||||
|
|
||||||
// 1. construct ordered basis
|
// 1. construct ordered basis
|
||||||
ptr_vector<app> ordered_basis;
|
ptr_vector<app> ordered_basis;
|
||||||
obj_map<app, unsigned> map;
|
obj_map<app, unsigned> map;
|
||||||
unsigned counter = 0;
|
unsigned counter = 0;
|
||||||
for (const auto& linear_combination : m_linear_combinations)
|
for (const auto& linear_combination : m_linear_combinations) {
|
||||||
{
|
for (const auto& pair : linear_combination) {
|
||||||
for (const auto& pair : linear_combination)
|
if (!map.contains(pair.first)) {
|
||||||
{
|
|
||||||
if (!map.contains(pair.first))
|
|
||||||
{
|
|
||||||
ordered_basis.push_back(pair.first);
|
ordered_basis.push_back(pair.first);
|
||||||
map.insert(pair.first, counter++);
|
map.insert(pair.first, counter++);
|
||||||
}
|
}
|
||||||
|
@ -396,11 +341,9 @@ void unsat_core_plugin_farkas_lemma::compute_linear_combination(const vector<rat
|
||||||
// 2. populate matrix
|
// 2. populate matrix
|
||||||
spacer_matrix matrix(m_linear_combinations.size(), ordered_basis.size());
|
spacer_matrix matrix(m_linear_combinations.size(), ordered_basis.size());
|
||||||
|
|
||||||
for (unsigned i=0; i < m_linear_combinations.size(); ++i)
|
for (unsigned i = 0; i < m_linear_combinations.size(); ++i) {
|
||||||
{
|
|
||||||
auto linear_combination = m_linear_combinations[i];
|
auto linear_combination = m_linear_combinations[i];
|
||||||
for (const auto& pair : linear_combination)
|
for (const auto& pair : linear_combination) {
|
||||||
{
|
|
||||||
matrix.set(i, map[pair.first], pair.second);
|
matrix.set(i, map[pair.first], pair.second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -409,44 +352,36 @@ void unsat_core_plugin_farkas_lemma::compute_linear_combination(const vector<rat
|
||||||
unsigned i = matrix.perform_gaussian_elimination();
|
unsigned i = matrix.perform_gaussian_elimination();
|
||||||
|
|
||||||
// 4. extract linear combinations from matrix and add result to core
|
// 4. extract linear combinations from matrix and add result to core
|
||||||
for (unsigned k=0; k < i; k++)// i points to the row after the last row which is non-zero
|
for (unsigned k = 0; k < i; ++k)// i points to the row after the last row which is non-zero
|
||||||
{
|
{
|
||||||
ptr_vector<app> literals;
|
coeff_lits_t coeff_lits;
|
||||||
vector<rational> coefficients;
|
for (unsigned l = 0; l < matrix.num_cols(); ++l) {
|
||||||
for (unsigned l=0; l < matrix.num_cols(); ++l)
|
if (!matrix.get(k,l).is_zero()) {
|
||||||
{
|
coeff_lits.push_back(std::make_pair(matrix.get(k, l), ordered_basis[l]));
|
||||||
if (!matrix.get(k,l).is_zero())
|
}
|
||||||
{
|
|
||||||
literals.push_back(ordered_basis[l]);
|
|
||||||
coefficients.push_back(matrix.get(k,l));
|
|
||||||
}
|
}
|
||||||
}
|
SASSERT(!coeff_lits.empty());
|
||||||
SASSERT(literals.size() > 0);
|
expr_ref linear_combination = compute_linear_combination(coeff_lits);
|
||||||
expr_ref linear_combination(m);
|
|
||||||
compute_linear_combination(coefficients, literals, linear_combination);
|
|
||||||
|
|
||||||
m_learner.add_lemma_to_core(linear_combination);
|
m_learner.add_lemma_to_core(linear_combination);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void unsat_core_plugin_farkas_lemma_optimized::compute_linear_combination(const vector<rational>& coefficients, const ptr_vector<app>& literals, expr_ref& res)
|
expr_ref unsat_core_plugin_farkas_lemma_optimized::compute_linear_combination(const coeff_lits_t& coeff_lits)
|
||||||
{
|
{
|
||||||
SASSERT(literals.size() == coefficients.size());
|
|
||||||
|
smt::farkas_util util(m);
|
||||||
|
for (auto const & p : coeff_lits) {
|
||||||
|
util.add(p.first, p.second);
|
||||||
|
}
|
||||||
|
expr_ref negated_linear_combination = util.get();
|
||||||
|
SASSERT(m.is_not(negated_linear_combination));
|
||||||
|
return expr_ref(mk_not(m, negated_linear_combination), m);
|
||||||
|
//TODO: rewrite the get-method to return nonnegated stuff?
|
||||||
|
}
|
||||||
|
|
||||||
ast_manager& m = res.get_manager();
|
void unsat_core_plugin_farkas_lemma_bounded::finalize() {
|
||||||
smt::farkas_util util(m);
|
|
||||||
for(unsigned i = 0; i < literals.size(); ++i)
|
|
||||||
{
|
|
||||||
util.add(coefficients[i], literals[i]);
|
|
||||||
}
|
|
||||||
expr_ref negated_linear_combination = util.get();
|
|
||||||
SASSERT(m.is_not(negated_linear_combination));
|
|
||||||
res = mk_not(m, negated_linear_combination); //TODO: rewrite the get-method to return nonnegated stuff?
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void unsat_core_plugin_farkas_lemma_bounded::finalize() {
|
|
||||||
if (m_linear_combinations.empty()) {
|
if (m_linear_combinations.empty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -486,13 +421,12 @@ void unsat_core_plugin_farkas_lemma::compute_linear_combination(const vector<rat
|
||||||
arith_util util(m);
|
arith_util util(m);
|
||||||
|
|
||||||
vector<expr_ref_vector> coeffs;
|
vector<expr_ref_vector> coeffs;
|
||||||
for (unsigned i=0; i < matrix.num_rows(); ++i) {
|
for (unsigned i = 0; i < matrix.num_rows(); ++i) {
|
||||||
coeffs.push_back(expr_ref_vector(m));
|
coeffs.push_back(expr_ref_vector(m));
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<expr_ref_vector> bounded_vectors;
|
vector<expr_ref_vector> bounded_vectors;
|
||||||
for (unsigned j=0; j < matrix.num_cols(); ++j)
|
for (unsigned j = 0; j < matrix.num_cols(); ++j) {
|
||||||
{
|
|
||||||
bounded_vectors.push_back(expr_ref_vector(m));
|
bounded_vectors.push_back(expr_ref_vector(m));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -501,37 +435,24 @@ void unsat_core_plugin_farkas_lemma::compute_linear_combination(const vector<rat
|
||||||
{
|
{
|
||||||
params_ref p;
|
params_ref p;
|
||||||
p.set_bool("model", true);
|
p.set_bool("model", true);
|
||||||
scoped_ptr<solver> s = mk_smt_solver(m, p, symbol::null); // TODO: incremental version?
|
solver_ref s = mk_smt_solver(m, p, symbol::null); // TODO: incremental version?
|
||||||
|
|
||||||
// add new variables w_in,
|
// add new variables w_in,
|
||||||
for (unsigned i=0; i < matrix.num_rows(); ++i)
|
for (unsigned i = 0; i < matrix.num_rows(); ++i) {
|
||||||
{
|
|
||||||
std::string name = "w_" + std::to_string(i) + std::to_string(n);
|
std::string name = "w_" + std::to_string(i) + std::to_string(n);
|
||||||
|
coeffs[i].push_back(m.mk_const(name, util.mk_int()));
|
||||||
func_decl_ref decl(m);
|
|
||||||
decl = m.mk_func_decl(symbol(name.c_str()), 0, (sort*const*)nullptr, util.mk_int());
|
|
||||||
coeffs[i].push_back(m.mk_const(decl));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// we need s_jn
|
// we need s_jn
|
||||||
for (unsigned j=0; j < matrix.num_cols(); ++j)
|
for (unsigned j = 0; j < matrix.num_cols(); ++j) {
|
||||||
{
|
|
||||||
std::string name = "s_" + std::to_string(j) + std::to_string(n);
|
std::string name = "s_" + std::to_string(j) + std::to_string(n);
|
||||||
|
bounded_vectors[j].push_back(m.mk_const(name, util.mk_int()));
|
||||||
func_decl_ref decl(m);
|
|
||||||
decl = m.mk_func_decl(symbol(name.c_str()), 0, (sort*const*)nullptr, util.mk_int());
|
|
||||||
|
|
||||||
expr_ref s_jn(m);
|
|
||||||
s_jn = m.mk_const(decl);
|
|
||||||
|
|
||||||
bounded_vectors[j].push_back(s_jn);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// assert bounds for all s_jn
|
// assert bounds for all s_jn
|
||||||
for (unsigned l=0; l < n; ++l) {
|
for (unsigned l = 0; l < n; ++l) {
|
||||||
for (unsigned j=0; j < matrix.num_cols(); ++j) {
|
for (unsigned j = 0; j < matrix.num_cols(); ++j) {
|
||||||
expr* s_jn = bounded_vectors[j][l].get();
|
expr* s_jn = bounded_vectors[j][l].get();
|
||||||
|
|
||||||
expr_ref lb(util.mk_le(util.mk_int(0), s_jn), m);
|
expr_ref lb(util.mk_le(util.mk_int(0), s_jn), m);
|
||||||
expr_ref ub(util.mk_le(s_jn, util.mk_int(1)), m);
|
expr_ref ub(util.mk_le(s_jn, util.mk_int(1)), m);
|
||||||
s->assert_expr(lb);
|
s->assert_expr(lb);
|
||||||
|
@ -540,47 +461,40 @@ void unsat_core_plugin_farkas_lemma::compute_linear_combination(const vector<rat
|
||||||
}
|
}
|
||||||
|
|
||||||
// assert: forall i,j: a_ij = sum_k w_ik * s_jk
|
// assert: forall i,j: a_ij = sum_k w_ik * s_jk
|
||||||
for (unsigned i=0; i < matrix.num_rows(); ++i)
|
for (unsigned i = 0; i < matrix.num_rows(); ++i) {
|
||||||
{
|
for (unsigned j = 0; j < matrix.num_cols(); ++j) {
|
||||||
for (unsigned j=0; j < matrix.num_cols(); ++j)
|
|
||||||
{
|
|
||||||
SASSERT(matrix.get(i, j).is_int());
|
SASSERT(matrix.get(i, j).is_int());
|
||||||
app_ref a_ij(util.mk_numeral(matrix.get(i,j), true),m);
|
app_ref a_ij(util.mk_numeral(matrix.get(i,j), true), m);
|
||||||
|
|
||||||
app_ref sum(m);
|
app_ref sum(util.mk_int(0), m);
|
||||||
sum = util.mk_int(0);
|
for (unsigned k = 0; k < n; ++k) {
|
||||||
for (unsigned k=0; k < n; ++k)
|
|
||||||
{
|
|
||||||
sum = util.mk_add(sum, util.mk_mul(coeffs[i][k].get(), bounded_vectors[j][k].get()));
|
sum = util.mk_add(sum, util.mk_mul(coeffs[i][k].get(), bounded_vectors[j][k].get()));
|
||||||
}
|
|
||||||
expr_ref eq(m.mk_eq(a_ij, sum),m);
|
|
||||||
s->assert_expr(eq);
|
|
||||||
}
|
}
|
||||||
|
expr_ref eq(m.mk_eq(a_ij, sum), m);
|
||||||
|
s->assert_expr(eq);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// check result
|
// check result
|
||||||
lbool res = s->check_sat(0,nullptr);
|
lbool res = s->check_sat(0, nullptr);
|
||||||
|
|
||||||
// if sat extract model and add corresponding linear combinations to core
|
// if sat extract model and add corresponding linear combinations to core
|
||||||
if (res == lbool::l_true) {
|
if (res == lbool::l_true) {
|
||||||
model_ref model;
|
model_ref model;
|
||||||
s->get_model(model);
|
s->get_model(model);
|
||||||
|
|
||||||
for (unsigned k=0; k < n; ++k) {
|
for (unsigned k = 0; k < n; ++k) {
|
||||||
ptr_vector<app> literals;
|
coeff_lits_t coeff_lits;
|
||||||
vector<rational> coefficients;
|
for (unsigned j = 0; j < matrix.num_cols(); ++j) {
|
||||||
for (unsigned j=0; j < matrix.num_cols(); ++j) {
|
|
||||||
expr_ref evaluation(m);
|
expr_ref evaluation(m);
|
||||||
|
|
||||||
model.get()->eval(bounded_vectors[j][k].get(), evaluation, false);
|
model.get()->eval(bounded_vectors[j][k].get(), evaluation, false);
|
||||||
if (!util.is_zero(evaluation)) {
|
if (!util.is_zero(evaluation)) {
|
||||||
literals.push_back(ordered_basis[j]);
|
coeff_lits.push_back(std::make_pair(rational(1), ordered_basis[j]));
|
||||||
coefficients.push_back(rational(1));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SASSERT(!literals.empty()); // since then previous outer loop would have found solution already
|
SASSERT(!coeff_lits.empty()); // since then previous outer loop would have found solution already
|
||||||
expr_ref linear_combination(m);
|
expr_ref linear_combination = compute_linear_combination(coeff_lits);
|
||||||
compute_linear_combination(coefficients, literals, linear_combination);
|
|
||||||
|
|
||||||
m_learner.add_lemma_to_core(linear_combination);
|
m_learner.add_lemma_to_core(linear_combination);
|
||||||
}
|
}
|
||||||
|
@ -589,7 +503,7 @@ void unsat_core_plugin_farkas_lemma::compute_linear_combination(const vector<rat
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsat_core_plugin_min_cut::unsat_core_plugin_min_cut(unsat_core_learner& learner, ast_manager& m) : unsat_core_plugin(learner), m(m){}
|
unsat_core_plugin_min_cut::unsat_core_plugin_min_cut(unsat_core_learner& learner, ast_manager& m) : unsat_core_plugin(learner) {}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* traverses proof rooted in step and constructs graph, which corresponds to the proof-DAG, with the following differences:
|
* traverses proof rooted in step and constructs graph, which corresponds to the proof-DAG, with the following differences:
|
||||||
|
@ -637,17 +551,11 @@ void unsat_core_plugin_farkas_lemma::compute_linear_combination(const vector<rat
|
||||||
{
|
{
|
||||||
bool is_sink = true;
|
bool is_sink = true;
|
||||||
|
|
||||||
ast_manager &m = m_learner.m;
|
ptr_buffer<proof> todo_subproof;
|
||||||
ptr_vector<proof> todo_subproof;
|
|
||||||
|
|
||||||
for (unsigned i = 0, sz = m.get_num_parents(step); i < sz; ++i)
|
for (proof* premise : m.get_parents(step)) {
|
||||||
{
|
if (m_learner.m_pr.is_b_marked(premise)) {
|
||||||
proof* premise = m.get_parent (step, i);
|
todo_subproof.push_back(premise);
|
||||||
{
|
|
||||||
if (m_learner.m_pr.is_b_marked(premise))
|
|
||||||
{
|
|
||||||
todo_subproof.push_back(premise);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (!todo_subproof.empty())
|
while (!todo_subproof.empty())
|
||||||
|
@ -685,10 +593,7 @@ void unsat_core_plugin_farkas_lemma::compute_linear_combination(const vector<rat
|
||||||
// otherwise continue search for leaves of subproof
|
// otherwise continue search for leaves of subproof
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (unsigned i = 0; i < m_learner.m.get_num_parents(current); ++i)
|
for (proof* premise : m.get_parents(current)) {
|
||||||
{
|
|
||||||
SASSERT(m_learner.m.is_proof(current->get_arg(i)));
|
|
||||||
proof* premise = m.get_parent (current, i);
|
|
||||||
todo_subproof.push_back(premise);
|
todo_subproof.push_back(premise);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -790,8 +695,8 @@ void unsat_core_plugin_farkas_lemma::compute_linear_combination(const vector<rat
|
||||||
* computes min-cut on the graph constructed by compute_partial_core-method
|
* computes min-cut on the graph constructed by compute_partial_core-method
|
||||||
* and adds the corresponding lemmas to the core
|
* and adds the corresponding lemmas to the core
|
||||||
*/
|
*/
|
||||||
void unsat_core_plugin_min_cut::finalize()
|
void unsat_core_plugin_min_cut::finalize()
|
||||||
{
|
{
|
||||||
unsigned_vector cut_nodes;
|
unsigned_vector cut_nodes;
|
||||||
m_min_cut.compute_min_cut(cut_nodes);
|
m_min_cut.compute_min_cut(cut_nodes);
|
||||||
|
|
||||||
|
|
|
@ -27,10 +27,12 @@ class unsat_core_learner;
|
||||||
|
|
||||||
|
|
||||||
class unsat_core_plugin {
|
class unsat_core_plugin {
|
||||||
|
protected:
|
||||||
|
typedef vector<std::pair<rational, app*>> coeff_lits_t;
|
||||||
|
ast_manager& m;
|
||||||
public:
|
public:
|
||||||
unsat_core_plugin(unsat_core_learner& learner) : m_learner(learner){};
|
unsat_core_plugin(unsat_core_learner& learner);
|
||||||
virtual ~unsat_core_plugin(){};
|
virtual ~unsat_core_plugin() {};
|
||||||
virtual void compute_partial_core(proof* step) = 0;
|
virtual void compute_partial_core(proof* step) = 0;
|
||||||
virtual void finalize(){};
|
virtual void finalize(){};
|
||||||
|
|
||||||
|
@ -68,24 +70,23 @@ private:
|
||||||
/*
|
/*
|
||||||
* compute linear combination of literals 'literals' having coefficients 'coefficients' and save result in res
|
* compute linear combination of literals 'literals' having coefficients 'coefficients' and save result in res
|
||||||
*/
|
*/
|
||||||
void compute_linear_combination(const vector<rational>& coefficients, const ptr_vector<app>& literals, expr_ref& res);
|
expr_ref compute_linear_combination(const coeff_lits_t& coeff_lits);
|
||||||
};
|
};
|
||||||
|
|
||||||
class unsat_core_plugin_farkas_lemma_optimized : public unsat_core_plugin {
|
class unsat_core_plugin_farkas_lemma_optimized : public unsat_core_plugin {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
unsat_core_plugin_farkas_lemma_optimized(unsat_core_learner& learner, ast_manager& m) : unsat_core_plugin(learner), m(m) {};
|
unsat_core_plugin_farkas_lemma_optimized(unsat_core_learner& learner, ast_manager& m) : unsat_core_plugin(learner) {};
|
||||||
|
|
||||||
void compute_partial_core(proof* step) override;
|
void compute_partial_core(proof* step) override;
|
||||||
void finalize() override;
|
void finalize() override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
vector<vector<std::pair<app*, rational> > > m_linear_combinations;
|
vector<vector<std::pair<app*, rational> > > m_linear_combinations;
|
||||||
ast_manager& m;
|
|
||||||
/*
|
/*
|
||||||
* compute linear combination of literals 'literals' having coefficients 'coefficients' and save result in res
|
* compute linear combination of literals 'literals' having coefficients 'coefficients' and save result in res
|
||||||
*/
|
*/
|
||||||
void compute_linear_combination(const vector<rational>& coefficients, const ptr_vector<app>& literals, expr_ref& res);
|
expr_ref compute_linear_combination(const coeff_lits_t& coeff_lits);
|
||||||
};
|
};
|
||||||
|
|
||||||
class unsat_core_plugin_farkas_lemma_bounded : public unsat_core_plugin_farkas_lemma_optimized {
|
class unsat_core_plugin_farkas_lemma_bounded : public unsat_core_plugin_farkas_lemma_optimized {
|
||||||
|
@ -104,7 +105,6 @@ private:
|
||||||
void compute_partial_core(proof* step) override;
|
void compute_partial_core(proof* step) override;
|
||||||
void finalize() override;
|
void finalize() override;
|
||||||
private:
|
private:
|
||||||
ast_manager& m;
|
|
||||||
|
|
||||||
ast_mark m_visited; // saves for each node i whether the subproof with root i has already been added to the min-cut-problem
|
ast_mark m_visited; // saves for each node i whether the subproof with root i has already been added to the min-cut-problem
|
||||||
obj_map<proof, unsigned> m_proof_to_node_minus; // maps proof-steps to the corresponding minus-nodes (the ones which are closer to source)
|
obj_map<proof, unsigned> m_proof_to_node_minus; // maps proof-steps to the corresponding minus-nodes (the ones which are closer to source)
|
||||||
|
|
|
@ -47,7 +47,7 @@ public:
|
||||||
virtual ~check_sat_result() {}
|
virtual ~check_sat_result() {}
|
||||||
void inc_ref() { m_ref_count++; }
|
void inc_ref() { m_ref_count++; }
|
||||||
void dec_ref() { SASSERT(m_ref_count > 0); m_ref_count--; if (m_ref_count == 0) dealloc(this); }
|
void dec_ref() { SASSERT(m_ref_count > 0); m_ref_count--; if (m_ref_count == 0) dealloc(this); }
|
||||||
void set_status(lbool r) { m_status = r; }
|
lbool set_status(lbool r) { return m_status = r; }
|
||||||
lbool status() const { return m_status; }
|
lbool status() const { return m_status; }
|
||||||
virtual void collect_statistics(statistics & st) const = 0;
|
virtual void collect_statistics(statistics & st) const = 0;
|
||||||
virtual void get_unsat_core(ptr_vector<expr> & r) = 0;
|
virtual void get_unsat_core(ptr_vector<expr> & r) = 0;
|
||||||
|
|
Loading…
Reference in a new issue