mirror of
https://github.com/Z3Prover/z3
synced 2025-04-15 13:28:47 +00:00
update scoring function for tab context
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
c482ede7ff
commit
0eea0bea9a
|
@ -54,8 +54,9 @@ def_module_params('fixedpoint',
|
||||||
"if true, finite_product_relation will attempt to avoid creating inner relation with empty signature "
|
"if true, finite_product_relation will attempt to avoid creating inner relation with empty signature "
|
||||||
"by putting in half of the table columns, if it would have been empty otherwise"),
|
"by putting in half of the table columns, if it would have been empty otherwise"),
|
||||||
('print_answer', BOOL, False, 'print answer instance(s) to query'),
|
('print_answer', BOOL, False, 'print answer instance(s) to query'),
|
||||||
('print_certificate', BOOL, False, 'print certificate for reacahbility or non-reachability'),
|
('print_certificate', BOOL, False, 'print certificate for reachability or non-reachability'),
|
||||||
('print_statistics', BOOL, False, 'print statistics'),
|
('print_statistics', BOOL, False, 'print statistics'),
|
||||||
|
('tab_selection', SYMBOL, 'weight', 'selection method for tabular strategy: weight (default), first, var-use'),
|
||||||
))
|
))
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@ Revision History:
|
||||||
#include "th_rewriter.h"
|
#include "th_rewriter.h"
|
||||||
#include "datatype_decl_plugin.h"
|
#include "datatype_decl_plugin.h"
|
||||||
#include "for_each_expr.h"
|
#include "for_each_expr.h"
|
||||||
|
#include "matcher.h"
|
||||||
|
|
||||||
namespace tb {
|
namespace tb {
|
||||||
|
|
||||||
|
@ -420,17 +421,17 @@ namespace tb {
|
||||||
class rules {
|
class rules {
|
||||||
typedef obj_map<func_decl, unsigned_vector> map;
|
typedef obj_map<func_decl, unsigned_vector> map;
|
||||||
vector<ref<clause> > m_rules;
|
vector<ref<clause> > m_rules;
|
||||||
map m_index;
|
map m_index;
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
|
||||||
typedef vector<ref<clause> >::const_iterator iterator;
|
typedef vector<ref<clause> >::const_iterator iterator;
|
||||||
|
|
||||||
iterator begin() const { return m_rules.begin(); }
|
iterator begin() const { return m_rules.begin(); }
|
||||||
iterator end() const { return m_rules.end(); }
|
iterator end() const { return m_rules.end(); }
|
||||||
|
|
||||||
void init(datalog::rule_set const& rules) {
|
void init(datalog::rule_set const& rules) {
|
||||||
m_rules.reset();
|
reset();
|
||||||
m_index.reset();
|
|
||||||
datalog::rule_manager& rm = rules.get_rule_manager();
|
datalog::rule_manager& rm = rules.get_rule_manager();
|
||||||
datalog::rule_ref r(rm);
|
datalog::rule_ref r(rm);
|
||||||
datalog::rule_set::iterator it = rules.begin();
|
datalog::rule_set::iterator it = rules.begin();
|
||||||
|
@ -453,7 +454,7 @@ namespace tb {
|
||||||
e->get_data().m_value.push_back(idx);
|
e->get_data().m_value.push_back(idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned get_num_rules(func_decl* p) {
|
unsigned get_num_rules(func_decl* p) const {
|
||||||
map::obj_map_entry* e = m_index.find_core(p);
|
map::obj_map_entry* e = m_index.find_core(p);
|
||||||
if (p) {
|
if (p) {
|
||||||
return e->get_data().get_value().size();
|
return e->get_data().get_value().size();
|
||||||
|
@ -463,12 +464,25 @@ namespace tb {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void get_decls(ptr_vector<func_decl>& decls) const {
|
||||||
|
map::iterator it = m_index.begin();
|
||||||
|
map::iterator end = m_index.end();
|
||||||
|
for (; it != end; ++it) {
|
||||||
|
decls.push_back(it->m_key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ref<clause> get_rule(func_decl* p, unsigned idx) const {
|
ref<clause> get_rule(func_decl* p, unsigned idx) const {
|
||||||
map::obj_map_entry* e = m_index.find_core(p);
|
map::obj_map_entry* e = m_index.find_core(p);
|
||||||
SASSERT(p);
|
SASSERT(p);
|
||||||
unsigned rule_id = e->get_data().get_value()[idx];
|
unsigned rule_id = e->get_data().get_value()[idx];
|
||||||
return m_rules[rule_id];
|
return m_rules[rule_id];
|
||||||
}
|
}
|
||||||
|
private:
|
||||||
|
void reset() {
|
||||||
|
m_rules.reset();
|
||||||
|
m_index.reset();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -720,102 +734,240 @@ namespace tb {
|
||||||
|
|
||||||
// predicate selection strategy.
|
// predicate selection strategy.
|
||||||
class selection {
|
class selection {
|
||||||
|
enum strategy {
|
||||||
|
WEIGHT_SELECT,
|
||||||
|
FIRST_SELECT,
|
||||||
|
VAR_USE_SELECT
|
||||||
|
};
|
||||||
|
typedef svector<double> double_vector;
|
||||||
|
typedef obj_map<func_decl, double_vector> score_map;
|
||||||
datalog::context& m_ctx;
|
datalog::context& m_ctx;
|
||||||
ast_manager& m;
|
ast_manager& m;
|
||||||
datatype_util dt;
|
datatype_util dt;
|
||||||
obj_map<func_decl, unsigned_vector> m_scores;
|
score_map m_score_map;
|
||||||
unsigned_vector m_score_values;
|
double_vector m_scores;
|
||||||
|
double_vector m_var_scores;
|
||||||
|
strategy m_strategy;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
selection(datalog::context& ctx):
|
selection(datalog::context& ctx):
|
||||||
m_ctx(ctx),
|
m_ctx(ctx),
|
||||||
m(ctx.get_manager()),
|
m(ctx.get_manager()),
|
||||||
dt(m) {
|
dt(m) {
|
||||||
|
set_strategy(ctx.get_params().tab_selection());
|
||||||
}
|
}
|
||||||
|
|
||||||
void init(rules const& rs) {
|
void init(rules const& rs) {
|
||||||
m_scores.reset();
|
reset();
|
||||||
|
double_vector& scores = m_scores;
|
||||||
rules::iterator it = rs.begin(), end = rs.end();
|
rules::iterator it = rs.begin(), end = rs.end();
|
||||||
for (; it != end; ++it) {
|
for (; it != end; ++it) {
|
||||||
ref<clause> g = *it;
|
ref<clause> g = *it;
|
||||||
app* p = g->get_head();
|
app* p = g->get_head();
|
||||||
unsigned_vector scores;
|
scores.reset();
|
||||||
score_predicate(p, scores);
|
score_predicate(p, scores);
|
||||||
insert_score(p->get_decl(), scores);
|
insert_score(p->get_decl(), scores);
|
||||||
}
|
}
|
||||||
|
normalize_scores(rs);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned select(clause const& g) {
|
unsigned select(clause const& g) {
|
||||||
|
switch(m_strategy) {
|
||||||
|
case WEIGHT_SELECT:
|
||||||
|
return weight_select(g);
|
||||||
|
case FIRST_SELECT:
|
||||||
|
return trivial_select(g);
|
||||||
|
case VAR_USE_SELECT:
|
||||||
|
return andrei_select(g);
|
||||||
|
default:
|
||||||
|
return weight_select(g);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void reset() {
|
||||||
|
m_score_map.reset();
|
||||||
|
m_scores.reset();
|
||||||
|
m_var_scores.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
// determine if constructors in p are matches by rules.
|
||||||
|
bool is_reductive(app* p, double_vector const& p_scores) {
|
||||||
|
func_decl* f = p->get_decl();
|
||||||
|
score_map::obj_map_entry* e = m_score_map.find_core(p->get_decl());
|
||||||
|
if (!e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
double_vector const& scores = e->get_data().m_value;
|
||||||
|
SASSERT(scores.size() == p->get_num_args());
|
||||||
|
bool has_reductive = false;
|
||||||
|
bool is_red = true;
|
||||||
|
for (unsigned i = 0; is_red && i < scores.size(); ++i) {
|
||||||
|
if (scores[i] >= 1) {
|
||||||
|
has_reductive = true;
|
||||||
|
is_red &= p_scores[i] >= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return has_reductive && is_red;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_strategy(symbol const& str) {
|
||||||
|
if (str == symbol("weight")) {
|
||||||
|
m_strategy = WEIGHT_SELECT;
|
||||||
|
}
|
||||||
|
else if (str == symbol("first")) {
|
||||||
|
m_strategy = FIRST_SELECT;
|
||||||
|
}
|
||||||
|
else if (str == symbol("var-use")) {
|
||||||
|
m_strategy = VAR_USE_SELECT;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_strategy = WEIGHT_SELECT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned trivial_select(clause const& g) {
|
||||||
return 0;
|
return 0;
|
||||||
#if 0
|
}
|
||||||
unsigned max_score = 0;
|
|
||||||
|
unsigned andrei_select(clause const& g) {
|
||||||
|
score_variables(g);
|
||||||
|
double_vector& scores = m_scores;
|
||||||
|
double max_score = 0;
|
||||||
unsigned result = 0;
|
unsigned result = 0;
|
||||||
unsigned_vector& scores = m_score_values;
|
|
||||||
for (unsigned i = 0; i < g.get_num_predicates(); ++i) {
|
for (unsigned i = 0; i < g.get_num_predicates(); ++i) {
|
||||||
scores.reset();
|
scores.reset();
|
||||||
|
double_vector p_scores;
|
||||||
|
double score = 0;
|
||||||
app* p = g.get_predicate(i);
|
app* p = g.get_predicate(i);
|
||||||
score_predicate(p, scores);
|
score_predicate(p, scores);
|
||||||
unsigned score = compute_score(p->get_decl(), scores);
|
m_score_map.find(p->get_decl(), p_scores);
|
||||||
|
SASSERT(p_scores.empty() || p->get_num_args() == p_scores.size());
|
||||||
|
p_scores.resize(p->get_num_args());
|
||||||
|
for (unsigned j = 0; j < p->get_num_args(); ++j) {
|
||||||
|
if (is_var(p->get_arg(j))) {
|
||||||
|
unsigned idx = to_var(p->get_arg(j))->get_idx();
|
||||||
|
score += m_var_scores[idx];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
IF_VERBOSE(1, verbose_stream() << p_scores[j] << " " << scores[j] << "\n";);
|
||||||
|
score += p_scores[j]*scores[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IF_VERBOSE(1, verbose_stream() << "score: " << mk_pp(p, m) << " " << score << "\n";);
|
||||||
if (score > max_score) {
|
if (score > max_score) {
|
||||||
max_score = score;
|
max_score = score;
|
||||||
result = i;
|
result = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
IF_VERBOSE(1, verbose_stream() << "select:" << result << "\n";);
|
||||||
#endif
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void reset() {
|
unsigned weight_select(clause const& g) {
|
||||||
m_scores.reset();
|
double_vector& scores = m_scores;
|
||||||
m_score_values.reset();
|
double max_score = 0;
|
||||||
}
|
unsigned result = 0;
|
||||||
|
for (unsigned i = 0; i < g.get_num_predicates(); ++i) {
|
||||||
private:
|
scores.reset();
|
||||||
|
double score = 0;
|
||||||
unsigned compute_score(func_decl* f, unsigned_vector const& scores) {
|
app* p = g.get_predicate(i);
|
||||||
unsigned_vector f_scores;
|
score_predicate(p, scores);
|
||||||
unsigned score = 0;
|
for (unsigned j = 0; j < scores.size(); ++j) {
|
||||||
if (m_scores.find(f, f_scores)) {
|
score += scores[j];
|
||||||
SASSERT(f_scores.size() == scores.size());
|
}
|
||||||
for (unsigned i = 0; i < scores.size(); ++i) {
|
IF_VERBOSE(1, verbose_stream() << "score: " << mk_pp(p, m) << " " << score << "\n";);
|
||||||
score += scores[i]*f_scores[i];
|
if (score > max_score) {
|
||||||
|
max_score = score;
|
||||||
|
result = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// else there is no rule.
|
IF_VERBOSE(1, verbose_stream() << "select " << result << "\n";);
|
||||||
return score;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void score_variables(clause const& g) {
|
||||||
|
m_var_scores.reset();
|
||||||
|
for (unsigned i = 0; i < g.get_num_predicates(); ++i) {
|
||||||
|
app* p = g.get_predicate(i);
|
||||||
|
score_variables(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void score_variables(app* p) {
|
||||||
|
score_map::obj_map_entry* e = m_score_map.find_core(p->get_decl());
|
||||||
|
if (!e) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
double_vector& scores = e->get_data().m_value;
|
||||||
|
for (unsigned i = 0; i < p->get_num_args(); ++i) {
|
||||||
|
if (is_var(p->get_arg(i))) {
|
||||||
|
unsigned idx = to_var(p->get_arg(i))->get_idx();
|
||||||
|
if (m_var_scores.size() <= idx) {
|
||||||
|
m_var_scores.resize(idx+1);
|
||||||
|
}
|
||||||
|
m_var_scores[idx] += scores[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void normalize_scores(rules const& rs) {
|
||||||
|
ptr_vector<func_decl> decls;
|
||||||
|
rs.get_decls(decls);
|
||||||
|
for (unsigned i = 0; i < decls.size(); ++i) {
|
||||||
|
unsigned nr = rs.get_num_rules(decls[i]);
|
||||||
|
score_map::obj_map_entry& e = *m_score_map.find_core(decls[i]);
|
||||||
|
double_vector& scores = e.get_data().m_value;
|
||||||
|
for (unsigned j = 0; j < scores.size(); ++j) {
|
||||||
|
scores[j] = scores[j]/nr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void score_predicate(app* p, unsigned_vector& scores) {
|
void score_predicate(app* p, double_vector& scores) {
|
||||||
for (unsigned i = 0; i < p->get_num_args(); ++i) {
|
for (unsigned i = 0; i < p->get_num_args(); ++i) {
|
||||||
scores.push_back(score_argument(p->get_arg(i)));
|
scores.push_back(score_argument(p->get_arg(i)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned score_argument(expr* arg) {
|
unsigned score_argument(expr* arg) {
|
||||||
if (is_var(arg)) {
|
unsigned score = 0;
|
||||||
return 0;
|
score_argument(arg, score, 20);
|
||||||
}
|
return score;
|
||||||
if (m.is_value(arg)) {
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
if (is_app(arg) && dt.is_constructor(to_app(arg)->get_decl())) {
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void insert_score(func_decl* f, unsigned_vector const& scores) {
|
void score_argument(expr* arg, unsigned& score, unsigned max_score) {
|
||||||
obj_map<func_decl, unsigned_vector>::obj_map_entry* e;
|
if (score < max_score && is_app(arg)) {
|
||||||
e = m_scores.find_core(f);
|
app* a = to_app(arg);
|
||||||
|
if (dt.is_constructor(a->get_decl())) {
|
||||||
|
score += 1;
|
||||||
|
for (unsigned i = 0; i < a->get_num_args(); ++i) {
|
||||||
|
score_argument(a->get_arg(i), score, max_score);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (m.is_value(a)) {
|
||||||
|
++score;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void insert_score(func_decl* f, double_vector const& scores) {
|
||||||
|
score_map::obj_map_entry* e = m_score_map.find_core(f);
|
||||||
if (e) {
|
if (e) {
|
||||||
unsigned_vector & old_scores = e->get_data().m_value;
|
double_vector & old_scores = e->get_data().m_value;
|
||||||
SASSERT(scores.size() == old_scores.size());
|
SASSERT(scores.size() == old_scores.size());
|
||||||
for (unsigned i = 0; i < scores.size(); ++i) {
|
for (unsigned i = 0; i < scores.size(); ++i) {
|
||||||
old_scores[i] += scores[i];
|
old_scores[i] += scores[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
m_scores.insert(f, scores);
|
m_score_map.insert(f, scores);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1255,7 +1407,8 @@ namespace datalog {
|
||||||
|
|
||||||
void display_premise(tb::clause& p, std::ostream& out) {
|
void display_premise(tb::clause& p, std::ostream& out) {
|
||||||
func_decl* f = p.get_predicate(p.get_predicate_index())->get_decl();
|
func_decl* f = p.get_predicate(p.get_predicate_index())->get_decl();
|
||||||
out << "{g" << p.get_seqno() << " " << f->get_name() << " pos: " << p.get_predicate_index() << " rule: " << p.get_next_rule() << "}\n";
|
out << "{g" << p.get_seqno() << " " << f->get_name() << " pos: "
|
||||||
|
<< p.get_predicate_index() << " rule: " << p.get_next_rule() << "}\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
void display_clause(tb::clause& g, std::ostream& out) {
|
void display_clause(tb::clause& g, std::ostream& out) {
|
||||||
|
@ -1266,7 +1419,6 @@ namespace datalog {
|
||||||
scoped_proof sp(m);
|
scoped_proof sp(m);
|
||||||
proof_ref pr(m);
|
proof_ref pr(m);
|
||||||
proof_ref_vector prs(m);
|
proof_ref_vector prs(m);
|
||||||
expr_ref_vector subst(m);
|
|
||||||
ref<tb::clause> clause = get_clause();
|
ref<tb::clause> clause = get_clause();
|
||||||
ref<tb::clause> replayed_clause;
|
ref<tb::clause> replayed_clause;
|
||||||
replace_proof_converter pc(m);
|
replace_proof_converter pc(m);
|
||||||
|
@ -1293,20 +1445,26 @@ namespace datalog {
|
||||||
clause = parent;
|
clause = parent;
|
||||||
substs.push_back(s1);
|
substs.push_back(s1);
|
||||||
}
|
}
|
||||||
for (unsigned i = substs.size(); i > 0; ) {
|
IF_VERBOSE(1, display_body_insts(substs, *clause, verbose_stream()););
|
||||||
--i;
|
|
||||||
apply_subst(subst, substs[i]);
|
|
||||||
}
|
|
||||||
expr_ref body = clause->get_body();
|
|
||||||
var_subst vs(m, false);
|
|
||||||
vs(body, subst.size(), subst.c_ptr(), body);
|
|
||||||
IF_VERBOSE(1, verbose_stream() << mk_pp(body, m) << "\n";);
|
|
||||||
pc.invert();
|
pc.invert();
|
||||||
prs.push_back(m.mk_asserted(root));
|
prs.push_back(m.mk_asserted(root));
|
||||||
pc(m, 1, prs.c_ptr(), pr);
|
pc(m, 1, prs.c_ptr(), pr);
|
||||||
return pr;
|
return pr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void display_body_insts(vector<expr_ref_vector> const& substs, tb::clause const& clause, std::ostream& out) const {
|
||||||
|
expr_ref_vector subst(m);
|
||||||
|
for (unsigned i = substs.size(); i > 0; ) {
|
||||||
|
--i;
|
||||||
|
apply_subst(subst, substs[i]);
|
||||||
|
}
|
||||||
|
expr_ref body = clause.get_body();
|
||||||
|
var_subst vs(m, false);
|
||||||
|
vs(body, subst.size(), subst.c_ptr(), body);
|
||||||
|
out << mk_pp(body, m) << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
void resolve_rule(replace_proof_converter& pc, tb::clause const& r1, tb::clause const& r2,
|
void resolve_rule(replace_proof_converter& pc, tb::clause const& r1, tb::clause const& r2,
|
||||||
expr_ref_vector const& s1, expr_ref_vector const& s2, tb::clause const& res) const {
|
expr_ref_vector const& s1, expr_ref_vector const& s2, tb::clause const& res) const {
|
||||||
unsigned idx = r1.get_predicate_index();
|
unsigned idx = r1.get_predicate_index();
|
||||||
|
|
Loading…
Reference in a new issue