3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-24 01:25:31 +00:00
This commit is contained in:
Nikolaj Bjorner 2017-06-01 14:50:37 -07:00
commit 55ba1e9178
52 changed files with 877 additions and 311 deletions

View file

@ -42,7 +42,8 @@ namespace sat {
stats() { reset(); }
void reset() { memset(this, 0, sizeof(*this)); }
};
public:
class card {
unsigned m_index;
literal m_lit;
@ -105,6 +106,7 @@ namespace sat {
void swap(unsigned i, unsigned j) { std::swap(m_lits[i], m_lits[j]); }
void negate() { m_lits[0].neg(); }
};
protected:
struct ineq {
literal_vector m_lits;
@ -304,6 +306,13 @@ namespace sat {
void add_at_least(bool_var v, literal_vector const& lits, unsigned k);
void add_pb_ge(bool_var v, svector<wliteral> const& wlits, unsigned k);
void add_xor(bool_var v, literal_vector const& lits);
unsigned num_pb() const { return m_pbs.size(); }
pb const& get_pb(unsigned i) const { return *m_pbs[i]; }
unsigned num_card() const { return m_cards.size(); }
card const& get_card(unsigned i) const { return *m_cards[i]; }
unsigned num_xor() const { return m_xors.size(); }
xor const& get_xor(unsigned i) const { return *m_xors[i]; }
virtual void propagate(literal l, ext_constraint_idx idx, bool & keep);
virtual bool resolve_conflict();
virtual void get_antecedents(literal l, ext_justification_idx idx, literal_vector & r);

View file

@ -126,6 +126,27 @@ namespace sat {
m_drat_file = p.drat_file();
m_drat = (m_drat_check || m_drat_file != symbol("")) && p.threads() == 1;
m_dyn_sub_res = p.dyn_sub_res();
// Parameters used in Liang, Ganesh, Poupart, Czarnecki AAAI 2016.
m_branching_heuristic = BH_VSIDS;
if (p.branching_heuristic() == symbol("vsids")) {
m_branching_heuristic = BH_VSIDS;
}
else if (p.branching_heuristic() == symbol("chb")) {
m_branching_heuristic = BH_CHB;
}
else if (p.branching_heuristic() == symbol("lrb")) {
m_branching_heuristic = BH_LRB;
}
else {
throw sat_param_exception("invalid branching heuristic: accepted heuristics are 'vsids', 'lrb' or 'chb'");
}
m_anti_exploration = m_branching_heuristic != BH_VSIDS;
m_step_size_init = 0.40;
m_step_size_dec = 0.000001;
m_step_size_min = 0.06;
m_reward_multiplier = 0.9;
m_reward_offset = 1000000.0;
}
void config::collect_param_descrs(param_descrs & r) {

View file

@ -44,6 +44,12 @@ namespace sat {
GC_PSM_GLUE
};
enum branching_heuristic {
BH_VSIDS,
BH_CHB,
BH_LRB
};
struct config {
unsigned long long m_max_memory;
phase_selection m_phase;
@ -95,6 +101,14 @@ namespace sat {
symbol m_glue_psm;
symbol m_psm_glue;
// branching heuristic settings.
branching_heuristic m_branching_heuristic;
bool m_anti_exploration;
double m_step_size_init;
double m_step_size_dec;
double m_step_size_min;
double m_reward_multiplier;
double m_reward_offset;
config(params_ref const & p);
void updt_params(params_ref const & p);
static void collect_param_descrs(param_descrs & d);

View file

@ -46,7 +46,7 @@ namespace sat {
virtual std::ostream& display(std::ostream& out) const = 0;
virtual std::ostream& display_justification(std::ostream& out, ext_justification_idx idx) const = 0;
virtual void collect_statistics(statistics& st) const = 0;
virtual extension* copy(solver* s) = 0;
virtual extension* copy(solver* s) = 0;
virtual void find_mutexes(literal_vector& lits, vector<literal_vector> & mutexes) = 0;
};

View file

@ -384,6 +384,7 @@ namespace sat {
candidate(bool_var v, float r): m_var(v), m_rating(r) {}
};
svector<candidate> m_candidates;
uint_set m_select_lookahead_vars;
float get_rating(bool_var v) const { return m_rating[v]; }
float get_rating(literal l) const { return get_rating(l.var()); }
@ -468,7 +469,11 @@ namespace sat {
for (bool_var const* it = m_freevars.begin(), * end = m_freevars.end(); it != end; ++it) {
SASSERT(is_undef(*it));
bool_var x = *it;
if (newbies || active_prefix(x)) {
if (!m_select_lookahead_vars.empty() && m_select_lookahead_vars.contains(x)) {
m_candidates.push_back(candidate(x, m_rating[x]));
sum += m_rating[x];
}
else if (newbies || active_prefix(x)) {
m_candidates.push_back(candidate(x, m_rating[x]));
sum += m_rating[x];
}
@ -1857,6 +1862,31 @@ namespace sat {
return search();
}
literal select_lookahead(bool_var_vector const& vars) {
m_search_mode = lookahead_mode::searching;
scoped_level _sl(*this, c_fixed_truth);
init();
if (inconsistent()) return null_literal;
inc_istamp();
for (auto v : vars) {
m_select_lookahead_vars.insert(v);
}
literal l = choose();
m_select_lookahead_vars.reset();
if (inconsistent()) return null_literal;
// assign unit literals that were found during search for lookahead.
unsigned num_assigned = 0;
for (literal lit : m_trail) {
if (!m_s.was_eliminated(lit.var()) && m_s.value(lit) != l_true) {
m_s.assign(lit, justification());
++num_assigned;
}
}
IF_VERBOSE(1, verbose_stream() << "(sat-lookahead :units " << num_assigned << ")\n";);
return l;
}
/**
\brief simplify set of clauses by extracting units from a lookahead at base level.
*/

View file

@ -9,6 +9,7 @@ def_module_params('sat',
('restart.initial', UINT, 100, 'initial restart (number of conflicts)'),
('restart.max', UINT, UINT_MAX, 'maximal number of restarts.'),
('restart.factor', DOUBLE, 1.5, 'restart increment factor for geometric strategy'),
('branching.heuristic', SYMBOL, 'vsids', 'branching heuristic vsids, lrb or chb'),
('random_freq', DOUBLE, 0.01, 'frequency of random case splits'),
('random_seed', UINT, 0, 'random seed'),
('burst_search', UINT, 100, 'number of conflicts before first global simplification'),
@ -21,8 +22,7 @@ def_module_params('sat',
('minimize_lemmas', BOOL, True, 'minimize learned clauses'),
('dyn_sub_res', BOOL, True, 'dynamic subsumption resolution for minimizing learned clauses'),
('core.minimize', BOOL, False, 'minimize computed core'),
('core.minimize_partial', BOOL, False, 'apply partial (cheap) core minimization'),
('threads', UINT, 1, 'number of parallel threads to use'),
('core.minimize_partial', BOOL, False, 'apply partial (cheap) core minimization'), ('threads', UINT, 1, 'number of parallel threads to use'),
('dimacs.core', BOOL, False, 'extract core from DIMACS benchmarks'),
('drat.file', SYMBOL, '', 'file to dump DRAT proofs'),
('drat.check', BOOL, False, 'build up internal proof and check'),

View file

@ -175,6 +175,11 @@ namespace sat {
m_phase.push_back(PHASE_NOT_AVAILABLE);
m_prev_phase.push_back(PHASE_NOT_AVAILABLE);
m_assigned_since_gc.push_back(false);
m_last_conflict.push_back(0);
m_last_propagation.push_back(0);
m_participated.push_back(0);
m_canceled.push_back(0);
m_reasoned.push_back(0);
m_case_split_queue.mk_var_eh(v);
m_simplifier.insert_elim_todo(v);
SASSERT(!was_eliminated(v));
@ -581,6 +586,29 @@ namespace sat {
if (m_ext && m_external[v])
m_ext->asserted(l);
switch (m_config.m_branching_heuristic) {
case BH_VSIDS:
break;
case BH_CHB:
m_last_propagation[v] = m_stats.m_conflict;
break;
case BH_LRB:
m_participated[v] = 0;
m_reasoned[v] = 0;
break;
}
if (m_config.m_anti_exploration) {
uint64 age = m_stats.m_conflict - m_canceled[v];
if (age > 0) {
double decay = pow(0.95, age);
m_activity[v] = static_cast<unsigned>(m_activity[v] * decay);
// NB. MapleSAT does not update canceled.
m_canceled[v] = m_stats.m_conflict;
m_case_split_queue.activity_changed_eh(v, false);
}
}
SASSERT(!l.sign() || m_phase[v] == NEG_PHASE);
SASSERT(l.sign() || m_phase[v] == POS_PHASE);
@ -772,12 +800,26 @@ namespace sat {
}
bool solver::propagate(bool update) {
unsigned qhead = m_qhead;
bool r = propagate_core(update);
if (m_config.m_branching_heuristic == BH_CHB) {
update_chb_activity(r, qhead);
}
CASSERT("sat_propagate", check_invariant());
CASSERT("sat_missed_prop", check_missed_propagation());
return r;
}
literal solver::select_lookahead(bool_var_vector const& vars) {
lookahead lh(*this);
literal result = lh.select_lookahead(vars);
if (result == null_literal) {
set_conflict(justification());
}
// extract unit literals from lh
return result;
}
// -----------------------
//
// Search
@ -1065,6 +1107,18 @@ namespace sat {
}
while (!m_case_split_queue.empty()) {
if (m_config.m_anti_exploration) {
next = m_case_split_queue.min_var();
auto age = m_stats.m_conflict - m_canceled[next];
while (age > 0) {
double decay = pow(0.95, age);
m_activity[next] = static_cast<unsigned>(m_activity[next] * pow(0.95, age));
m_case_split_queue.activity_changed_eh(next, false);
m_canceled[next] = m_stats.m_conflict;
next = m_case_split_queue.min_var();
age = m_stats.m_conflict - m_canceled[next];
}
}
next = m_case_split_queue.next_var();
if (value(next) == l_undef && !was_eliminated(next))
return next;
@ -1829,6 +1883,9 @@ namespace sat {
m_conflicts_since_restart++;
m_conflicts_since_gc++;
m_stats.m_conflict++;
if (m_step_size > m_config.m_step_size_min) {
m_step_size -= m_config.m_step_size_dec;
}
m_conflict_lvl = get_max_lvl(m_not_l, m_conflict);
TRACE("sat", tout << "conflict detected at level " << m_conflict_lvl << " for ";
@ -2176,7 +2233,16 @@ namespace sat {
SASSERT(var < num_vars());
if (!is_marked(var) && var_lvl > 0) {
mark(var);
inc_activity(var);
switch (m_config.m_branching_heuristic) {
case BH_VSIDS:
inc_activity(var);
break;
case BH_CHB:
m_last_conflict[var] = m_stats.m_conflict;
break;
default:
break;
}
if (var_lvl == m_conflict_lvl)
num_marks++;
else
@ -2432,6 +2498,9 @@ namespace sat {
\brief Reset the mark of the variables in the current lemma.
*/
void solver::reset_lemma_var_marks() {
if (m_config.m_branching_heuristic == BH_LRB) {
update_lrb_reasoned();
}
literal_vector::iterator it = m_lemma.begin();
literal_vector::iterator end = m_lemma.end();
SASSERT(!is_marked((*it).var()));
@ -2442,6 +2511,58 @@ namespace sat {
}
}
void solver::update_lrb_reasoned() {
unsigned sz = m_lemma.size();
SASSERT(!is_marked(m_lemma[0].var()));
mark(m_lemma[0].var());
for (unsigned i = m_lemma.size(); i > 0; ) {
--i;
justification js = m_justification[m_lemma[i].var()];
switch (js.get_kind()) {
case justification::NONE:
break;
case justification::BINARY:
update_lrb_reasoned(js.get_literal());
break;
case justification::TERNARY:
update_lrb_reasoned(js.get_literal1());
update_lrb_reasoned(js.get_literal2());
break;
case justification::CLAUSE: {
clause & c = *(m_cls_allocator.get_clause(js.get_clause_offset()));
for (unsigned i = 0; i < c.size(); ++i) {
update_lrb_reasoned(c[i]);
}
break;
}
case justification::EXT_JUSTIFICATION: {
fill_ext_antecedents(m_lemma[i], js);
literal_vector::iterator it = m_ext_antecedents.begin();
literal_vector::iterator end = m_ext_antecedents.end();
for (; it != end; ++it) {
update_lrb_reasoned(*it);
}
break;
}
}
}
reset_mark(m_lemma[0].var());
for (unsigned i = m_lemma.size(); i > sz; ) {
--i;
reset_mark(m_lemma[i].var());
}
m_lemma.shrink(sz);
}
void solver::update_lrb_reasoned(literal lit) {
bool_var v = lit.var();
if (!is_marked(v)) {
mark(v);
m_reasoned[v]++;
m_lemma.push_back(lit);
}
}
/**
\brief Apply dynamic subsumption resolution to new lemma.
Only binary and ternary clauses are used.
@ -2618,6 +2739,18 @@ namespace sat {
bool_var v = l.var();
SASSERT(value(v) == l_undef);
m_case_split_queue.unassign_var_eh(v);
if (m_config.m_branching_heuristic == BH_LRB) {
uint64 interval = m_stats.m_conflict - m_last_propagation[v];
if (interval > 0) {
auto activity = m_activity[v];
auto reward = (m_config.m_reward_offset * (m_participated[v] + m_reasoned[v])) / interval;
m_activity[v] = static_cast<unsigned>(m_step_size * reward + ((1 - m_step_size) * activity));
m_case_split_queue.activity_changed_eh(v, m_activity[v] > activity);
}
}
if (m_config.m_anti_exploration) {
m_canceled[v] = m_stats.m_conflict;
}
}
m_trail.shrink(old_sz);
m_qhead = old_sz;
@ -2800,6 +2933,8 @@ namespace sat {
m_probing.updt_params(p);
m_scc.updt_params(p);
m_rand.set_seed(m_config.m_random_seed);
m_step_size = m_config.m_step_size_init;
}
void solver::collect_param_descrs(param_descrs & d) {
@ -2837,6 +2972,7 @@ namespace sat {
// -----------------------
void solver::rescale_activity() {
SASSERT(m_config.m_branching_heuristic == BH_VSIDS);
svector<unsigned>::iterator it = m_activity.begin();
svector<unsigned>::iterator end = m_activity.end();
for (; it != end; ++it) {
@ -2845,6 +2981,18 @@ namespace sat {
m_activity_inc >>= 14;
}
void solver::update_chb_activity(bool is_sat, unsigned qhead) {
SASSERT(m_config.m_branching_heuristic == BH_CHB);
double multiplier = m_config.m_reward_offset * (is_sat ? m_config.m_reward_multiplier : 1.0);
for (unsigned i = qhead; i < m_trail.size(); ++i) {
auto v = m_trail[i].var();
auto reward = multiplier / (m_stats.m_conflict - m_last_conflict[v] + 1);
auto activity = m_activity[v];
m_activity[v] = static_cast<unsigned>(m_step_size * reward + ((1.0 - m_step_size) * activity));
m_case_split_queue.activity_changed_eh(v, m_activity[v] > activity);
}
}
// -----------------------
//
// Iterators

View file

@ -110,8 +110,17 @@ namespace sat {
svector<char> m_eliminated;
svector<char> m_external;
svector<unsigned> m_level;
// branch variable selection:
svector<unsigned> m_activity;
unsigned m_activity_inc;
svector<uint64> m_last_conflict;
svector<uint64> m_last_propagation;
svector<uint64> m_participated;
svector<uint64> m_canceled;
svector<uint64> m_reasoned;
int m_action;
double m_step_size;
// phase
svector<char> m_phase;
svector<char> m_prev_phase;
svector<char> m_assigned_since_gc;
@ -300,7 +309,7 @@ namespace sat {
}
void set_par(parallel* p, unsigned id);
bool canceled() { return !m_rlimit.inc(); }
config const& get_config() { return m_config; }
config const& get_config() const { return m_config; }
extension* get_extension() const { return m_ext.get(); }
void set_extension(extension* e);
typedef std::pair<literal, literal> bin_clause;
@ -343,6 +352,8 @@ namespace sat {
model_converter const & get_model_converter() const { return m_mc; }
void set_model(model const& mdl);
literal select_lookahead(bool_var_vector const& vars);
protected:
unsigned m_conflicts;
unsigned m_restarts;
@ -555,6 +566,12 @@ namespace sat {
private:
void rescale_activity();
void update_chb_activity(bool is_sat, unsigned qhead);
void update_lrb_reasoned();
void update_lrb_reasoned(literal lit);
// -----------------------
//
// Iterators

View file

@ -66,7 +66,11 @@ class inc_sat_solver : public solver {
expr_dependency_ref m_dep_core;
svector<double> m_weights;
std::string m_unknown;
// access formulas after they have been pre-processed and handled by the sat solver.
// this allows to access the internal state of the SAT solver and carry on partial results.
bool m_internalized; // are formulas internalized?
bool m_internalized_converted; // have internalized formulas been converted back
expr_ref_vector m_internalized_fmls; // formulas in internalized format
typedef obj_map<expr, sat::literal> dep2asm_t;
public:
@ -81,7 +85,10 @@ public:
m_map(m),
m_num_scopes(0),
m_dep_core(m),
m_unknown("no reason given") {
m_unknown("no reason given"),
m_internalized(false),
m_internalized_converted(false),
m_internalized_fmls(m) {
updt_params(p);
init_preprocess();
}
@ -141,6 +148,8 @@ public:
if (r != l_true) return r;
r = internalize_assumptions(sz, assumptions, dep2asm);
if (r != l_true) return r;
m_internalized = true;
m_internalized_converted = false;
r = m_solver.check(m_asms.size(), m_asms.c_ptr());
@ -170,8 +179,11 @@ public:
m_fmls_head_lim.push_back(m_fmls_head);
if (m_bb_rewriter) m_bb_rewriter->push();
m_map.push();
m_internalized = true;
m_internalized_converted = false;
}
virtual void pop(unsigned n) {
m_internalized = false;
if (n > m_num_scopes) { // allow inc_sat_solver to
n = m_num_scopes; // take over for another solver.
}
@ -204,6 +216,7 @@ public:
}
virtual ast_manager& get_manager() const { return m; }
virtual void assert_expr(expr * t) {
m_internalized = false;
TRACE("goal2sat", tout << mk_pp(t, m) << "\n";);
m_fmls.push_back(t);
}
@ -242,6 +255,28 @@ public:
return 0;
}
virtual expr_ref lookahead(expr_ref_vector const& candidates) {
sat::bool_var_vector vars;
u_map<expr*> var2candidate;
for (auto c : candidates) {
// TBD: check membership
sat::bool_var v = m_map.to_bool_var(c);
SASSERT(v != sat::null_bool_var);
vars.push_back(v);
var2candidate.insert(v, c);
}
sat::literal l = m_solver.select_lookahead(vars);
if (l == sat::null_literal) {
return expr_ref(m.mk_true(), m);
}
expr* e;
if (!var2candidate.find(l.var(), e)) {
// TBD: if candidate set is empty, then do something else.
e = m.mk_true();
}
return expr_ref(l.sign() ? m.mk_not(e) : e, m);
}
virtual lbool get_consequences_core(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq) {
init_preprocess();
TRACE("sat", tout << assumptions << "\n" << vars << "\n";);
@ -320,9 +355,18 @@ public:
virtual void get_labels(svector<symbol> & r) {
}
virtual unsigned get_num_assertions() const {
return m_fmls.size();
const_cast<inc_sat_solver*>(this)->convert_internalized();
if (m_internalized && m_internalized_converted) {
return m_internalized_fmls.size();
}
else {
return m_fmls.size();
}
}
virtual expr * get_assertion(unsigned idx) const {
if (m_internalized && m_internalized_converted) {
return m_internalized_fmls[idx];
}
return m_fmls[idx];
}
virtual unsigned get_num_assumptions() const {
@ -332,6 +376,32 @@ public:
return m_asmsf[idx];
}
void convert_internalized() {
if (!m_internalized) return;
sat2goal s2g;
model_converter_ref mc;
goal g(m, false, false, false);
s2g(m_solver, m_map, m_params, g, mc);
extract_model();
if (!m_model) {
m_model = alloc(model, m);
}
model_ref mdl = m_model;
if (m_mc) (*m_mc)(mdl);
for (unsigned i = 0; i < mdl->get_num_constants(); ++i) {
func_decl* c = mdl->get_constant(i);
expr_ref eq(m.mk_eq(m.mk_const(c), mdl->get_const_interp(c)), m);
g.assert_expr(eq);
}
m_internalized_fmls.reset();
g.get_formulas(m_internalized_fmls);
// g.display(std::cout);
m_internalized_converted = true;
// if (mc) mc->display(std::cout << "mc");
// if (m_mc) m_mc->display(std::cout << "m_mc\n");
// if (m_mc0) m_mc0->display(std::cout << "m_mc0\n");
}
void init_preprocess() {
if (m_preprocess) {
m_preprocess->reset();
@ -374,7 +444,7 @@ private:
init_preprocess();
SASSERT(g->models_enabled());
SASSERT(!g->proofs_enabled());
TRACE("goal2sat", g->display(tout););
TRACE("sat", g->display(tout););
try {
(*m_preprocess)(g, m_subgoals, m_mc, m_pc, m_dep_core);
}
@ -391,7 +461,7 @@ private:
}
g = m_subgoals[0];
expr_ref_vector atoms(m);
TRACE("goal2sat", g->display_with_dependencies(tout););
TRACE("sat", g->display_with_dependencies(tout););
m_goal2sat(*g, m_params, m_solver, m_map, dep2asm, true);
m_goal2sat.get_interpreted_atoms(atoms);
if (!atoms.empty()) {

View file

@ -39,6 +39,15 @@ namespace sat {
m_queue.decreased(v);
}
void activity_changed_eh(bool_var v, bool up) {
if (m_queue.contains(v)) {
if (up)
m_queue.decreased(v);
else
m_queue.increased(v);
}
}
void mk_var_eh(bool_var v) {
m_queue.reserve(v+1);
m_queue.insert(v);
@ -61,6 +70,8 @@ namespace sat {
bool empty() const { return m_queue.empty(); }
bool_var next_var() { SASSERT(!empty()); return m_queue.erase_min(); }
bool_var min_var() { SASSERT(!empty()); return m_queue.min_value(); }
};
};

View file

@ -137,7 +137,7 @@ struct goal2sat::imp {
sat::bool_var v = m_solver.mk_var(ext);
m_map.insert(t, v);
l = sat::literal(v, sign);
TRACE("goal2sat", tout << "new_var: " << v << "\n" << mk_ismt2_pp(t, m) << "\n";);
TRACE("sat", tout << "new_var: " << v << ": " << mk_ismt2_pp(t, m) << "\n";);
if (ext && !is_uninterp_const(t)) {
m_interpreted_atoms.push_back(t);
}
@ -993,6 +993,7 @@ struct sat2goal::imp {
expr_ref_vector m_lit2expr;
unsigned long long m_max_memory;
bool m_learned;
unsigned m_glue;
imp(ast_manager & _m, params_ref const & p):m(_m), m_lit2expr(m) {
updt_params(p);
@ -1000,6 +1001,7 @@ struct sat2goal::imp {
void updt_params(params_ref const & p) {
m_learned = p.get_bool("learned", false);
m_glue = p.get_uint("glue", UINT_MAX);
m_max_memory = megabytes_to_bytes(p.get_uint("max_memory", UINT_MAX));
}
@ -1042,20 +1044,71 @@ struct sat2goal::imp {
return m_lit2expr.get(l.index());
}
void assert_clauses(sat::clause * const * begin, sat::clause * const * end, goal & r) {
void assert_pb(goal& r, sat::card_extension::pb const& p) {
pb_util pb(m);
ptr_buffer<expr> lits;
vector<rational> coeffs;
for (unsigned i = 0; i < p.size(); ++i) {
lits.push_back(lit2expr(p[i].second));
coeffs.push_back(rational(p[i].first));
}
rational k(p.k());
expr_ref fml(pb.mk_ge(p.size(), coeffs.c_ptr(), lits.c_ptr(), k), m);
if (p.lit() != sat::null_literal) {
fml = m.mk_eq(lit2expr(p.lit()), fml);
}
r.assert_expr(fml);
}
void assert_card(goal& r, sat::card_extension::card const& c) {
pb_util pb(m);
ptr_buffer<expr> lits;
for (unsigned i = 0; i < c.size(); ++i) {
lits.push_back(lit2expr(c[i]));
}
expr_ref fml(pb.mk_at_most_k(c.size(), lits.c_ptr(), c.k()), m);
if (c.lit() != sat::null_literal) {
fml = m.mk_eq(lit2expr(c.lit()), fml);
}
r.assert_expr(fml);
}
void assert_xor(goal & r, sat::card_extension::xor const& x) {
ptr_buffer<expr> lits;
for (unsigned i = 0; i < x.size(); ++i) {
lits.push_back(lit2expr(x[i]));
}
expr_ref fml(m.mk_xor(x.size(), lits.c_ptr()), m);
if (x.lit() != sat::null_literal) {
fml = m.mk_eq(lit2expr(x.lit()), fml);
}
r.assert_expr(fml);
}
void assert_clauses(sat::solver const & s, sat::clause * const * begin, sat::clause * const * end, goal & r, bool asserted) {
ptr_buffer<expr> lits;
for (sat::clause * const * it = begin; it != end; it++) {
checkpoint();
lits.reset();
sat::clause const & c = *(*it);
unsigned sz = c.size();
for (unsigned i = 0; i < sz; i++) {
lits.push_back(lit2expr(c[i]));
if (asserted || m_learned || c.glue() <= s.get_config().m_gc_small_lbd) {
for (unsigned i = 0; i < sz; i++) {
lits.push_back(lit2expr(c[i]));
}
r.assert_expr(m.mk_or(lits.size(), lits.c_ptr()));
}
r.assert_expr(m.mk_or(lits.size(), lits.c_ptr()));
}
}
sat::card_extension* get_card_extension(sat::solver const& s) {
sat::extension* ext = s.get_extension();
return dynamic_cast<sat::card_extension*>(ext);
}
void operator()(sat::solver const & s, atom2bool_var const & map, goal & r, model_converter_ref & mc) {
if (s.inconsistent()) {
r.assert_expr(m.mk_false());
@ -1087,9 +1140,22 @@ struct sat2goal::imp {
r.assert_expr(m.mk_or(lit2expr(it->first), lit2expr(it->second)));
}
// collect clauses
assert_clauses(s.begin_clauses(), s.end_clauses(), r);
if (m_learned)
assert_clauses(s.begin_learned(), s.end_learned(), r);
assert_clauses(s, s.begin_clauses(), s.end_clauses(), r, true);
assert_clauses(s, s.begin_learned(), s.end_learned(), r, false);
// TBD: collect assertions from plugin
sat::card_extension* ext = get_card_extension(s);
if (ext) {
for (unsigned i = 0; i < ext->num_pb(); ++i) {
assert_pb(r, ext->get_pb(i));
}
for (unsigned i = 0; i < ext->num_card(); ++i) {
assert_card(r, ext->get_card(i));
}
for (unsigned i = 0; i < ext->num_xor(); ++i) {
assert_xor(r, ext->get_xor(i));
}
}
}
};
@ -1100,6 +1166,7 @@ sat2goal::sat2goal():m_imp(0) {
void sat2goal::collect_param_descrs(param_descrs & r) {
insert_max_memory(r);
r.insert("learned", CPK_BOOL, "(default: false) collect also learned clauses.");
r.insert("glue", CPK_UINT, "(default: max-int) collect learned clauses with glue level below parameter.");
}
struct sat2goal::scoped_set_imp {