3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-06-25 15:23:41 +00:00

fix xor handling, and defaults for cardinality

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2017-03-09 22:44:41 +01:00
parent ac59e7b6d3
commit 5f5819f029
8 changed files with 119 additions and 50 deletions

View file

@ -419,8 +419,8 @@ struct pb2bv_rewriter::imp {
bv(m), bv(m),
m_trail(m), m_trail(m),
m_args(m), m_args(m),
m_keep_cardinality_constraints(true), m_keep_cardinality_constraints(false),
m_min_arity(8) m_min_arity(2)
{} {}
bool mk_app(bool full, func_decl * f, unsigned sz, expr * const* args, expr_ref & result) { bool mk_app(bool full, func_decl * f, unsigned sz, expr * const* args, expr_ref & result) {
@ -618,12 +618,12 @@ struct pb2bv_rewriter::imp {
m_fresh(m), m_fresh(m),
m_num_translated(0), m_num_translated(0),
m_rw(*this, m) { m_rw(*this, m) {
m_rw.keep_cardinality_constraints(p.get_bool("keep_cardinality_constraints", true)); m_rw.keep_cardinality_constraints(p.get_bool("keep_cardinality_constraints", false));
} }
void updt_params(params_ref const & p) { void updt_params(params_ref const & p) {
m_params.append(p); m_params.append(p);
m_rw.keep_cardinality_constraints(m_params.get_bool("keep_cardinality_constraints", true)); m_rw.keep_cardinality_constraints(m_params.get_bool("keep_cardinality_constraints", false));
} }
void collect_param_descrs(param_descrs& r) const { void collect_param_descrs(param_descrs& r) const {
r.insert("keep_cardinality_constraints", CPK_BOOL, "(default: true) retain cardinality constraints (don't bit-blast them) and use built-in cardinality solver"); r.insert("keep_cardinality_constraints", CPK_BOOL, "(default: true) retain cardinality constraints (don't bit-blast them) and use built-in cardinality solver");

View file

@ -270,7 +270,6 @@ namespace opt {
#endif #endif
solver& s = get_solver(); solver& s = get_solver();
s.assert_expr(m_hard_constraints); s.assert_expr(m_hard_constraints);
display_benchmark();
IF_VERBOSE(1, verbose_stream() << "(optimize:check-sat)\n";); IF_VERBOSE(1, verbose_stream() << "(optimize:check-sat)\n";);
lbool is_sat = s.check_sat(0,0); lbool is_sat = s.check_sat(0,0);
TRACE("opt", tout << "initial search result: " << is_sat << "\n";); TRACE("opt", tout << "initial search result: " << is_sat << "\n";);
@ -1002,8 +1001,9 @@ namespace opt {
TRACE("opt", tout << "Term does not evaluate " << term << "\n";); TRACE("opt", tout << "Term does not evaluate " << term << "\n";);
return false; return false;
} }
if (!m_arith.is_numeral(val, r)) { unsigned bv_size;
TRACE("opt", tout << "model does not evaluate objective to a value\n";); if (!m_arith.is_numeral(val, r) && !m_bv.is_numeral(val, r, bv_size)) {
TRACE("opt", tout << "model does not evaluate objective to a value, but to " << val << "\n";);
return false; return false;
} }
if (r != v) { if (r != v) {
@ -1199,6 +1199,9 @@ namespace opt {
} }
void context::display_benchmark() { void context::display_benchmark() {
display(verbose_stream());
return;
if (opt_params(m_params).dump_benchmarks() && if (opt_params(m_params).dump_benchmarks() &&
sat_enabled() && sat_enabled() &&
m_objectives.size() == 1 && m_objectives.size() == 1 &&
@ -1208,6 +1211,8 @@ namespace opt {
unsigned sz = o.m_terms.size(); unsigned sz = o.m_terms.size();
inc_sat_display(verbose_stream(), get_solver(), sz, o.m_terms.c_ptr(), o.m_weights.c_ptr()); inc_sat_display(verbose_stream(), get_solver(), sz, o.m_terms.c_ptr(), o.m_weights.c_ptr());
} }
} }
void context::display(std::ostream& out) { void context::display(std::ostream& out) {

View file

@ -146,7 +146,7 @@ namespace sat {
set_conflict(c, lit); set_conflict(c, lit);
break; break;
default: default:
m_stats.m_num_propagations++; m_stats.m_num_card_propagations++;
m_num_propagations_since_pop++; m_num_propagations_since_pop++;
//TRACE("sat", tout << "#prop: " << m_stats.m_num_propagations << " - " << c.lit() << " => " << lit << "\n";); //TRACE("sat", tout << "#prop: " << m_stats.m_num_propagations << " - " << c.lit() << " => " << lit << "\n";);
SASSERT(validate_unit_propagation(c)); SASSERT(validate_unit_propagation(c));
@ -183,8 +183,10 @@ namespace sat {
} }
void card_extension::set_conflict(card& c, literal lit) { void card_extension::set_conflict(card& c, literal lit) {
m_stats.m_num_card_conflicts++;
TRACE("sat", display(tout, c, true); ); TRACE("sat", display(tout, c, true); );
SASSERT(validate_conflict(c)); SASSERT(validate_conflict(c));
SASSERT(value(lit) == l_false);
s().set_conflict(justification::mk_ext_justification(c.index()), ~lit); s().set_conflict(justification::mk_ext_justification(c.index()), ~lit);
SASSERT(s().inconsistent()); SASSERT(s().inconsistent());
} }
@ -223,6 +225,7 @@ namespace sat {
if (x.lit() != null_literal && x.lit().sign() == is_true) { if (x.lit() != null_literal && x.lit().sign() == is_true) {
x.negate(); x.negate();
} }
TRACE("sat", display(tout, x, true););
unsigned sz = x.size(); unsigned sz = x.size();
unsigned j = 0; unsigned j = 0;
for (unsigned i = 0; i < sz && j < 2; ++i) { for (unsigned i = 0; i < sz && j < 2; ++i) {
@ -234,7 +237,16 @@ namespace sat {
switch (j) { switch (j) {
case 0: case 0:
if (!parity(x, 0)) { if (!parity(x, 0)) {
set_conflict(x, x[0]); literal_set litset;
for (unsigned i = 0; i < sz; ++i) {
litset.insert(x[i]);
}
literal_vector const& lits = s().m_trail;
unsigned idx = lits.size()-1;
while (!litset.contains(lits[idx])) {
--idx;
}
set_conflict(x, lits[idx]);
} }
break; break;
case 1: case 1:
@ -249,14 +261,16 @@ namespace sat {
} }
void card_extension::assign(xor& x, literal lit) { void card_extension::assign(xor& x, literal lit) {
SASSERT(!s().inconsistent());
switch (value(lit)) { switch (value(lit)) {
case l_true: case l_true:
break; break;
case l_false: case l_false:
set_conflict(x, lit); set_conflict(x, lit);
SASSERT(s().inconsistent());
break; break;
default: default:
m_stats.m_num_propagations++; m_stats.m_num_xor_propagations++;
m_num_propagations_since_pop++; m_num_propagations_since_pop++;
if (s().m_config.m_drat) { if (s().m_config.m_drat) {
svector<drat::premise> ps; svector<drat::premise> ps;
@ -269,6 +283,7 @@ namespace sat {
ps.push_back(drat::premise(drat::s_ext(), x.lit())); ps.push_back(drat::premise(drat::s_ext(), x.lit()));
s().m_drat.add(lits, ps); s().m_drat.add(lits, ps);
} }
TRACE("sat", display(tout << lit << " ", x, true););
s().assign(lit, justification::mk_ext_justification(x.index())); s().assign(lit, justification::mk_ext_justification(x.index()));
break; break;
} }
@ -290,8 +305,11 @@ namespace sat {
void card_extension::set_conflict(xor& x, literal lit) { void card_extension::set_conflict(xor& x, literal lit) {
m_stats.m_num_xor_conflicts++;
TRACE("sat", display(tout, x, true); ); TRACE("sat", display(tout, x, true); );
if (value(lit) == l_true) lit.neg();
SASSERT(validate_conflict(x)); SASSERT(validate_conflict(x));
TRACE("sat", display(tout << lit << " ", x, true););
s().set_conflict(justification::mk_ext_justification(x.index()), ~lit); s().set_conflict(justification::mk_ext_justification(x.index()), ~lit);
SASSERT(s().inconsistent()); SASSERT(s().inconsistent());
} }
@ -332,7 +350,7 @@ namespace sat {
assign(x, p ? ~x[0] : x[0]); assign(x, p ? ~x[0] : x[0]);
} }
else if (!parity(x, 0)) { else if (!parity(x, 0)) {
set_conflict(x, x[0]); set_conflict(x, ~x[1]);
} }
return s().inconsistent() ? l_false : l_true; return s().inconsistent() ? l_false : l_true;
} }
@ -410,6 +428,7 @@ namespace sat {
m_bound = 0; m_bound = 0;
literal consequent = s().m_not_l; literal consequent = s().m_not_l;
justification js = s().m_conflict; justification js = s().m_conflict;
TRACE("sat", tout << consequent << " " << js << "\n";);
m_conflict_lvl = s().get_max_lvl(consequent, js); m_conflict_lvl = s().get_max_lvl(consequent, js);
if (consequent != null_literal) { if (consequent != null_literal) {
consequent.neg(); consequent.neg();
@ -418,7 +437,6 @@ namespace sat {
literal_vector const& lits = s().m_trail; literal_vector const& lits = s().m_trail;
unsigned idx = lits.size()-1; unsigned idx = lits.size()-1;
int offset = 1; int offset = 1;
DEBUG_CODE(active2pb(m_A);); DEBUG_CODE(active2pb(m_A););
unsigned init_marks = m_num_marks; unsigned init_marks = m_num_marks;
@ -490,17 +508,18 @@ namespace sat {
card& c = index2card(index); card& c = index2card(index);
m_bound += offset * c.k(); m_bound += offset * c.k();
process_card(c, offset); process_card(c, offset);
++m_stats.m_num_card_resolves;
} }
else { else {
// jus.push_back(js); // jus.push_back(js);
m_lemma.reset(); m_lemma.reset();
m_bound += offset; m_bound += offset;
inc_coeff(consequent, offset); inc_coeff(consequent, offset);
get_xor_antecedents(idx, m_lemma); get_xor_antecedents(consequent, idx, js, m_lemma);
// get_antecedents(consequent, index, m_lemma);
for (unsigned i = 0; i < m_lemma.size(); ++i) { for (unsigned i = 0; i < m_lemma.size(); ++i) {
process_antecedent(~m_lemma[i], offset); process_antecedent(~m_lemma[i], offset);
} }
++m_stats.m_num_xor_resolves;
} }
break; break;
} }
@ -666,7 +685,6 @@ namespace sat {
CTRACE("sat", s().is_marked(m_lemma[i].var()), tout << "marked: " << m_lemma[i] << "\n";); CTRACE("sat", s().is_marked(m_lemma[i].var()), tout << "marked: " << m_lemma[i] << "\n";);
s().mark(m_lemma[i].var()); s().mark(m_lemma[i].var());
} }
m_stats.m_num_conflicts++;
return true; return true;
@ -797,19 +815,17 @@ namespace sat {
The idea is to collect premises based on xor resolvents. The idea is to collect premises based on xor resolvents.
Variables that are repeated an even number of times cancel out. Variables that are repeated an even number of times cancel out.
*/ */
void card_extension::get_xor_antecedents(unsigned index, literal_vector& r) { void card_extension::get_xor_antecedents(literal l, unsigned index, justification js, literal_vector& r) {
literal_vector const& lits = s().m_trail;
literal l = lits[index + 1];
unsigned level = lvl(l); unsigned level = lvl(l);
bool_var v = l.var(); bool_var v = l.var();
SASSERT(s().m_justification[v].get_kind() == justification::EXT_JUSTIFICATION); SASSERT(js.get_kind() == justification::EXT_JUSTIFICATION);
SASSERT(!is_card_index(s().m_justification[v].get_ext_justification_idx())); SASSERT(!is_card_index(js.get_ext_justification_idx()));
TRACE("sat", tout << l << ": " << js << "\n"; tout << s().m_trail << "\n";);
unsigned num_marks = 0; unsigned num_marks = 0;
unsigned count = 0; unsigned count = 0;
while (true) { while (true) {
++count; ++count;
justification js = s().m_justification[v];
if (js.get_kind() == justification::EXT_JUSTIFICATION) { if (js.get_kind() == justification::EXT_JUSTIFICATION) {
unsigned idx = js.get_ext_justification_idx(); unsigned idx = js.get_ext_justification_idx();
if (is_card_index(idx)) { if (is_card_index(idx)) {
@ -838,7 +854,7 @@ namespace sat {
r.push_back(l); r.push_back(l);
} }
while (num_marks > 0) { while (num_marks > 0) {
l = lits[index]; l = s().m_trail[index];
v = l.var(); v = l.var();
unsigned n = get_parity(v); unsigned n = get_parity(v);
if (n > 0) { if (n > 0) {
@ -859,6 +875,7 @@ namespace sat {
} }
--index; --index;
--num_marks; --num_marks;
js = s().m_justification[v];
} }
// now walk the defined literals // now walk the defined literals
@ -874,6 +891,7 @@ namespace sat {
reset_parity(lit.var()); reset_parity(lit.var());
} }
m_parity_trail.reset(); m_parity_trail.reset();
TRACE("sat", tout << r << "\n";);
} }
void card_extension::get_antecedents(literal l, ext_justification_idx idx, literal_vector & r) { void card_extension::get_antecedents(literal l, ext_justification_idx idx, literal_vector & r) {
@ -1274,8 +1292,12 @@ namespace sat {
} }
void card_extension::collect_statistics(statistics& st) const { void card_extension::collect_statistics(statistics& st) const {
st.update("cardinality propagations", m_stats.m_num_propagations); st.update("cardinality propagations", m_stats.m_num_card_propagations);
st.update("cardinality conflicts", m_stats.m_num_conflicts); st.update("cardinality conflicts", m_stats.m_num_card_conflicts);
st.update("cardinality resolves", m_stats.m_num_card_resolves);
st.update("xor propagations", m_stats.m_num_xor_propagations);
st.update("xor conflicts", m_stats.m_num_xor_conflicts);
st.update("xor resolves", m_stats.m_num_xor_resolves);
} }
bool card_extension::validate_conflict(card& c) { bool card_extension::validate_conflict(card& c) {
@ -1310,6 +1332,7 @@ namespace sat {
val += coeff; val += coeff;
} }
} }
CTRACE("sat", val >= 0, active2pb(m_A); display(tout, m_A););
return val < 0; return val < 0;
} }

View file

@ -30,8 +30,12 @@ namespace sat {
friend class local_search; friend class local_search;
struct stats { struct stats {
unsigned m_num_propagations; unsigned m_num_card_propagations;
unsigned m_num_conflicts; unsigned m_num_card_conflicts;
unsigned m_num_card_resolves;
unsigned m_num_xor_propagations;
unsigned m_num_xor_conflicts;
unsigned m_num_xor_resolves;
stats() { reset(); } stats() { reset(); }
void reset() { memset(this, 0, sizeof(*this)); } void reset() { memset(this, 0, sizeof(*this)); }
}; };
@ -172,7 +176,7 @@ namespace sat {
bool is_card_index(unsigned idx) const { return 0 == (idx & 0x1); } bool is_card_index(unsigned idx) const { return 0 == (idx & 0x1); }
card& index2card(unsigned idx) const { SASSERT(is_card_index(idx)); return *m_cards[idx >> 1]; } card& index2card(unsigned idx) const { SASSERT(is_card_index(idx)); return *m_cards[idx >> 1]; }
xor& index2xor(unsigned idx) const { SASSERT(!is_card_index(idx)); return *m_xors[idx >> 1]; } xor& index2xor(unsigned idx) const { SASSERT(!is_card_index(idx)); return *m_xors[idx >> 1]; }
void get_xor_antecedents(unsigned index, literal_vector& r); void get_xor_antecedents(literal l, unsigned inddex, justification js, literal_vector& r);
template<typename T> template<typename T>

View file

@ -42,6 +42,7 @@ namespace sat {
m_index_in_unsat_stack.resize(num_constraints(), 0); m_index_in_unsat_stack.resize(num_constraints(), 0);
coefficient_in_ob_constraint.resize(num_vars() + 1, 0); coefficient_in_ob_constraint.resize(num_vars() + 1, 0);
if (m_config.mode() == local_search_mode::gsat) {
uint_set is_neighbor; uint_set is_neighbor;
for (bool_var v = 0; v < num_vars(); ++v) { for (bool_var v = 0; v < num_vars(); ++v) {
is_neighbor.reset(); is_neighbor.reset();
@ -59,6 +60,7 @@ namespace sat {
} }
} }
} }
}
for (unsigned i = 0; i < ob_constraint.size(); ++i) for (unsigned i = 0; i < ob_constraint.size(); ++i)
coefficient_in_ob_constraint[ob_constraint[i].var_id] = ob_constraint[i].coefficient; coefficient_in_ob_constraint[ob_constraint[i].var_id] = ob_constraint[i].coefficient;
@ -69,7 +71,7 @@ namespace sat {
void local_search::init_cur_solution() { void local_search::init_cur_solution() {
for (unsigned v = 0; v < num_vars(); ++v) { for (unsigned v = 0; v < num_vars(); ++v) {
// use bias half the time. // use bias half the time.
if (m_rand() % 100 < 50) { if (m_rand() % 100 < 10) {
m_vars[v].m_value = ((unsigned)(m_rand() % 100) < m_vars[v].m_bias); m_vars[v].m_value = ((unsigned)(m_rand() % 100) < m_vars[v].m_bias);
} }
} }

View file

@ -100,7 +100,8 @@ namespace sat {
vector<watch_list> m_watches; // literal: watch structure vector<watch_list> m_watches; // literal: watch structure
svector<lit_info> m_lits; // literal: attributes. svector<lit_info> m_lits; // literal: attributes.
float m_weighted_new_binaries; // metric associated with current lookahead1 literal. float m_weighted_new_binaries; // metric associated with current lookahead1 literal.
svector<prefix> m_prefix; // var: prefix where variable participates in propagation unsigned m_prefix; // where we are in search tree
svector<prefix> m_vprefix; // var: prefix where variable participates in propagation
indexed_uint_set m_freevars; indexed_uint_set m_freevars;
svector<search_mode> m_search_modes; // stack of modes svector<search_mode> m_search_modes; // stack of modes
search_mode m_search_mode; // mode of search search_mode m_search_mode; // mode of search
@ -131,6 +132,34 @@ namespace sat {
} }
}; };
// ----------------------------------------
// prefix updates. I use low order bits and
// skip bit 0 in a bid to reduce details.
void flip_prefix() {
if (m_trail_lim.size() < 32) {
unsigned mask = (1 << m_trail_lim.size());
m_prefix &= mask | (mask - 1);
}
}
void prune_prefix() {
if (m_trail_lim.size() < 32) {
m_prefix &= (1 << m_trail_lim.size()) - 1;
}
}
void update_prefix(literal l) {
bool_var x = l.var();
unsigned p = m_prefix[x].m_prefix;
if (m_prefix[x].m_length >= m_trail_lim.size() ||
((p | m_prefix) != m_prefix)) {
m_prefix[x].m_length = m_trail_lim.size();
m_prefix[x].m_prefix = m_prefix;
}
}
// ---------------------------------------- // ----------------------------------------
void add_binary(literal l1, literal l2) { void add_binary(literal l1, literal l2) {
@ -222,6 +251,8 @@ namespace sat {
assign(v); // v \/ ~u, u \/ v => v is a unit literal assign(v); // v \/ ~u, u \/ v => v is a unit literal
} }
else if (add_tc1(v, u)) { else if (add_tc1(v, u)) {
update_prefix(u);
update_prefix(v);
add_binary(u, v); add_binary(u, v);
} }
} }
@ -715,7 +746,7 @@ namespace sat {
m_lits.push_back(lit_info()); m_lits.push_back(lit_info());
m_lits.push_back(lit_info()); m_lits.push_back(lit_info());
m_rating.push_back(0); m_rating.push_back(0);
m_prefix.push_back(prefix()); m_vprefix.push_back(prefix());
m_freevars.insert(v); m_freevars.insert(v);
} }
@ -1155,6 +1186,7 @@ namespace sat {
bool backtrack(literal_vector& trail) { bool backtrack(literal_vector& trail) {
if (trail.empty()) return false; if (trail.empty()) return false;
pop(); pop();
flip_prefix();
assign(~trail.back()); assign(~trail.back());
propagate(); propagate();
trail.pop_back(); trail.pop_back();
@ -1221,6 +1253,7 @@ namespace sat {
} }
std::ostream& display(std::ostream& out) const { std::ostream& display(std::ostream& out) const {
out << std::hex << "Prefix: " << m_prefix << std::dec << "\n";
display_values(out); display_values(out);
display_binary(out); display_binary(out);
display_clauses(out); display_clauses(out);

View file

@ -48,6 +48,7 @@ public:
} }
virtual void collect_param_descrs(param_descrs & r) { virtual void collect_param_descrs(param_descrs & r) {
r.insert("keep_cardinality_constraints", CPK_BOOL, "(default: true) retain cardinality constraints for solver");
} }

View file

@ -282,6 +282,7 @@ void * memory::allocate(size_t s) {
if (g_memory_thread_alloc_size > SYNCH_THRESHOLD) { if (g_memory_thread_alloc_size > SYNCH_THRESHOLD) {
synchronize_counters(true); synchronize_counters(true);
} }
return static_cast<size_t*>(r) + 1; // we return a pointer to the location after the extra field return static_cast<size_t*>(r) + 1; // we return a pointer to the location after the extra field
} }