mirror of
https://github.com/Z3Prover/z3
synced 2025-07-20 11:22:04 +00:00
Cleanup iuc_proof
This commit is contained in:
parent
ebf6b18821
commit
abe67705d3
4 changed files with 211 additions and 260 deletions
|
@ -6,229 +6,182 @@
|
||||||
|
|
||||||
namespace spacer {
|
namespace spacer {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ====================================
|
* ====================================
|
||||||
* init
|
* init
|
||||||
* ====================================
|
* ====================================
|
||||||
*/
|
*/
|
||||||
iuc_proof::iuc_proof(ast_manager& m, proof* pr, expr_set& b_conjuncts) : m(m), m_pr(pr,m)
|
iuc_proof::iuc_proof(ast_manager& m, proof* pr, expr_set& core_lits) :
|
||||||
{
|
m(m), m_pr(pr,m) {
|
||||||
// init A-marks and B-marks
|
// init A-marks and B-marks
|
||||||
collect_symbols_b(b_conjuncts);
|
collect_core_symbols(core_lits);
|
||||||
compute_marks(b_conjuncts);
|
compute_marks(core_lits);
|
||||||
}
|
}
|
||||||
|
|
||||||
proof* iuc_proof::get()
|
/*
|
||||||
{
|
* ====================================
|
||||||
return m_pr.get();
|
* methods for computing symbol colors
|
||||||
}
|
* ====================================
|
||||||
|
*/
|
||||||
|
class collect_pure_proc {
|
||||||
|
func_decl_set& m_symbs;
|
||||||
|
public:
|
||||||
|
collect_pure_proc(func_decl_set& s):m_symbs(s) {}
|
||||||
|
|
||||||
/*
|
void operator()(app* a) {
|
||||||
* ====================================
|
if (a->get_family_id() == null_family_id) {
|
||||||
* methods for computing symbol colors
|
m_symbs.insert(a->get_decl());
|
||||||
* ====================================
|
|
||||||
*/
|
|
||||||
class collect_pure_proc {
|
|
||||||
func_decl_set& m_symbs;
|
|
||||||
public:
|
|
||||||
collect_pure_proc(func_decl_set& s):m_symbs(s) {}
|
|
||||||
|
|
||||||
void operator()(app* a) {
|
|
||||||
if (a->get_family_id() == null_family_id) {
|
|
||||||
m_symbs.insert(a->get_decl());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void operator()(var*) {}
|
|
||||||
void operator()(quantifier*) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
void iuc_proof::collect_symbols_b(expr_set& b_conjuncts)
|
|
||||||
{
|
|
||||||
expr_mark visited;
|
|
||||||
collect_pure_proc proc(m_symbols_b);
|
|
||||||
for (expr_set::iterator it = b_conjuncts.begin(); it != b_conjuncts.end(); ++it)
|
|
||||||
{
|
|
||||||
for_each_expr(proc, visited, *it);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
void operator()(var*) {}
|
||||||
|
void operator()(quantifier*) {}
|
||||||
|
};
|
||||||
|
|
||||||
class is_pure_expr_proc {
|
void iuc_proof::collect_core_symbols(expr_set& core_lits)
|
||||||
func_decl_set const& m_symbs;
|
{
|
||||||
array_util m_au;
|
expr_mark visited;
|
||||||
public:
|
collect_pure_proc proc(m_core_symbols);
|
||||||
struct non_pure {};
|
for (expr_set::iterator it = core_lits.begin(); it != core_lits.end(); ++it) {
|
||||||
|
for_each_expr(proc, visited, *it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
is_pure_expr_proc(func_decl_set const& s, ast_manager& m):
|
class is_pure_expr_proc {
|
||||||
|
func_decl_set const& m_symbs;
|
||||||
|
array_util m_au;
|
||||||
|
public:
|
||||||
|
struct non_pure {};
|
||||||
|
|
||||||
|
is_pure_expr_proc(func_decl_set const& s, ast_manager& m):
|
||||||
m_symbs(s),
|
m_symbs(s),
|
||||||
m_au (m)
|
m_au (m)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void operator()(app* a) {
|
void operator()(app* a) {
|
||||||
if (a->get_family_id() == null_family_id) {
|
if (a->get_family_id() == null_family_id) {
|
||||||
if (!m_symbs.contains(a->get_decl())) {
|
if (!m_symbs.contains(a->get_decl())) {
|
||||||
throw non_pure();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (a->get_family_id () == m_au.get_family_id () &&
|
|
||||||
a->is_app_of (a->get_family_id (), OP_ARRAY_EXT)) {
|
|
||||||
throw non_pure();
|
throw non_pure();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void operator()(var*) {}
|
else if (a->get_family_id () == m_au.get_family_id () &&
|
||||||
void operator()(quantifier*) {}
|
a->is_app_of (a->get_family_id (), OP_ARRAY_EXT)) {
|
||||||
};
|
throw non_pure();
|
||||||
|
|
||||||
// requires that m_symbols_b has already been computed, which is done during initialization.
|
|
||||||
bool iuc_proof::only_contains_symbols_b(expr* expr) const
|
|
||||||
{
|
|
||||||
is_pure_expr_proc proc(m_symbols_b, m);
|
|
||||||
try {
|
|
||||||
for_each_expr(proc, expr);
|
|
||||||
}
|
}
|
||||||
catch (is_pure_expr_proc::non_pure)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
void operator()(var*) {}
|
||||||
|
void operator()(quantifier*) {}
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
bool iuc_proof::is_core_pure(expr* e) const
|
||||||
* ====================================
|
{
|
||||||
* methods for computing which premises
|
is_pure_expr_proc proc(m_core_symbols, m);
|
||||||
* have been used to derive the conclusions
|
try {
|
||||||
* ====================================
|
for_each_expr(proc, e);
|
||||||
*/
|
}
|
||||||
|
catch (is_pure_expr_proc::non_pure)
|
||||||
|
{return false;}
|
||||||
|
|
||||||
void iuc_proof::compute_marks(expr_set& b_conjuncts)
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void iuc_proof::compute_marks(expr_set& core_lits)
|
||||||
|
{
|
||||||
|
proof_post_order it(m_pr, m);
|
||||||
|
while (it.hasNext())
|
||||||
{
|
{
|
||||||
proof_post_order it(m_pr, m);
|
proof* cur = it.next();
|
||||||
while (it.hasNext())
|
if (m.get_num_parents(cur) == 0)
|
||||||
{
|
{
|
||||||
proof* currentNode = it.next();
|
switch(cur->get_decl_kind())
|
||||||
|
|
||||||
if (m.get_num_parents(currentNode) == 0)
|
|
||||||
{
|
{
|
||||||
switch(currentNode->get_decl_kind())
|
case PR_ASSERTED:
|
||||||
{
|
if (core_lits.contains(m.get_fact(cur)))
|
||||||
|
m_b_mark.mark(cur, true);
|
||||||
case PR_ASSERTED: // currentNode is an axiom
|
else
|
||||||
{
|
m_a_mark.mark(cur, true);
|
||||||
if (b_conjuncts.contains(m.get_fact(currentNode)))
|
break;
|
||||||
{
|
case PR_HYPOTHESIS:
|
||||||
m_b_mark.mark(currentNode, true);
|
m_h_mark.mark(cur, true);
|
||||||
}
|
break;
|
||||||
else
|
default:
|
||||||
{
|
break;
|
||||||
m_a_mark.mark(currentNode, true);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// currentNode is a hypothesis:
|
|
||||||
case PR_HYPOTHESIS:
|
|
||||||
{
|
|
||||||
m_h_mark.mark(currentNode, true);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// collect from parents whether derivation of current node contains A-axioms, B-axioms and hypothesis
|
|
||||||
bool need_to_mark_a = false;
|
|
||||||
bool need_to_mark_b = false;
|
|
||||||
bool need_to_mark_h = false;
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < m.get_num_parents(currentNode); ++i)
|
|
||||||
{
|
|
||||||
SASSERT(m.is_proof(currentNode->get_arg(i)));
|
|
||||||
proof* premise = to_app(currentNode->get_arg(i));
|
|
||||||
|
|
||||||
need_to_mark_a = need_to_mark_a || m_a_mark.is_marked(premise);
|
|
||||||
need_to_mark_b = need_to_mark_b || m_b_mark.is_marked(premise);
|
|
||||||
need_to_mark_h = need_to_mark_h || m_h_mark.is_marked(premise);
|
|
||||||
}
|
|
||||||
|
|
||||||
// if current node is application of lemma, we know that all hypothesis are removed
|
|
||||||
if(currentNode->get_decl_kind() == PR_LEMMA)
|
|
||||||
{
|
|
||||||
need_to_mark_h = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// save results
|
|
||||||
m_a_mark.mark(currentNode, need_to_mark_a);
|
|
||||||
m_b_mark.mark(currentNode, need_to_mark_b);
|
|
||||||
m_h_mark.mark(currentNode, need_to_mark_h);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
|
|
||||||
bool iuc_proof::is_a_marked(proof* p)
|
|
||||||
{
|
|
||||||
return m_a_mark.is_marked(p);
|
|
||||||
}
|
|
||||||
bool iuc_proof::is_b_marked(proof* p)
|
|
||||||
{
|
|
||||||
return m_b_mark.is_marked(p);
|
|
||||||
}
|
|
||||||
bool iuc_proof::is_h_marked(proof* p)
|
|
||||||
{
|
|
||||||
return m_h_mark.is_marked(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* ====================================
|
|
||||||
* methods for dot printing
|
|
||||||
* ====================================
|
|
||||||
*/
|
|
||||||
void iuc_proof::pp_dot()
|
|
||||||
{
|
|
||||||
pp_proof_dot(m, m_pr, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* ====================================
|
|
||||||
* statistics
|
|
||||||
* ====================================
|
|
||||||
*/
|
|
||||||
|
|
||||||
void iuc_proof::print_farkas_stats()
|
|
||||||
{
|
|
||||||
unsigned farkas_counter = 0;
|
|
||||||
unsigned farkas_counter2 = 0;
|
|
||||||
|
|
||||||
proof_post_order it3(m_pr, m);
|
|
||||||
while (it3.hasNext())
|
|
||||||
{
|
{
|
||||||
proof* currentNode = it3.next();
|
// collect from parents whether derivation of current node
|
||||||
|
// contains A-axioms, B-axioms and hypothesis
|
||||||
|
bool need_to_mark_a = false;
|
||||||
|
bool need_to_mark_b = false;
|
||||||
|
bool need_to_mark_h = false;
|
||||||
|
|
||||||
// if node is theory lemma
|
for (unsigned i = 0; i < m.get_num_parents(cur); ++i)
|
||||||
if (is_farkas_lemma(m, currentNode))
|
|
||||||
{
|
{
|
||||||
farkas_counter++;
|
SASSERT(m.is_proof(cur->get_arg(i)));
|
||||||
|
proof* premise = to_app(cur->get_arg(i));
|
||||||
|
|
||||||
// check whether farkas lemma is to be interpolated (could potentially miss farkas lemmas, which are interpolated, because we potentially don't want to use the lowest cut)
|
need_to_mark_a |= m_a_mark.is_marked(premise);
|
||||||
bool has_blue_nonred_parent = false;
|
need_to_mark_b |= m_b_mark.is_marked(premise);
|
||||||
for (unsigned i = 0; i < m.get_num_parents(currentNode); ++i)
|
need_to_mark_h |= m_h_mark.is_marked(premise);
|
||||||
{
|
|
||||||
proof* premise = to_app(currentNode->get_arg(i));
|
|
||||||
if (!is_a_marked(premise) && is_b_marked(premise))
|
|
||||||
{
|
|
||||||
has_blue_nonred_parent = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (has_blue_nonred_parent && is_a_marked(currentNode))
|
|
||||||
{
|
|
||||||
SASSERT(is_b_marked(currentNode));
|
|
||||||
farkas_counter2++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
verbose_stream() << "\nThis proof contains " << farkas_counter << " Farkas lemmas. " << farkas_counter2 << " Farkas lemmas participate in the lowest cut\n";
|
// if current node is application of a lemma, then all
|
||||||
|
// active hypotheses are removed
|
||||||
|
if(cur->get_decl_kind() == PR_LEMMA) need_to_mark_h = false;
|
||||||
|
|
||||||
|
// save results
|
||||||
|
m_a_mark.mark(cur, need_to_mark_a);
|
||||||
|
m_b_mark.mark(cur, need_to_mark_b);
|
||||||
|
m_h_mark.mark(cur, need_to_mark_h);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ====================================
|
||||||
|
* statistics
|
||||||
|
* ====================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
// debug method
|
||||||
|
void iuc_proof::dump_farkas_stats()
|
||||||
|
{
|
||||||
|
unsigned fl_total = 0;
|
||||||
|
unsigned fl_lowcut = 0;
|
||||||
|
|
||||||
|
proof_post_order it(m_pr, m);
|
||||||
|
while (it.hasNext())
|
||||||
|
{
|
||||||
|
proof* cur = it.next();
|
||||||
|
|
||||||
|
// if node is theory lemma
|
||||||
|
if (is_farkas_lemma(m, cur))
|
||||||
|
{
|
||||||
|
fl_total++;
|
||||||
|
|
||||||
|
// check whether farkas lemma is to be interpolated (could
|
||||||
|
// potentially miss farkas lemmas, which are interpolated,
|
||||||
|
// because we potentially don't want to use the lowest
|
||||||
|
// cut)
|
||||||
|
bool has_blue_nonred_parent = false;
|
||||||
|
for (unsigned i = 0; i < m.get_num_parents(cur); ++i) {
|
||||||
|
proof* premise = to_app(cur->get_arg(i));
|
||||||
|
if (!is_a_marked(premise) && is_b_marked(premise)) {
|
||||||
|
has_blue_nonred_parent = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (has_blue_nonred_parent && is_a_marked(cur))
|
||||||
|
{
|
||||||
|
SASSERT(is_b_marked(cur));
|
||||||
|
fl_lowcut++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IF_VERBOSE(1, verbose_stream()
|
||||||
|
<< "\n total farkas lemmas " << fl_total
|
||||||
|
<< " farkas lemmas in lowest cut " << fl_lowcut << "\n";);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -4,60 +4,56 @@
|
||||||
#include "ast/ast.h"
|
#include "ast/ast.h"
|
||||||
|
|
||||||
namespace spacer {
|
namespace spacer {
|
||||||
typedef obj_hashtable<expr> expr_set;
|
typedef obj_hashtable<expr> expr_set;
|
||||||
typedef obj_hashtable<func_decl> func_decl_set;
|
typedef obj_hashtable<func_decl> func_decl_set;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* an iuc_proof is a proof together with information of the coloring of the axioms.
|
* An iuc_proof is a proof together with information of the
|
||||||
*/
|
* coloring of the axioms.
|
||||||
class iuc_proof
|
*/
|
||||||
{
|
class iuc_proof
|
||||||
public:
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
iuc_proof(ast_manager& m, proof* pr, expr_set& b_conjuncts);
|
// Constructs an iuc_proof given an ast_manager, a proof, and a set of
|
||||||
|
// literals core_lits that might be included in the unsat core
|
||||||
|
iuc_proof(ast_manager& m, proof* pr, expr_set& core_lits);
|
||||||
|
|
||||||
proof* get();
|
// returns the proof object
|
||||||
|
proof* get() {return m_pr.get();}
|
||||||
|
|
||||||
/*
|
// returns true if all uninterpreted symbols of e are from the core literals
|
||||||
* returns whether symbol contains only symbols which occur in B.
|
// requires that m_core_symbols has already been computed
|
||||||
*/
|
bool is_core_pure(expr* e) const;
|
||||||
bool only_contains_symbols_b(expr* expr) const;
|
|
||||||
|
|
||||||
bool is_a_marked(proof* p);
|
bool is_a_marked(proof* p) {return m_a_mark.is_marked(p);}
|
||||||
bool is_b_marked(proof* p);
|
bool is_b_marked(proof* p) {return m_b_mark.is_marked(p);}
|
||||||
bool is_h_marked(proof* p);
|
bool is_h_marked(proof* p) {return m_h_mark.is_marked(p);}
|
||||||
|
|
||||||
bool is_b_pure (proof *p)
|
bool is_b_pure (proof *p) {
|
||||||
{return !is_h_marked (p) && only_contains_symbols_b (m.get_fact (p));}
|
return !is_h_marked (p) && is_core_pure(m.get_fact (p));
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
// debug method
|
||||||
* print dot-representation to file proof.dot
|
void dump_farkas_stats();
|
||||||
* use Graphviz's dot with option -Tpdf to convert dot-representation into pdf
|
private:
|
||||||
*/
|
ast_manager& m;
|
||||||
void pp_dot();
|
proof_ref m_pr;
|
||||||
|
|
||||||
void print_farkas_stats();
|
ast_mark m_a_mark;
|
||||||
private:
|
ast_mark m_b_mark;
|
||||||
ast_manager& m;
|
ast_mark m_h_mark;
|
||||||
proof_ref m_pr;
|
|
||||||
|
|
||||||
ast_mark m_a_mark;
|
// symbols that occur in any literals in the core
|
||||||
ast_mark m_b_mark;
|
func_decl_set m_core_symbols;
|
||||||
ast_mark m_h_mark;
|
|
||||||
|
|
||||||
func_decl_set m_symbols_b; // symbols, which occur in any b-asserted formula
|
// collect symbols occuring in B (the core)
|
||||||
|
void collect_core_symbols(expr_set& core_lits);
|
||||||
|
|
||||||
// collect symbols occuring in B
|
// compute for each formula of the proof whether it derives
|
||||||
void collect_symbols_b(expr_set& b_conjuncts);
|
// from A or from B
|
||||||
|
void compute_marks(expr_set& core_lits);
|
||||||
// compute for each formula of the proof whether it derives from A and whether it derives from B
|
};
|
||||||
void compute_marks(expr_set& b_conjuncts);
|
|
||||||
|
|
||||||
void pp_dot_to_stream(std::ofstream& dotstream);
|
|
||||||
std::string escape_dot(const std::string &s);
|
|
||||||
|
|
||||||
void post_process_dot(std::string dot_filepath, std::ofstream& dotstream);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -289,7 +289,7 @@ void iuc_solver::get_iuc(expr_ref_vector &core)
|
||||||
{
|
{
|
||||||
iuc_proof iuc_before(m, res.get(), B);
|
iuc_proof iuc_before(m, res.get(), B);
|
||||||
verbose_stream() << "\nStats before transformation:";
|
verbose_stream() << "\nStats before transformation:";
|
||||||
iuc_before.print_farkas_stats();
|
iuc_before.dump_farkas_stats();
|
||||||
}
|
}
|
||||||
|
|
||||||
proof_utils::reduce_hypotheses(res);
|
proof_utils::reduce_hypotheses(res);
|
||||||
|
@ -299,7 +299,7 @@ void iuc_solver::get_iuc(expr_ref_vector &core)
|
||||||
{
|
{
|
||||||
iuc_proof iuc_after(m, res.get(), B);
|
iuc_proof iuc_after(m, res.get(), B);
|
||||||
verbose_stream() << "Stats after transformation:";
|
verbose_stream() << "Stats after transformation:";
|
||||||
iuc_after.print_farkas_stats();
|
iuc_after.dump_farkas_stats();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else // -- new hypothesis reducer
|
else // -- new hypothesis reducer
|
||||||
|
@ -309,7 +309,7 @@ void iuc_solver::get_iuc(expr_ref_vector &core)
|
||||||
{
|
{
|
||||||
iuc_proof iuc_before(m, res.get(), B);
|
iuc_proof iuc_before(m, res.get(), B);
|
||||||
verbose_stream() << "\nStats before transformation:";
|
verbose_stream() << "\nStats before transformation:";
|
||||||
iuc_before.print_farkas_stats();
|
iuc_before.dump_farkas_stats();
|
||||||
}
|
}
|
||||||
|
|
||||||
theory_axiom_reducer ta_reducer(m);
|
theory_axiom_reducer ta_reducer(m);
|
||||||
|
@ -324,7 +324,7 @@ void iuc_solver::get_iuc(expr_ref_vector &core)
|
||||||
{
|
{
|
||||||
iuc_proof iuc_after(m, res.get(), B);
|
iuc_proof iuc_after(m, res.get(), B);
|
||||||
verbose_stream() << "Stats after transformation:";
|
verbose_stream() << "Stats after transformation:";
|
||||||
iuc_after.print_farkas_stats();
|
iuc_after.dump_farkas_stats();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -331,11 +331,13 @@ void unsat_core_plugin_farkas_lemma::compute_linear_combination(const vector<rat
|
||||||
{
|
{
|
||||||
SASSERT(!m_learner.m_pr.is_a_marked(premise));
|
SASSERT(!m_learner.m_pr.is_a_marked(premise));
|
||||||
|
|
||||||
if (m_learner.m_pr.only_contains_symbols_b(m_learner.m.get_fact(premise)) && !m_learner.m_pr.is_h_marked(premise))
|
if (m_learner.m_pr.is_b_pure(premise))
|
||||||
{
|
{
|
||||||
rational coefficient;
|
rational coefficient;
|
||||||
VERIFY(params[i].is_rational(coefficient));
|
VERIFY(params[i].is_rational(coefficient));
|
||||||
linear_combination.push_back(std::make_pair(to_app(m_learner.m.get_fact(premise)), abs(coefficient)));
|
linear_combination.push_back
|
||||||
|
(std::make_pair(to_app(m_learner.m.get_fact(premise)),
|
||||||
|
abs(coefficient)));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue