mirror of
https://github.com/Z3Prover/z3
synced 2025-04-07 18:05:21 +00:00
151 lines
5 KiB
C++
151 lines
5 KiB
C++
/*++
|
|
Copyright (c) 2011 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
split_clause_tactic.cpp
|
|
|
|
Abstract:
|
|
|
|
Tactic that creates a subgoal for each literal in a clause (l_1 or ... or l_n).
|
|
The tactic fails if the main goal does not contain any clause.
|
|
|
|
Author:
|
|
|
|
Leonardo (leonardo) 2011-11-21
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
#include"tactical.h"
|
|
#include"split_clause_tactic.h"
|
|
|
|
class split_clause_tactic : public tactic {
|
|
bool m_largest_clause;
|
|
|
|
unsigned select_clause(ast_manager & m, goal_ref const & in) {
|
|
unsigned result_idx = UINT_MAX;
|
|
unsigned len = 0;
|
|
unsigned sz = in->size();
|
|
for (unsigned i = 0; i < sz; i++) {
|
|
expr * f = in->form(i);
|
|
if (m.is_or(f)) {
|
|
unsigned curr_len = to_app(f)->get_num_args();
|
|
if (curr_len >= 2) {
|
|
// consider only non unit clauses
|
|
if (!m_largest_clause)
|
|
return i;
|
|
if (curr_len > len) {
|
|
result_idx = i;
|
|
len = curr_len;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return result_idx;
|
|
}
|
|
|
|
class split_pc : public proof_converter {
|
|
ast_manager & m_manager;
|
|
app * m_clause;
|
|
proof * m_clause_pr;
|
|
public:
|
|
split_pc(ast_manager & m, app * cls, proof * pr):m_manager(m), m_clause(cls), m_clause_pr(pr) {
|
|
m.inc_ref(cls);
|
|
m.inc_ref(pr);
|
|
}
|
|
|
|
~split_pc() {
|
|
m_manager.dec_ref(m_clause);
|
|
m_manager.dec_ref(m_clause_pr);
|
|
}
|
|
|
|
virtual void operator()(ast_manager & m, unsigned num_source, proof * const * source, proof_ref & result) {
|
|
// Let m_clause be of the form (l_0 or ... or l_{num_source - 1})
|
|
// Each source[i] proof is a proof for "false" using l_i as a hypothesis
|
|
// So, I use lemma for producing a proof for (not l_i) that does not contain the hypothesis,
|
|
// and unit_resolution for building a proof for the goal.
|
|
SASSERT(num_source == m_clause->get_num_args());
|
|
proof_ref_buffer prs(m);
|
|
prs.push_back(m_clause_pr);
|
|
for (unsigned i = 0; i < num_source; i++) {
|
|
proof * pr_i = source[i];
|
|
expr * not_li = m.mk_not(m_clause->get_arg(i));
|
|
prs.push_back(m.mk_lemma(pr_i, not_li));
|
|
}
|
|
result = m.mk_unit_resolution(prs.size(), prs.c_ptr());
|
|
}
|
|
|
|
virtual proof_converter * translate(ast_translation & translator) {
|
|
return alloc(split_pc, translator.to(), translator(m_clause), translator(m_clause_pr));
|
|
}
|
|
};
|
|
|
|
public:
|
|
split_clause_tactic(params_ref const & ref = params_ref()) {
|
|
updt_params(ref);
|
|
}
|
|
|
|
virtual tactic * translate(ast_manager & m) {
|
|
split_clause_tactic * t = alloc(split_clause_tactic);
|
|
t->m_largest_clause = m_largest_clause;
|
|
return t;
|
|
}
|
|
|
|
virtual ~split_clause_tactic() {
|
|
}
|
|
|
|
virtual void updt_params(params_ref const & p) {
|
|
m_largest_clause = p.get_bool(":split-largest-clause", false);
|
|
}
|
|
|
|
virtual void collect_param_descrs(param_descrs & r) {
|
|
r.insert(":split-largest-clause", CPK_BOOL, "(default: false) split the largest clause in the goal.");
|
|
}
|
|
|
|
virtual void operator()(goal_ref const & in,
|
|
goal_ref_buffer & result,
|
|
model_converter_ref & mc,
|
|
proof_converter_ref & pc,
|
|
expr_dependency_ref & core) {
|
|
SASSERT(in->is_well_sorted());
|
|
tactic_report report("split-clause", *in);
|
|
TRACE("before_split_clause", in->display(tout););
|
|
pc = 0; mc = 0; core = 0;
|
|
ast_manager & m = in->m();
|
|
unsigned cls_pos = select_clause(m, in);
|
|
if (cls_pos == UINT_MAX) {
|
|
throw tactic_exception("split-clause tactic failed, goal does not contain any clause");
|
|
}
|
|
bool produce_proofs = in->proofs_enabled();
|
|
app * cls = to_app(in->form(cls_pos));
|
|
expr_dependency * cls_dep = in->dep(cls_pos);
|
|
if (produce_proofs)
|
|
pc = alloc(split_pc, m, cls, in->pr(cls_pos));
|
|
unsigned cls_sz = cls->get_num_args();
|
|
report_tactic_progress(":num-new-branches", cls_sz);
|
|
for (unsigned i = 0; i < cls_sz; i++) {
|
|
goal * subgoal_i;
|
|
if (i == cls_sz - 1)
|
|
subgoal_i = in.get();
|
|
else
|
|
subgoal_i = alloc(goal, *in);
|
|
expr * lit_i = cls->get_arg(i);
|
|
proof * pr_i = 0;
|
|
if (produce_proofs)
|
|
pr_i = m.mk_hypothesis(lit_i);
|
|
subgoal_i->update(cls_pos, lit_i, pr_i, cls_dep);
|
|
subgoal_i->inc_depth();
|
|
result.push_back(subgoal_i);
|
|
}
|
|
}
|
|
|
|
virtual void cleanup() {
|
|
// do nothing this tactic is too simple
|
|
}
|
|
};
|
|
|
|
tactic * mk_split_clause_tactic(params_ref const & p) {
|
|
return clean(alloc(split_clause_tactic, p));
|
|
}
|