3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-23 09:05:31 +00:00

merge with opt

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2018-04-30 08:27:54 -07:00
commit 859c68c2ac
58 changed files with 1329 additions and 526 deletions

View file

@ -2245,8 +2245,8 @@ namespace sat {
IF_VERBOSE(0,
verbose_stream() << "Discrepancy of watched literal: " << l << " id: " << c.id()
<< " clause: " << c << (found?" is watched, but shouldn't be":" not watched, but should be") << "\n";
display_watch_list(verbose_stream() << l << ": ", s().m_cls_allocator, get_wlist(l)) << "\n";
display_watch_list(verbose_stream() << ~l << ": ", s().m_cls_allocator, get_wlist(~l)) << "\n";
s().display_watch_list(verbose_stream() << l << ": ", get_wlist(l)) << "\n";
s().display_watch_list(verbose_stream() << ~l << ": ", get_wlist(~l)) << "\n";
verbose_stream() << "value: " << value(l) << " level: " << lvl(l) << "\n";
display(verbose_stream(), c, true);
if (c.lit() != null_literal) verbose_stream() << value(c.lit()) << "\n";);

101
src/sat/sat_allocator.h Normal file
View file

@ -0,0 +1,101 @@
/*++
Copyright (c) 2018 Microsoft Corporation
Module Name:
sat_allocator.h
Abstract:
Small object allocator suitable for clauses
Author:
Nikolaj bjorner (nbjorner) 2018-04-26.
Revision History:
--*/
#ifndef SAT_ALLOCATOR_H_
#define SAT_ALLOCATOR_H_
#include "util/vector.h"
#include "util/machine.h"
class sat_allocator {
static const unsigned CHUNK_SIZE = (1 << 16);
static const unsigned SMALL_OBJ_SIZE = 512;
static const unsigned MASK = ((1 << PTR_ALIGNMENT) - 1);
static const unsigned NUM_FREE = 1 + (SMALL_OBJ_SIZE >> PTR_ALIGNMENT);
struct chunk {
char * m_curr;
char m_data[CHUNK_SIZE];
chunk():m_curr(m_data) {}
};
ptr_vector<chunk> m_chunks;
void * m_chunk_ptr;
ptr_vector<void> m_free[NUM_FREE];
size_t m_alloc_size;
char const * m_id;
unsigned align_size(size_t sz) const {
return free_slot_id(sz) << PTR_ALIGNMENT;
}
unsigned free_slot_id(size_t size) const {
return (static_cast<unsigned>(size >> PTR_ALIGNMENT) + ((0 != (size & MASK)) ? 1u : 0u));
}
public:
sat_allocator(char const * id = "unknown"): m_id(id), m_alloc_size(0), m_chunk_ptr(nullptr) {}
~sat_allocator() { reset(); }
void reset() {
for (chunk * ch : m_chunks) dealloc(ch);
m_chunks.reset();
for (unsigned i = 0; i < NUM_FREE; ++i) m_free[i].reset();
m_alloc_size = 0;
m_chunk_ptr = nullptr;
}
void * allocate(size_t size) {
m_alloc_size += size;
if (size >= SMALL_OBJ_SIZE) {
return memory::allocate(size);
}
unsigned slot_id = free_slot_id(size);
if (!m_free[slot_id].empty()) {
void* result = m_free[slot_id].back();
m_free[slot_id].pop_back();
return result;
}
if (m_chunks.empty()) {
m_chunks.push_back(alloc(chunk));
m_chunk_ptr = m_chunks.back();
}
unsigned sz = align_size(size);
if ((char*)m_chunk_ptr + sz > (char*)m_chunks.back() + CHUNK_SIZE) {
m_chunks.push_back(alloc(chunk));
m_chunk_ptr = m_chunks.back();
}
void * result = m_chunk_ptr;
m_chunk_ptr = (char*)m_chunk_ptr + sz;
return result;
}
void deallocate(size_t size, void * p) {
m_alloc_size -= size;
if (size >= SMALL_OBJ_SIZE) {
memory::deallocate(p);
}
else {
m_free[free_slot_id(size)].push_back(p);
}
}
size_t get_allocation_size() const { return m_alloc_size; }
};
inline void * operator new(size_t s, sat_allocator & r) { return r.allocate(s); }
inline void * operator new[](size_t s, sat_allocator & r) { return r.allocate(s); }
inline void operator delete(void * p, sat_allocator & r) { UNREACHABLE(); }
inline void operator delete[](void * p, sat_allocator & r) { UNREACHABLE(); }
#endif /* SAT_ALLOCATOR_H_ */

View file

@ -108,7 +108,6 @@ namespace sat {
int64 limit = -m_asymm_branch_limit;
std::stable_sort(clauses.begin(), clauses.end(), clause_size_lt());
m_counter -= clauses.size();
SASSERT(s.m_qhead == s.m_trail.size());
clause_vector::iterator it = clauses.begin();
clause_vector::iterator it2 = it;
clause_vector::iterator end = clauses.end();
@ -120,7 +119,6 @@ namespace sat {
}
break;
}
SASSERT(s.m_qhead == s.m_trail.size());
clause & c = *(*it);
if (m_counter < limit || s.inconsistent() || c.was_removed()) {
*it2 = *it;
@ -335,13 +333,18 @@ namespace sat {
if (!m_to_delete.empty()) {
unsigned j = 0;
for (unsigned i = 0; i < c.size(); ++i) {
if (!m_to_delete.contains(c[i])) {
c[j] = c[i];
++j;
}
else {
m_pos.erase(c[i]);
m_neg.erase(~c[i]);
literal lit = c[i];
switch (s.value(lit)) {
case l_true:
scoped_d.del_clause();
return false;
case l_false:
break;
default:
if (!m_to_delete.contains(lit)) {
c[j++] = lit;
}
break;
}
}
return re_attach(scoped_d, c, j);
@ -361,6 +364,7 @@ namespace sat {
}
bool asymm_branch::flip_literal_at(clause const& c, unsigned flip_index, unsigned& new_sz) {
VERIFY(s.m_trail.size() == s.m_qhead);
bool found_conflict = false;
unsigned i = 0, sz = c.size();
s.push();
@ -401,10 +405,12 @@ namespace sat {
}
bool asymm_branch::re_attach(scoped_detach& scoped_d, clause& c, unsigned new_sz) {
VERIFY(s.m_trail.size() == s.m_qhead);
m_elim_literals += c.size() - new_sz;
if (c.is_learned()) {
m_elim_learned_literals += c.size() - new_sz;
}
switch(new_sz) {
case 0:
s.set_conflict(justification());
@ -414,19 +420,18 @@ namespace sat {
s.assign(c[0], justification());
s.propagate_core(false);
scoped_d.del_clause();
SASSERT(s.inconsistent() || s.m_qhead == s.m_trail.size());
return false; // check_missed_propagation() may fail, since m_clauses is not in a consistent state.
case 2:
SASSERT(s.value(c[0]) == l_undef && s.value(c[1]) == l_undef);
VERIFY(s.value(c[0]) == l_undef && s.value(c[1]) == l_undef);
s.mk_bin_clause(c[0], c[1], c.is_learned());
if (s.m_trail.size() > s.m_qhead) s.propagate_core(false);
scoped_d.del_clause();
SASSERT(s.m_qhead == s.m_trail.size());
return false;
default:
c.shrink(new_sz);
if (s.m_config.m_drat) s.m_drat.add(c, true);
// if (s.m_config.m_drat) s.m_drat.del(c0); // TBD
SASSERT(s.m_qhead == s.m_trail.size());
return true;
}
}
@ -445,12 +450,8 @@ namespace sat {
bool asymm_branch::process(clause & c) {
TRACE("asymm_branch_detail", tout << "processing: " << c << "\n";);
SASSERT(s.scope_lvl() == 0);
SASSERT(s.m_qhead == s.m_trail.size());
SASSERT(!s.inconsistent());
#ifdef Z3DEBUG
unsigned trail_sz = s.m_trail.size();
#endif
unsigned sz = c.size();
SASSERT(sz > 0);
unsigned i;
@ -474,8 +475,6 @@ namespace sat {
bool found_conflict = flip_literal_at(c, flip_position, new_sz);
SASSERT(!s.inconsistent());
SASSERT(s.scope_lvl() == 0);
SASSERT(trail_sz == s.m_trail.size());
SASSERT(s.m_qhead == s.m_trail.size());
if (!found_conflict) {
// clause size can't be reduced.
return true;

View file

@ -194,7 +194,9 @@ namespace sat {
if (u != get_parent(v) && safe_reach(u, v)) {
++elim;
add_del(~u, v);
// IF_VERBOSE(1, verbose_stream() << "remove " << u << " -> " << v << "\n");
if (s.get_config().m_drat) s.m_drat.del(~u, v);
s.m_mc.stackv().reset(); // TBD: brittle code
s.add_ate(~u, v);
if (find_binary_watch(wlist, ~v)) {
IF_VERBOSE(10, verbose_stream() << "binary: " << ~u << "\n");
s.assign(~u, justification());

View file

@ -95,7 +95,6 @@ namespace sat {
}
}
bool clause::satisfied_by(model const & m) const {
for (literal l : *this) {
if (l.sign()) {
@ -110,6 +109,23 @@ namespace sat {
return false;
}
clause_offset clause::get_new_offset() const {
unsigned o1 = m_lits[0].index();
if (sizeof(clause_offset) == 8) {
unsigned o2 = m_lits[1].index();
return (clause_offset)o1 + (((clause_offset)o2) << 32);
}
return (clause_offset)o1;
}
void clause::set_new_offset(clause_offset offset) {
m_lits[0] = to_literal(static_cast<unsigned>(offset));
if (sizeof(offset) == 8) {
m_lits[1] = to_literal(static_cast<unsigned>(offset >> 32));
}
}
void tmp_clause::set(unsigned num_lits, literal const * lits, bool learned) {
if (m_clause && m_clause->m_capacity < num_lits) {
dealloc_svect(m_clause);
@ -135,12 +151,15 @@ namespace sat {
m_allocator("clause-allocator") {
}
void clause_allocator::finalize() {
m_allocator.reset();
}
clause * clause_allocator::get_clause(clause_offset cls_off) const {
SASSERT(cls_off == reinterpret_cast<clause_offset>(reinterpret_cast<clause*>(cls_off)));
return reinterpret_cast<clause *>(cls_off);
}
clause_offset clause_allocator::get_offset(clause const * cls) const {
SASSERT(cls == reinterpret_cast<clause *>(reinterpret_cast<size_t>(cls)));
return reinterpret_cast<size_t>(cls);
@ -155,6 +174,18 @@ namespace sat {
return cls;
}
clause * clause_allocator::copy_clause(clause const& other) {
size_t size = clause::get_obj_size(other.size());
void * mem = m_allocator.allocate(size);
clause * cls = new (mem) clause(m_id_gen.mk(), other.size(), other.m_lits, other.is_learned());
cls->m_reinit_stack = other.on_reinit_stack();
cls->m_glue = other.glue();
cls->m_psm = other.psm();
cls->m_frozen = other.frozen();
cls->m_approx = other.approx();
return cls;
}
void clause_allocator::del_clause(clause * cls) {
TRACE("sat_clause", tout << "delete: " << cls->id() << " " << *cls << "\n";);
m_id_gen.recycle(cls->id());

View file

@ -19,10 +19,11 @@ Revision History:
#ifndef SAT_CLAUSE_H_
#define SAT_CLAUSE_H_
#include "sat/sat_types.h"
#include "util/small_object_allocator.h"
#include "util/id_gen.h"
#include "util/map.h"
#include "sat/sat_types.h"
#include "sat/sat_allocator.h"
#ifdef _MSC_VER
#pragma warning(disable : 4200)
@ -97,6 +98,8 @@ namespace sat {
unsigned glue() const { return m_glue; }
void set_psm(unsigned psm) { m_psm = psm > 255 ? 255 : psm; }
unsigned psm() const { return m_psm; }
clause_offset get_new_offset() const;
void set_new_offset(clause_offset off);
bool on_reinit_stack() const { return m_reinit_stack; }
void set_reinit_stack(bool f) { m_reinit_stack = f; }
@ -133,13 +136,16 @@ namespace sat {
\brief Simple clause allocator that allows uint (32bit integers) to be used to reference clauses (even in 64bit machines).
*/
class clause_allocator {
small_object_allocator m_allocator;
id_gen m_id_gen;
small_object_allocator m_allocator;
id_gen m_id_gen;
public:
clause_allocator();
void finalize();
size_t get_allocation_size() const { return m_allocator.get_allocation_size(); }
clause * get_clause(clause_offset cls_off) const;
clause_offset get_offset(clause const * ptr) const;
clause * mk_clause(unsigned num_lits, literal const * lits, bool learned);
clause * copy_clause(clause const& other);
void del_clause(clause * cls);
};

View file

@ -124,6 +124,15 @@ namespace sat {
};
iterator mk_iterator() const { return iterator(const_cast<clause_use_list*>(this)->m_clauses); }
std::ostream& display(std::ostream& out) const {
iterator it = mk_iterator();
while (!it.at_end()) {
out << it.curr() << "\n";
it.next();
}
return out;
}
};
};

View file

@ -41,6 +41,7 @@ namespace sat {
else
throw sat_param_exception("invalid restart strategy");
m_restart_fast = p.restart_fast();
s = p.phase();
if (s == symbol("always_false"))
m_phase = PS_ALWAYS_FALSE;
@ -60,6 +61,7 @@ namespace sat {
m_restart_initial = p.restart_initial();
m_restart_factor = p.restart_factor();
m_restart_max = p.restart_max();
m_propagate_prefetch = p.propagate_prefetch();
m_inprocess_max = p.inprocess_max();
m_random_freq = p.random_freq();
@ -113,12 +115,15 @@ namespace sat {
m_lookahead_cube_psat_clause_base = p.lookahead_cube_psat_clause_base();
m_lookahead_cube_psat_trigger = p.lookahead_cube_psat_trigger();
m_lookahead_global_autarky = p.lookahead_global_autarky();
m_lookahead_use_learned = p.lookahead_use_learned();
// These parameters are not exposed
m_simplify_mult1 = _p.get_uint("simplify_mult1", 300);
m_next_simplify1 = _p.get_uint("next_simplify", 30000);
m_simplify_mult2 = _p.get_double("simplify_mult2", 1.5);
m_simplify_max = _p.get_uint("simplify_max", 500000);
// --------------------------------
m_simplify_delay = p.simplify_delay();
s = p.gc();
if (s == symbol("dyn_psm"))
@ -138,6 +143,7 @@ namespace sat {
m_gc_small_lbd = p.gc_small_lbd();
m_gc_k = std::min(255u, p.gc_k());
m_gc_burst = p.gc_burst();
m_gc_defrag = p.gc_defrag();
m_minimize_lemmas = p.minimize_lemmas();
m_core_minimize = p.core_minimize();
@ -178,8 +184,10 @@ namespace sat {
m_pb_solver = PB_TOTALIZER;
else if (s == symbol("solver"))
m_pb_solver = PB_SOLVER;
else if (s == symbol("segmented"))
m_pb_solver = PB_SEGMENTED;
else
throw sat_param_exception("invalid PB solver: solver, totalizer, circuit, sorting");
throw sat_param_exception("invalid PB solver: solver, totalizer, circuit, sorting, segmented");
m_card_solver = p.cardinality_solver();

View file

@ -54,7 +54,8 @@ namespace sat {
PB_SOLVER,
PB_CIRCUIT,
PB_SORTING,
PB_TOTALIZER
PB_TOTALIZER,
PB_SEGMENTED
};
enum reward_t {
@ -84,7 +85,9 @@ namespace sat {
unsigned m_phase_caching_on;
unsigned m_phase_caching_off;
bool m_phase_sticky;
bool m_propagate_prefetch;
restart_strategy m_restart;
bool m_restart_fast;
unsigned m_restart_initial;
double m_restart_factor; // for geometric case
unsigned m_restart_max;
@ -110,11 +113,13 @@ namespace sat {
double m_lookahead_cube_psat_trigger;
reward_t m_lookahead_reward;
bool m_lookahead_global_autarky;
bool m_lookahead_use_learned;
bool m_incremental;
unsigned m_simplify_mult1;
unsigned m_next_simplify1;
double m_simplify_mult2;
unsigned m_simplify_max;
unsigned m_simplify_delay;
unsigned m_variable_decay;
@ -124,6 +129,8 @@ namespace sat {
unsigned m_gc_small_lbd;
unsigned m_gc_k;
bool m_gc_burst;
bool m_gc_defrag;
bool m_minimize_lemmas;
bool m_dyn_sub_res;

View file

@ -42,7 +42,7 @@ namespace sat {
for (unsigned i = 0; i < m_proof.size(); ++i) {
clause* c = m_proof[i];
if (c && (c->size() == 2 || m_status[i] == status::deleted || m_status[i] == status::external)) {
s.m_cls_allocator.del_clause(c);
s.dealloc_clause(c);
}
}
}
@ -118,7 +118,7 @@ namespace sat {
if (st == status::learned) {
verify(2, lits);
}
clause* c = s.m_cls_allocator.mk_clause(2, lits, st == status::learned);
clause* c = s.alloc_clause(2, lits, st == status::learned);
m_proof.push_back(c);
m_status.push_back(st);
unsigned idx = m_watched_clauses.size();
@ -452,7 +452,7 @@ namespace sat {
case 0: add(); break;
case 1: append(lits[0], status::external); break;
default: {
clause* c = s.m_cls_allocator.mk_clause(lits.size(), lits.c_ptr(), true);
clause* c = s.alloc_clause(lits.size(), lits.c_ptr(), true);
append(*c, status::external);
break;
}
@ -468,7 +468,7 @@ namespace sat {
case 1: append(c[0], status::learned); break;
default: {
verify(c.size(), c.begin());
clause* cl = s.m_cls_allocator.mk_clause(c.size(), c.c_ptr(), true);
clause* cl = s.alloc_clause(c.size(), c.c_ptr(), true);
append(*cl, status::external);
break;
}
@ -490,7 +490,7 @@ namespace sat {
TRACE("sat", tout << "del: " << c << "\n";);
if (m_out) dump(c.size(), c.begin(), status::deleted);
if (m_check) {
clause* c1 = s.m_cls_allocator.mk_clause(c.size(), c.begin(), c.is_learned());
clause* c1 = s.alloc_clause(c.size(), c.begin(), c.is_learned());
append(*c1, status::deleted);
}
}

View file

@ -199,7 +199,7 @@ namespace sat {
literal r = roots[v];
SASSERT(v != r.var());
bool root_ok = !m_solver.is_external(v) || m_solver.set_root(l, r);
if (m_solver.is_external(v) && (m_solver.is_incremental() || !root_ok)) {
if (m_solver.is_assumption(v) || (m_solver.is_external(v) && (m_solver.is_incremental() || !root_ok))) {
// cannot really eliminate v, since we have to notify extension of future assignments
m_solver.mk_bin_clause(~l, r, false);
m_solver.mk_bin_clause(l, ~r, false);

View file

@ -101,7 +101,7 @@ namespace sat{
pos_occs.reset();
neg_occs.reset();
literal_vector lits;
add_clauses(b, lits);
add_clauses(v, b, lits);
return true;
}
@ -157,7 +157,7 @@ namespace sat{
return b;
}
void elim_vars::add_clauses(bdd const& b, literal_vector& lits) {
void elim_vars::add_clauses(bool_var v0, bdd const& b, literal_vector& lits) {
if (b.is_true()) {
// no-op
}
@ -167,6 +167,7 @@ namespace sat{
if (simp.cleanup_clause(c))
return;
if (v0 == 39063) IF_VERBOSE(0, verbose_stream() << "bdd: " << c << "\n");
switch (c.size()) {
case 0:
s.set_conflict(justification());
@ -184,7 +185,7 @@ namespace sat{
s.m_stats.m_mk_ter_clause++;
else
s.m_stats.m_mk_clause++;
clause* cp = s.m_cls_allocator.mk_clause(c.size(), c.c_ptr(), false);
clause* cp = s.alloc_clause(c.size(), c.c_ptr(), false);
s.m_clauses.push_back(cp);
simp.m_use_list.insert(*cp);
if (simp.m_sub_counter > 0)
@ -198,10 +199,10 @@ namespace sat{
else {
unsigned v = m_vars[b.var()];
lits.push_back(literal(v, false));
add_clauses(b.lo(), lits);
add_clauses(v0, b.lo(), lits);
lits.pop_back();
lits.push_back(literal(v, true));
add_clauses(b.hi(), lits);
add_clauses(v0, b.hi(), lits);
lits.pop_back();
}
}
@ -213,7 +214,7 @@ namespace sat{
}
if (b.is_false()) {
if (lits.size() > 1) {
clause* c = s.m_cls_allocator.mk_clause(lits.size(), lits.c_ptr(), false);
clause* c = s.alloc_clause(lits.size(), lits.c_ptr(), false);
clauses.push_back(c);
}
else {

View file

@ -57,7 +57,7 @@ namespace sat {
bdd make_clauses(literal lit);
bdd mk_literal(literal l);
void get_clauses(bdd const& b, literal_vector& lits, clause_vector& clauses, literal_vector& units);
void add_clauses(bdd const& b, literal_vector& lits);
void add_clauses(bool_var v, bdd const& b, literal_vector& lits);
bool elim_var(bool_var v, bdd const& b);
bdd elim_var(bool_var v);

View file

@ -136,9 +136,9 @@ namespace sat {
TRACE("iff3_finder",
tout << "visiting: " << x << "\n";
tout << "pos:\n";
display_watch_list(tout, s.m_cls_allocator, pos_wlist);
s.display_watch_list(tout, pos_wlist);
tout << "\nneg:\n";
display_watch_list(tout, s.m_cls_allocator, neg_wlist);
s.display_watch_list(tout, neg_wlist);
tout << "\n--------------\n";);
// traverse the ternary clauses x \/ l1 \/ l2
bool_var curr_v1 = null_bool_var;

View file

@ -66,7 +66,7 @@ namespace sat {
if (c.size() == 3) {
CTRACE("sat_ter_watch_bug", !contains_watched(s.get_wlist(~c[0]), c[1], c[2]), tout << c << "\n";
tout << "watch_list:\n";
sat::display_watch_list(tout, s.m_cls_allocator, s.get_wlist(~c[0]));
s.display_watch_list(tout, s.get_wlist(~c[0]));
tout << "\n";);
VERIFY(contains_watched(s.get_wlist(~c[0]), c[1], c[2]));
VERIFY(contains_watched(s.get_wlist(~c[1]), c[0], c[2]));
@ -164,9 +164,9 @@ namespace sat {
tout << "was_eliminated1: " << s.was_eliminated(l.var());
tout << " was_eliminated2: " << s.was_eliminated(w.get_literal().var());
tout << " learned: " << w.is_learned() << "\n";
sat::display_watch_list(tout, s.m_cls_allocator, wlist);
s.display_watch_list(tout, wlist);
tout << "\n";
sat::display_watch_list(tout, s.m_cls_allocator, s.get_wlist(~(w.get_literal())));
s.display_watch_list(tout, s.get_wlist(~(w.get_literal())));
tout << "\n";);
VERIFY(find_binary_watch(s.get_wlist(~(w.get_literal())), l));
break;
@ -176,7 +176,7 @@ namespace sat {
VERIFY(w.get_literal1().index() < w.get_literal2().index());
break;
case watched::CLAUSE:
VERIFY(!s.m_cls_allocator.get_clause(w.get_clause_offset())->was_removed());
VERIFY(!s.get_clause(w.get_clause_offset()).was_removed());
break;
default:
break;

View file

@ -79,11 +79,13 @@ namespace sat {
void local_search::init_cur_solution() {
for (var_info& vi : m_vars) {
// use bias with a small probability
if (m_rand() % 10 < 5 || m_config.phase_sticky()) {
vi.m_value = ((unsigned)(m_rand() % 100) < vi.m_bias);
}
else {
vi.m_value = (m_rand() % 2) == 0;
if (!vi.m_unit) {
if (m_rand() % 10 < 5 || m_config.phase_sticky()) {
vi.m_value = ((unsigned)(m_rand() % 100) < vi.m_bias);
}
else {
vi.m_value = (m_rand() % 2) == 0;
}
}
}
}
@ -149,7 +151,7 @@ namespace sat {
void local_search::reinit() {
IF_VERBOSE(0, verbose_stream() << "(sat-local-search reinit)\n";);
IF_VERBOSE(1, verbose_stream() << "(sat-local-search reinit)\n";);
if (true || !m_is_pb) {
//
// the following methods does NOT converge for pseudo-boolean
@ -216,13 +218,15 @@ namespace sat {
for (unsigned i = 0; i < m_prop_queue.size() && i < m_vars.size(); ++i) {
literal lit2 = m_prop_queue[i];
if (!is_true(lit2)) {
if (is_unit(lit2)) return false;
if (is_unit(lit2)) {
return false;
}
flip_walksat(lit2.var());
add_propagation(lit2);
}
}
if (m_prop_queue.size() >= m_vars.size()) {
IF_VERBOSE(0, verbose_stream() << "failed literal\n");
IF_VERBOSE(0, verbose_stream() << "propagation loop\n");
return false;
}
if (unit) {
@ -328,6 +332,7 @@ namespace sat {
return;
}
if (k == 1 && sz == 2) {
// IF_VERBOSE(0, verbose_stream() << "bin: " << ~c[0] << " + " << ~c[1] << " <= 1\n");
for (unsigned i = 0; i < 2; ++i) {
literal t(c[i]), s(c[1-i]);
m_vars.reserve(t.var() + 1);
@ -750,11 +755,12 @@ namespace sat {
IF_VERBOSE(1, verbose_stream() << "(sat.local_search :unsat)\n");
return;
}
if (is_unit(best_var)) {
goto reflip;
}
flip_walksat(best_var);
literal lit(best_var, !cur_solution(best_var));
if (!propagate(lit)) {
IF_VERBOSE(0, verbose_stream() << "failed literal " << lit << "\n");
if (is_true(lit)) {
flip_walksat(best_var);
}
@ -774,6 +780,7 @@ namespace sat {
}
void local_search::flip_walksat(bool_var flipvar) {
VERIFY(!is_unit(flipvar));
m_vars[flipvar].m_value = !cur_solution(flipvar);
bool flip_is_true = cur_solution(flipvar);

View file

@ -1034,7 +1034,7 @@ namespace sat {
}
if (m_s.m_ext) {
m_ext = m_s.m_ext->copy(this, learned);
// m_ext = m_s.m_ext->copy(this, learned);
}
propagate();
m_qhead = m_trail.size();
@ -1832,7 +1832,7 @@ namespace sat {
unsigned dl_truth = base + m_lookahead.size() * m_config.m_dl_max_iterations;
scoped_level _sl(*this, dl_truth);
//SASSERT(get_level(m_trail.back()) == dl_truth);
IF_VERBOSE(2, verbose_stream() << "(sat-lookahead :double " << l << " :depth " << m_trail_lim.size() << ")\n";);
IF_VERBOSE(3, verbose_stream() << "(sat-lookahead :double " << l << " :depth " << m_trail_lim.size() << ")\n";);
lookahead_backtrack();
assign(l);
propagate();
@ -2227,7 +2227,7 @@ namespace sat {
void lookahead::init_search() {
m_search_mode = lookahead_mode::searching;
scoped_level _sl(*this, c_fixed_truth);
init(true);
init(m_s.m_config.m_lookahead_use_learned);
}
void lookahead::checkpoint() {

View file

@ -247,7 +247,7 @@ namespace sat {
stats m_stats;
model m_model;
cube_state m_cube_state;
scoped_ptr<extension> m_ext;
//scoped_ptr<extension> m_ext;
// ---------------------------------------
// truth values

View file

@ -75,32 +75,42 @@ namespace sat {
void model_converter::operator()(model & m) const {
vector<entry>::const_iterator begin = m_entries.begin();
vector<entry>::const_iterator it = m_entries.end();
bool first = true;
bool first = false; // true; // false; // // true;
//SASSERT(!m_solver || m_solver->check_clauses(m));
while (it != begin) {
--it;
SASSERT(it->get_kind() != ELIM_VAR || m[it->var()] == l_undef);
// if it->get_kind() == BLOCK_LIT, then it might be the case that m[it->var()] != l_undef,
bool_var v0 = it->var();
SASSERT(it->get_kind() != ELIM_VAR || v0 == null_bool_var || m[v0] == l_undef);
// if it->get_kind() == BCE, then it might be the case that m[v] != l_undef,
// and the following procedure flips its value.
bool sat = false;
bool var_sign = false;
unsigned index = 0;
literal_vector clause;
VERIFY(legal_to_flip(it->var()));
VERIFY(v0 == null_bool_var || legal_to_flip(v0));
for (literal l : it->m_clauses) {
if (l == null_literal) {
// end of clause
elim_stack* st = it->m_elim_stack[index];
if (!sat) {
VERIFY(legal_to_flip(it->var()));
m[it->var()] = var_sign ? l_false : l_true;
if (!sat && it->get_kind() == ATE) {
IF_VERBOSE(0, display(verbose_stream() << "violated ate\n", *it) << "\n");
IF_VERBOSE(0, for (unsigned v = 0; v < m.size(); ++v) verbose_stream() << v << " := " << m[v] << "\n";);
IF_VERBOSE(0, display(verbose_stream()));
exit(0);
first = false;
}
if (!sat && it->get_kind() != ATE && v0 != null_bool_var) {
VERIFY(legal_to_flip(v0));
m[v0] = var_sign ? l_false : l_true;
//IF_VERBOSE(0, verbose_stream() << "assign " << v0 << " "<< m[v0] << "\n");
}
elim_stack* st = it->m_elim_stack[index];
if (st) {
process_stack(m, clause, st->stack());
}
sat = false;
if (false && first && m_solver && !m_solver->check_clauses(m)) {
display(std::cout, *it) << "\n";
if (first && m_solver && !m_solver->check_clauses(m)) {
IF_VERBOSE(0, display(verbose_stream() << "after processing stack\n", *it) << "\n");
IF_VERBOSE(0, display(verbose_stream()));
first = false;
}
++index;
@ -115,18 +125,18 @@ namespace sat {
bool_var v = l.var();
if (v >= m.size()) std::cout << v << " model size: " << m.size() << "\n";
VERIFY(v < m.size());
if (v == it->var())
if (v == v0)
var_sign = sign;
if (value_at(l, m) == l_true)
sat = true;
else if (!sat && v != it->var() && m[v] == l_undef) {
else if (!sat && v != v0 && m[v] == l_undef) {
VERIFY(legal_to_flip(v));
// clause can be satisfied by assigning v.
m[v] = sign ? l_false : l_true;
// if (first) std::cout << "set: " << l << "\n";
sat = true;
if (false && first && m_solver && !m_solver->check_clauses(m)) {
display(std::cout, *it) << "\n";;
if (first && m_solver && !m_solver->check_clauses(m)) {
IF_VERBOSE(0, display(verbose_stream() << "after flipping undef\n", *it) << "\n");
first = false;
}
}
@ -190,17 +200,43 @@ namespace sat {
entry & e = m_entries.back();
SASSERT(e.var() == v);
SASSERT(e.get_kind() == k);
VERIFY(legal_to_flip(v));
VERIFY(v == null_bool_var || legal_to_flip(v));
return e;
}
void model_converter::add_ate(clause const& c) {
if (stackv().empty()) return;
insert(mk(ATE, null_bool_var), c);
}
void model_converter::add_ate(literal_vector const& lits) {
if (stackv().empty()) return;
insert(mk(ATE, null_bool_var), lits);
}
void model_converter::add_ate(literal l1, literal l2) {
if (stackv().empty()) return;
insert(mk(ATE, null_bool_var), l1, l2);
}
void model_converter::add_elim_stack(entry & e) {
e.m_elim_stack.push_back(stackv().empty() ? nullptr : alloc(elim_stack, stackv()));
#if 0
if (!stackv().empty() && e.get_kind() == ATE) {
IF_VERBOSE(0, display(verbose_stream(), e) << "\n");
}
#endif
for (auto const& s : stackv()) VERIFY(legal_to_flip(s.second.var()));
stackv().reset();
}
void model_converter::insert(entry & e, clause const & c) {
SASSERT(c.contains(e.var()));
SASSERT(m_entries.begin() <= &e);
SASSERT(&e < m_entries.end());
for (literal l : c) e.m_clauses.push_back(l);
e.m_clauses.push_back(null_literal);
e.m_elim_stack.push_back(nullptr);
add_elim_stack(e);
TRACE("sat_mc_bug", tout << "adding: " << c << "\n";);
}
@ -211,7 +247,7 @@ namespace sat {
e.m_clauses.push_back(l1);
e.m_clauses.push_back(l2);
e.m_clauses.push_back(null_literal);
e.m_elim_stack.push_back(nullptr);
add_elim_stack(e);
TRACE("sat_mc_bug", tout << "adding (binary): " << l1 << " " << l2 << "\n";);
}
@ -223,18 +259,17 @@ namespace sat {
for (unsigned i = 0; i < sz; ++i)
e.m_clauses.push_back(c[i]);
e.m_clauses.push_back(null_literal);
e.m_elim_stack.push_back(nullptr);
add_elim_stack(e);
// TRACE("sat_mc_bug", tout << "adding (wrapper): "; for (literal l : c) tout << l << " "; tout << "\n";);
}
void model_converter::insert(entry & e, literal_vector const& c, elim_stackv const& elims) {
void model_converter::insert(entry & e, literal_vector const& c) {
SASSERT(c.contains(literal(e.var(), false)) || c.contains(literal(e.var(), true)));
SASSERT(m_entries.begin() <= &e);
SASSERT(&e < m_entries.end());
for (literal l : c) e.m_clauses.push_back(l);
e.m_clauses.push_back(null_literal);
e.m_elim_stack.push_back(elims.empty() ? nullptr : alloc(elim_stack, elims));
for (auto const& s : elims) VERIFY(legal_to_flip(s.second.var()));
add_elim_stack(e);
TRACE("sat_mc_bug", tout << "adding: " << c << "\n";);
}
@ -245,7 +280,7 @@ namespace sat {
vector<entry>::const_iterator it = m_entries.begin();
vector<entry>::const_iterator end = m_entries.end();
for (; it != end; ++it) {
SASSERT(it->var() < num_vars);
SASSERT(it->var() == null_bool_var || it->var() < num_vars);
if (it->get_kind() == ELIM_VAR) {
svector<entry>::const_iterator it2 = it;
it2++;
@ -275,7 +310,8 @@ namespace sat {
}
std::ostream& model_converter::display(std::ostream& out, entry const& entry) const {
out << " (" << entry.get_kind() << " " << entry.var();
out << " (" << entry.get_kind() << " ";
if (entry.var() != null_bool_var) out << entry.var();
bool start = true;
unsigned index = 0;
for (literal l : entry.m_clauses) {
@ -305,7 +341,7 @@ namespace sat {
}
out << ")";
for (literal l : entry.m_clauses) {
if (l != null_literal) {
if (l != null_literal && l.var() != null_bool_var) {
if (false && m_solver && m_solver->was_eliminated(l.var())) out << "\neliminated: " << l;
}
}
@ -332,7 +368,7 @@ namespace sat {
for (entry const& e : m_entries) {
for (literal l : e.m_clauses) {
if (l != null_literal) {
if (l.var() > result)
if (l.var() != null_bool_var && l.var() > result)
result = l.var();
}
}
@ -371,9 +407,11 @@ namespace sat {
update_stack.push_back(null_literal);
}
}
swap(e.var(), clause.size(), clause);
update_stack.append(clause);
update_stack.push_back(null_literal);
if (e.var() != null_bool_var) {
swap(e.var(), clause.size(), clause);
update_stack.append(clause);
update_stack.push_back(null_literal);
}
clause.reset();
}
else {

View file

@ -66,11 +66,11 @@ namespace sat {
unsigned ref_count() const { return m_refcount; }
};
enum kind { ELIM_VAR = 0, BLOCK_LIT, CCE, ACCE };
enum kind { ELIM_VAR = 0, BCE, CCE, ACCE, ABCE, ATE };
class entry {
friend class model_converter;
unsigned m_var:30;
unsigned m_kind:2;
bool_var m_var;
kind m_kind;
literal_vector m_clauses; // the different clauses are separated by null_literal
sref_vector<elim_stack> m_elim_stack;
entry(kind k, bool_var v): m_var(v), m_kind(k) {}
@ -82,11 +82,12 @@ namespace sat {
m_elim_stack.append(src.m_elim_stack);
}
bool_var var() const { return m_var; }
kind get_kind() const { return static_cast<kind>(m_kind); }
kind get_kind() const { return m_kind; }
};
private:
vector<entry> m_entries;
solver const* m_solver;
elim_stackv m_elim_stack;
void process_stack(model & m, literal_vector const& clause, elim_stackv const& stack) const;
@ -96,6 +97,8 @@ namespace sat {
void swap(bool_var v, unsigned sz, literal_vector& clause);
void add_elim_stack(entry & e);
public:
model_converter();
~model_converter();
@ -103,11 +106,17 @@ namespace sat {
void operator()(model & m) const;
model_converter& operator=(model_converter const& other);
elim_stackv& stackv() { return m_elim_stack; }
entry & mk(kind k, bool_var v);
void insert(entry & e, clause const & c);
void insert(entry & e, literal l1, literal l2);
void insert(entry & e, clause_wrapper const & c);
void insert(entry & c, literal_vector const& covered_clause, elim_stackv const& elim_stack);
void insert(entry & c, literal_vector const& covered_clause);
void add_ate(literal_vector const& lits);
void add_ate(literal l1, literal l2);
void add_ate(clause const& c);
bool empty() const { return m_entries.empty(); }
@ -137,9 +146,11 @@ namespace sat {
inline std::ostream& operator<<(std::ostream& out, model_converter::kind k) {
switch (k) {
case model_converter::ELIM_VAR: out << "elim"; break;
case model_converter::BLOCK_LIT: out << "blocked"; break;
case model_converter::BCE: out << "bce"; break;
case model_converter::CCE: out << "cce"; break;
case model_converter::ACCE: out << "acce"; break;
case model_converter::ABCE: out << "abce"; break;
case model_converter::ATE: out << "ate"; break;
}
return out;
}

View file

@ -6,11 +6,13 @@ def_module_params('sat',
('phase.caching.on', UINT, 400, 'phase caching on period (in number of conflicts)'),
('phase.caching.off', UINT, 100, 'phase caching off period (in number of conflicts)'),
('phase.sticky', BOOL, False, 'use sticky phase caching for local search'),
('propagate.prefetch', BOOL, True, 'prefetch watch lists for assigned literals'),
('restart', SYMBOL, 'luby', 'restart strategy: luby or geometric'),
('restart.initial', UINT, 100, 'initial restart (number of conflicts)'),
('restart.max', UINT, UINT_MAX, 'maximal number of restarts.'),
('restart.fast', BOOL, False, 'use fast restart strategy.'),
('restart.factor', DOUBLE, 1.5, 'restart increment factor for geometric strategy'),
('variable_decay', UINT, 120, 'multiplier (divided by 100) for the VSIDS activity increement'),
('variable_decay', UINT, 110, 'multiplier (divided by 100) for the VSIDS activity increement'),
('inprocess.max', UINT, UINT_MAX, 'maximal number of inprocessing passes'),
('branching.heuristic', SYMBOL, 'vsids', 'branching heuristic vsids, lrb or chb'),
('branching.anti_exploration', BOOL, False, 'apply anti-exploration heuristic for branch selection'),
@ -24,6 +26,8 @@ def_module_params('sat',
('gc.small_lbd', UINT, 3, 'learned clauses with small LBD are never deleted (only used in dyn_psm)'),
('gc.k', UINT, 7, 'learned clauses that are inactive for k gc rounds are permanently deleted (only used in dyn_psm)'),
('gc.burst', BOOL, True, 'perform eager garbage collection during initialization'),
('gc.defrag', BOOL, True, 'defragment clauses when garbage collecting'),
('simplify.delay', UINT, 0, 'set initial delay of simplification by a conflict count'),
('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'),
@ -42,9 +46,9 @@ def_module_params('sat',
('local_search_mode', SYMBOL, 'wsat', 'local search algorithm, either default wsat or qsat'),
('unit_walk', BOOL, False, 'use unit-walk search instead of CDCL'),
('unit_walk_threads', UINT, 0, 'number of unit-walk search threads to find satisfiable solution'),
('lookahead.cube.cutoff', SYMBOL, 'adaptive_freevars', 'cutoff type used to create lookahead cubes: depth, freevars, psat, adaptive_freevars, adaptive_psat'),
('lookahead.cube.cutoff', SYMBOL, 'depth', 'cutoff type used to create lookahead cubes: depth, freevars, psat, adaptive_freevars, adaptive_psat'),
('lookahead.cube.fraction', DOUBLE, 0.4, 'adaptive fraction to create lookahead cubes. Used when lookahead.cube.cutoff is adaptive_freevars or adaptive_psat'),
('lookahead.cube.depth', UINT, 10, 'cut-off depth to create cubes. Used when lookahead.cube.cutoff is depth.'),
('lookahead.cube.depth', UINT, 1, 'cut-off depth to create cubes. Used when lookahead.cube.cutoff is depth.'),
('lookahead.cube.freevars', DOUBLE, 0.8, 'cube free fariable fraction. Used when lookahead.cube.cutoff is freevars'),
('lookahead.cube.psat.var_exp', DOUBLE, 1, 'free variable exponent for PSAT cutoff'),
('lookahead.cube.psat.clause_base', DOUBLE, 2, 'clause base for PSAT cutoff'),
@ -52,6 +56,7 @@ def_module_params('sat',
('lookahead_search', BOOL, False, 'use lookahead solver'),
('lookahead.preselect', BOOL, False, 'use pre-selection of subset of variables for branching'),
('lookahead_simplify', BOOL, False, 'use lookahead solver during simplification'),
('lookahead.use_learned', BOOL, False, 'use learned clauses when selecting lookahead literal'),
('lookahead_simplify.bca', BOOL, True, 'add learned binary clauses as part of lookahead simplification'),
('lookahead.global_autarky', BOOL, False, 'prefer to branch on variables that occur in clauses that are reduced'),
('lookahead.reward', SYMBOL, 'march_cu', 'select lookahead heuristic: ternary, heule_schur (Heule Schur), heuleu (Heule Unit), unit, or march_cu')))

View file

@ -100,7 +100,7 @@ namespace sat {
!m_learned_in_use_lists && m_num_calls >= m_bce_delay && single_threaded();
}
bool simplifier::ate_enabled() const { return m_ate; }
bool simplifier::ate_enabled() const { return m_num_calls >= m_bce_delay && m_ate; }
bool simplifier::bce_enabled() const { return bce_enabled_base() && (m_bce || m_bce_at == m_num_calls || m_acce || m_abce || m_cce); }
bool simplifier::acce_enabled() const { return bce_enabled_base() && m_acce; }
bool simplifier::cce_enabled() const { return bce_enabled_base() && (m_cce || m_acce); }
@ -939,6 +939,24 @@ namespace sat {
bool operator==(clause_ante const& a) const {
return a.m_lit1 == m_lit1 && a.m_lit2 == m_lit2 && a.m_clause == m_clause;
}
std::ostream& display(std::ostream& out, literal lit) const {
if (cls()) {
out << *cls() << " ";
}
else {
out << "(" << ~lit;
}
if (lit1() != null_literal) {
out << " " << lit1();
}
if (lit2() != null_literal) {
out << " " << lit2();
}
if (!cls()) out << ")";
if (from_ri()) out << "ri";
out << "\n";
return out;
}
};
class queue {
@ -965,7 +983,7 @@ namespace sat {
simplifier & s;
int m_counter;
model_converter & mc;
model_converter & m_mc;
queue m_queue;
literal_vector m_covered_clause; // covered clause
@ -974,7 +992,6 @@ namespace sat {
literal_vector m_tautology; // literals that are used in blocking tautology
literal_vector m_new_intersection;
svector<bool> m_in_intersection;
sat::model_converter::elim_stackv m_elim_stack;
unsigned m_ala_qhead;
clause_wrapper m_clause;
@ -982,7 +999,7 @@ namespace sat {
vector<watch_list> & wlist):
s(_s),
m_counter(limit),
mc(_mc),
m_mc(_mc),
m_queue(l, wlist),
m_clause(null_literal, null_literal) {
m_in_intersection.resize(s.s.num_vars() * 2, false);
@ -994,7 +1011,7 @@ namespace sat {
}
bool process_var(bool_var v) {
return !s.s.is_assumption(v) && !s.was_eliminated(v) && !s.is_external(v);
return !s.s.is_assumption(v) && !s.was_eliminated(v) && !s.is_external(v) && s.value(v) == l_undef;
}
enum elim_type {
@ -1052,10 +1069,11 @@ namespace sat {
// Find literals that are in the intersection of all resolvents with l.
//
bool resolution_intersection(literal l, bool adding) {
unsigned tsz = m_tautology.size();
reset_intersection();
m_tautology.reset();
if (!process_var(l.var())) return false;
bool first = true;
VERIFY(s.value(l) == l_undef);
for (watched & w : s.get_wlist(l)) {
// when adding a blocked clause, then all non-learned clauses have to be considered for the
// resolution intersection.
@ -1068,6 +1086,7 @@ namespace sat {
}
if (!first || s.is_marked(lit)) {
reset_intersection();
m_tautology.shrink(tsz);
return false; // intersection is empty or does not add anything new.
}
first = false;
@ -1104,22 +1123,31 @@ namespace sat {
for (literal lit : m_new_intersection)
add_intersection(lit);
}
if (m_intersection.empty())
if (m_intersection.empty()) {
m_tautology.shrink(tsz);
return false;
}
}
}
// remove tautology literals if literal has no resolution intersection
if (m_intersection.empty() && !first) {
m_tautology.shrink(tsz);
}
// if (first) IF_VERBOSE(0, verbose_stream() << "taut: " << m_tautology << "\n";);
return first;
}
bool check_abce_tautology(literal l) {
m_tautology.reset();
unsigned tsz = m_tautology.size();
if (!process_var(l.var())) return false;
for (watched & w : s.get_wlist(l)) {
if (w.is_binary_non_learned_clause()) {
literal lit = w.get_literal();
VERIFY(lit != ~l);
if (!s.is_marked(~lit)) return false;
if (!s.is_marked(~lit)) {
m_tautology.shrink(tsz);
return false;
}
m_tautology.push_back(~lit);
}
}
@ -1135,7 +1163,10 @@ namespace sat {
break;
}
}
if (!tautology) return false;
if (!tautology) {
m_tautology.shrink(tsz);
return false;
}
}
return true;
}
@ -1154,10 +1185,15 @@ namespace sat {
\brief idx is the index of the blocked literal.
m_tautology contains literals that were used to establish that the current members of m_covered_clause is blocked.
This routine removes literals that were not relevant to establishing it was blocked.
It has a bug: literals that are used to prune tautologies during resolution intersection should be included
in the dependencies. They may get used in some RI prunings and then they have to be included to avoid flipping
RI literals.
*/
void minimize_covered_clause(unsigned idx) {
// IF_VERBOSE(0, verbose_stream() << "minimize: " << m_covered_clause
// << " @ " << idx << "\n" << "tautology: " << m_tautology << "\n";);
literal _blocked = m_covered_clause[idx];
for (literal l : m_tautology) VERIFY(s.is_marked(l));
for (literal l : m_covered_clause) s.unmark_visited(l);
for (literal l : m_tautology) s.mark_visited(l);
@ -1167,8 +1203,18 @@ namespace sat {
if (m_covered_antecedent[i] == clause_ante()) s.mark_visited(lit);
if (s.is_marked(lit)) idx = i;
}
if (false && _blocked.var() == 8074) {
IF_VERBOSE(0, verbose_stream() << "covered: " << m_covered_clause << "\n";
verbose_stream() << "tautology: " << m_tautology << "\n";
verbose_stream() << "index: " << idx << "\n";
for (unsigned i = idx; i > 0; --i) {
m_covered_antecedent[i].display(verbose_stream(), m_covered_clause[i]);
});
}
for (unsigned i = idx; i > 0; --i) {
literal lit = m_covered_clause[i];
//s.mark_visited(lit);
//continue;
if (!s.is_marked(lit)) continue;
clause_ante const& ante = m_covered_antecedent[i];
if (ante.cls()) {
@ -1195,16 +1241,22 @@ namespace sat {
clause_ante const& ante = m_covered_antecedent[i];
if (ante.from_ri() && blocked != ante.lit1()) {
blocked = ante.lit1();
m_elim_stack.push_back(std::make_pair(j, blocked));
VERIFY(s.value(blocked) == l_undef);
m_mc.stackv().push_back(std::make_pair(j, blocked));
}
m_covered_clause[j++] = lit;
s.unmark_visited(lit);
}
}
for (literal l : m_covered_clause) VERIFY(!s.is_marked(l));
for (bool_var v = 0; v < s.s.num_vars(); ++v) VERIFY(!s.is_marked(literal(v, true)) && !s.is_marked(literal(v, false)));
// unsigned sz0 = m_covered_clause.size();
m_covered_clause.resize(j);
VERIFY(j >= m_clause.size());
if (false && _blocked.var() == 16774) {
IF_VERBOSE(0, verbose_stream() << "covered: " << m_covered_clause << "\n");
}
// IF_VERBOSE(0, verbose_stream() << "reduced from size " << sz0 << " to " << m_covered_clause << "\n" << m_clause << "\n";);
}
@ -1233,6 +1285,7 @@ namespace sat {
return true;
}
if (!s.is_marked(~lit)) {
// if (m_covered_clause[0].var() == 10219) IF_VERBOSE(0, verbose_stream() << "ala: " << l << " " << lit << "\n");
m_covered_clause.push_back(~lit);
m_covered_antecedent.push_back(clause_ante(l, false));
s.mark_visited(~lit);
@ -1262,6 +1315,7 @@ namespace sat {
if (lit1 == null_literal) {
return true;
}
// if (m_covered_clause[0].var() == 10219) IF_VERBOSE(0, verbose_stream() << "ala: " << c << " " << lit1 << "\n");
m_covered_clause.push_back(~lit1);
m_covered_antecedent.push_back(clause_ante(c));
s.mark_visited(~lit1);
@ -1282,7 +1336,7 @@ namespace sat {
for (unsigned i = 0; i < m_covered_clause.size(); ++i) {
literal lit = m_covered_clause[i];
if (resolution_intersection(lit, false)) {
blocked = m_covered_clause[i];
blocked = m_covered_clause[i];
minimize_covered_clause(i);
return true;
}
@ -1302,13 +1356,18 @@ namespace sat {
return sz0 * 400 < m_covered_clause.size();
}
void reset_mark() {
for (literal l : m_covered_clause) s.unmark_visited(l);
}
template<elim_type et>
elim_type cce(literal& blocked, model_converter::kind& k) {
bool is_tautology = false, first = true;
bool first = true;
unsigned sz = 0, sz0 = m_covered_clause.size();
for (literal l : m_covered_clause) s.mark_visited(l);
shuffle<literal>(m_covered_clause.size(), m_covered_clause.c_ptr(), s.s.m_rand);
m_elim_stack.reset();
m_tautology.reset();
m_mc.stackv().reset();
m_ala_qhead = 0;
switch (et) {
@ -1319,7 +1378,7 @@ namespace sat {
k = model_converter::ACCE;
break;
default:
k = model_converter::BLOCK_LIT;
k = model_converter::BCE;
break;
}
@ -1331,48 +1390,76 @@ namespace sat {
* and then check if any of the first sz0 literals are blocked.
*/
while (!is_tautology && m_covered_clause.size() > sz && !above_threshold(sz0)) {
SASSERT(!is_tautology);
if (et == ate_t) {
bool ala = add_ala();
reset_mark();
m_covered_clause.shrink(sz0);
return ala ? ate_t : no_t;
}
if ((et == abce_t || et == acce_t || et == ate_t) && add_ala()) {
for (literal l : m_covered_clause) s.unmark_visited(l);
while (m_covered_clause.size() > sz && !above_threshold(sz0)) {
if ((et == abce_t || et == acce_t) && add_ala()) {
reset_mark();
if (first) {
m_covered_clause.shrink(sz0);
}
else {
/*
* tautology depends on resolution intersection.
* literals used for resolution intersection may have to be flipped.
*/
for (literal l : m_covered_clause) {
m_tautology.push_back(l);
s.mark_visited(l);
}
minimize_covered_clause(m_covered_clause.size()-1);
}
return ate_t;
}
if (et == ate_t) {
for (literal l : m_covered_clause) s.unmark_visited(l);
return no_t;
}
if (first) {
for (unsigned i = 0; i < sz0; ++i) {
if (check_abce_tautology(m_covered_clause[i])) {
blocked = m_covered_clause[i];
is_tautology = true;
break;
reset_mark();
#if 0
if (sz0 == 3 && blocked.var() == 10219) {
IF_VERBOSE(0, verbose_stream() << "abce: " << m_covered_clause << "\n";
for (literal l : m_covered_clause) verbose_stream() << s.value(l) << "\n";
);
literal l = blocked;
clause_use_list & neg_occs = s.m_use_list.get(~l);
for (auto it = neg_occs.mk_iterator(); !it.at_end(); it.next()) {
clause & c = it.curr();
IF_VERBOSE(0, verbose_stream() << c << "\n");
}
}
#endif
m_covered_clause.shrink(sz0);
if (et == bce_t) return bce_t;
k = model_converter::ABCE;
return abce_t;
}
}
first = false;
}
first = false;
if (is_tautology || et == abce_t || et == bce_t) {
for (literal l : m_covered_clause) s.unmark_visited(l);
m_covered_clause.shrink(sz0);
if (!is_tautology) return no_t;
if (et == bce_t) return bce_t;
return abce_t;
if (et == abce_t || et == bce_t) {
break;
}
/*
* Add resolution intersection while checking if the clause becomes a tautology.
*/
sz = m_covered_clause.size();
if (et == cce_t || et == acce_t) {
is_tautology = add_cla(blocked);
if ((et == cce_t || et == acce_t) && add_cla(blocked)) {
reset_mark();
return et;
}
}
for (literal l : m_covered_clause) s.unmark_visited(l);
return is_tautology ? et : no_t;
reset_mark();
return no_t;
}
// perform covered clause elimination.
@ -1433,13 +1520,14 @@ namespace sat {
case ate_t:
w.set_learned(true);
s.s.set_learned1(l2, l, true);
m_mc.add_ate(m_covered_clause);
break;
case no_t:
break;
default:
block_covered_binary(w, l, blocked, k);
w.set_learned(true);
s.s.set_learned1(l2, l, true);
block_covered_binary(w, l, blocked, k);
break;
}
}
@ -1457,7 +1545,8 @@ namespace sat {
inc_bc(r);
switch (r) {
case ate_t:
s.set_learned(c);
m_mc.add_ate(m_covered_clause);
s.set_learned(c);
break;
case no_t:
break;
@ -1488,24 +1577,33 @@ namespace sat {
}
void block_covered_clause(clause& c, literal l, model_converter::kind k) {
if (false) {
IF_VERBOSE(0, verbose_stream() << "blocked: " << l << " @ " << c << " :covered " << m_covered_clause << "\n";
s.m_use_list.display(verbose_stream() << "use " << l << ":", l);
s.m_use_list.display(verbose_stream() << "use " << ~l << ":", ~l);
s.s.display_watch_list(verbose_stream() << ~l << ": ", s.get_wlist(l)) << "\n";
s.s.display_watch_list(verbose_stream() << l << ": ", s.get_wlist(~l)) << "\n";
);
}
TRACE("blocked_clause", tout << "new blocked clause: " << c << "\n";);
SASSERT(!s.is_external(l));
model_converter::entry& new_entry = mc.mk(k, l.var());
model_converter::entry& new_entry = m_mc.mk(k, l.var());
for (literal lit : c) {
if (lit != l && process_var(lit.var())) {
m_queue.decreased(~lit);
}
}
mc.insert(new_entry, m_covered_clause, m_elim_stack);
m_mc.insert(new_entry, m_covered_clause);
}
void block_covered_binary(watched const& w, literal l1, literal blocked, model_converter::kind k) {
SASSERT(!s.is_external(blocked));
model_converter::entry& new_entry = mc.mk(k, blocked.var());
model_converter::entry& new_entry = m_mc.mk(k, blocked.var());
literal l2 = w.get_literal();
TRACE("blocked_clause", tout << "new blocked clause: " << l2 << " " << l1 << "\n";);
s.set_learned(l1, l2);
mc.insert(new_entry, m_covered_clause, m_elim_stack);
m_mc.insert(new_entry, m_covered_clause);
m_queue.decreased(~l2);
}
@ -1526,18 +1624,15 @@ namespace sat {
Then the following binary clause is blocked: l \/ ~l'
*/
void bca(literal l) {
m_tautology.reset();
if (resolution_intersection(l, true)) {
// this literal is pure.
return;
}
for (literal l2 : m_intersection) {
l2.neg();
watched* w = find_binary_watch(s.get_wlist(~l), l2);
watched* w = find_binary_watch(s.get_wlist(~l), ~l2);
if (!w) {
IF_VERBOSE(100, verbose_stream() << "bca " << l << " " << l2 << "\n";);
s.get_wlist(~l).push_back(watched(l2, true));
VERIFY(!find_binary_watch(s.get_wlist(~l2), l));
s.get_wlist(~l2).push_back(watched(l, true));
s.s.mk_bin_clause(l, ~l2, true);
++s.m_num_bca;
}
}
@ -1743,13 +1838,19 @@ namespace sat {
}
void simplifier::save_clauses(model_converter::entry & mc_entry, clause_wrapper_vector const & cs) {
model_converter & mc = s.m_mc;
for (auto & e : cs) {
mc.insert(mc_entry, e);
s.m_mc.insert(mc_entry, e);
}
}
void simplifier::add_non_learned_binary_clause(literal l1, literal l2) {
#if 0
if ((l1.var() == 2039 || l2.var() == 2039) &&
(l1.var() == 27042 || l2.var() == 27042)) {
IF_VERBOSE(1, verbose_stream() << "add_bin: " << l1 << " " << l2 << "\n");
}
#endif
#if 0
watched* w;
watch_list & wlist1 = get_wlist(~l1);
watch_list & wlist2 = get_wlist(~l2);
@ -1770,6 +1871,9 @@ namespace sat {
else {
wlist2.push_back(watched(l1, false));
}
#else
s.mk_bin_clause(l1, l2, false);
#endif
}
/**
@ -1786,6 +1890,11 @@ namespace sat {
watch_list::iterator end2 = wlist2.end();
for (; it2 != end2; ++it2) {
if (it2->is_binary_clause() && it2->get_literal() == l) {
if ((l.var() == 2039 || l2.var() == 2039) &&
(l.var() == 27042 || l2.var() == 27042)) {
IF_VERBOSE(1, verbose_stream() << "remove_bin: " << l << " " << l2 << "\n");
}
TRACE("bin_clause_bug", tout << "removing: " << l << " " << it2->get_literal() << "\n";);
m_sub_bin_todo.erase(bin_clause(l2, l, it2->is_learned()));
continue;
@ -1886,6 +1995,13 @@ namespace sat {
m_elim_counter -= num_pos * num_neg + before_lits;
if (false) {
literal l(v, false);
IF_VERBOSE(0,
verbose_stream() << "elim: " << l << "\n";
s.display_watch_list(verbose_stream() << ~l << ": ", get_wlist(l)) << "\n";
s.display_watch_list(verbose_stream() << l << ": ", get_wlist(~l)) << "\n";);
}
// eliminate variable
++s.m_stats.m_elim_var_res;
VERIFY(!is_external(v));
@ -1907,6 +2023,7 @@ namespace sat {
m_new_cls.reset();
if (!resolve(c1, c2, pos_l, m_new_cls))
continue;
if (false && v == 27041) IF_VERBOSE(0, verbose_stream() << "elim: " << c1 << " + " << c2 << " -> " << m_new_cls << "\n");
TRACE("resolution_new_cls", tout << c1 << "\n" << c2 << "\n-->\n" << m_new_cls << "\n";);
if (cleanup_clause(m_new_cls))
continue; // clause is already satisfied.
@ -1927,7 +2044,7 @@ namespace sat {
s.m_stats.m_mk_ter_clause++;
else
s.m_stats.m_mk_clause++;
clause * new_c = s.m_cls_allocator.mk_clause(m_new_cls.size(), m_new_cls.c_ptr(), false);
clause * new_c = s.alloc_clause(m_new_cls.size(), m_new_cls.c_ptr(), false);
if (s.m_config.m_drat) s.m_drat.add(*new_c, true);
s.m_clauses.push_back(new_c);
@ -1997,7 +2114,7 @@ namespace sat {
sat_simplifier_params p(_p);
m_cce = p.cce();
m_acce = p.acce();
m_bca = p.bca();
m_bca = false && p.bca(); // disabled
m_abce = p.abce();
m_ate = p.ate();
m_bce_delay = p.bce_delay();
@ -2018,7 +2135,7 @@ namespace sat {
m_subsumption = p.subsumption();
m_subsumption_limit = p.subsumption_limit();
m_elim_vars = p.elim_vars();
m_elim_vars_bdd = p.elim_vars_bdd();
m_elim_vars_bdd = false && p.elim_vars_bdd(); // buggy?
m_elim_vars_bdd_delay = p.elim_vars_bdd_delay();
m_incremental_mode = s.get_config().m_incremental && !p.override_incremental();
}

View file

@ -47,6 +47,7 @@ namespace sat {
clause_use_list & get(literal l) { return m_use_list[l.index()]; }
clause_use_list const & get(literal l) const { return m_use_list[l.index()]; }
void finalize() { m_use_list.finalize(); }
std::ostream& display(std::ostream& out, literal l) const { return m_use_list[l.index()].display(out); }
};
class simplifier {

View file

@ -37,6 +37,7 @@ namespace sat {
m_checkpoint_enabled(true),
m_config(p),
m_par(nullptr),
m_cls_allocator_idx(false),
m_par_syncing_clauses(false),
m_par_id(0),
m_cleaner(*this),
@ -78,7 +79,7 @@ namespace sat {
void solver::del_clauses(clause_vector& clauses) {
for (clause * cp : clauses)
m_cls_allocator.del_clause(cp);
dealloc_clause(cp);
clauses.reset();
++m_stats.m_non_learned_generation;
}
@ -298,7 +299,7 @@ namespace sat {
if (m_config.m_drat && !m_drat.is_cleaned(c)) {
m_drat.del(c);
}
m_cls_allocator.del_clause(&c);
dealloc_clause(&c);
m_stats.m_del_clause++;
}
@ -333,6 +334,12 @@ namespace sat {
}
void solver::mk_bin_clause(literal l1, literal l2, bool learned) {
#if 0
if ((l1.var() == 2039 || l2.var() == 2039) &&
(l1.var() == 27042 || l2.var() == 27042)) {
IF_VERBOSE(1, verbose_stream() << "mk_bin: " << l1 << " " << l2 << " " << learned << "\n");
}
#endif
if (find_binary_watch(get_wlist(~l1), ~l2)) {
assign(l1, justification());
return;
@ -345,13 +352,13 @@ namespace sat {
if (w0) {
if (w0->is_learned() && !learned) {
w0->set_learned(false);
}
w0 = find_binary_watch(get_wlist(~l2), l1);
}
if (w0) {
if (w0->is_learned() && !learned) {
w0->set_learned(false);
}
}
else {
return;
}
w0 = find_binary_watch(get_wlist(~l2), l1);
VERIFY(w0);
w0->set_learned(false);
return;
}
if (m_config.m_drat)
@ -390,7 +397,7 @@ namespace sat {
clause * solver::mk_ter_clause(literal * lits, bool learned) {
m_stats.m_mk_ter_clause++;
clause * r = m_cls_allocator.mk_clause(3, lits, learned);
clause * r = alloc_clause(3, lits, learned);
bool reinit = attach_ter_clause(*r);
if (reinit && !learned) push_reinit_stack(*r);
if (m_config.m_drat) m_drat.add(*r, learned);
@ -429,7 +436,7 @@ namespace sat {
clause * solver::mk_nary_clause(unsigned num_lits, literal * lits, bool learned) {
m_stats.m_mk_clause++;
clause * r = m_cls_allocator.mk_clause(num_lits, lits, learned);
clause * r = alloc_clause(num_lits, lits, learned);
SASSERT(!learned || r->is_learned());
bool reinit = attach_nary_clause(*r);
if (reinit && !learned) push_reinit_stack(*r);
@ -446,7 +453,7 @@ namespace sat {
bool solver::attach_nary_clause(clause & c) {
bool reinit = false;
clause_offset cls_off = m_cls_allocator.get_offset(&c);
clause_offset cls_off = cls_allocator().get_offset(&c);
if (!at_base_lvl()) {
if (c.is_learned()) {
unsigned w2_idx = select_learned_watch_lit(c);
@ -480,6 +487,8 @@ namespace sat {
return reinit;
}
static unsigned s_count = 0;
void solver::attach_clause(clause & c, bool & reinit) {
SASSERT(c.size() > 2);
reinit = false;
@ -503,6 +512,83 @@ namespace sat {
}
}
bool solver::memory_pressure() {
return 3*cls_allocator().get_allocation_size()/2 + memory::get_allocation_size() > memory::get_max_memory_size();
}
struct solver::cmp_activity {
solver& s;
cmp_activity(solver& s):s(s) {}
bool operator()(bool_var v1, bool_var v2) const {
return s.m_activity[v1] > s.m_activity[v2];
}
};
void solver::defrag_clauses() {
if (memory_pressure()) return;
IF_VERBOSE(1, verbose_stream() << "(sat-defrag)\n");
clause_allocator& alloc = m_cls_allocator[!m_cls_allocator_idx];
ptr_vector<clause> new_clauses, new_learned;
for (clause* c : m_clauses) c->unmark_used();
for (clause* c : m_learned) c->unmark_used();
svector<bool_var> vars;
for (unsigned i = 0; i < num_vars(); ++i) vars.push_back(i);
std::stable_sort(vars.begin(), vars.end(), cmp_activity(*this));
literal_vector lits;
for (bool_var v : vars) lits.push_back(literal(v, false)), lits.push_back(literal(v, true));
// walk clauses, reallocate them in an order that defragments memory and creates locality.
for (literal lit : lits) {
watch_list& wlist = m_watches[lit.index()];
// for (watch_list& wlist : m_watches) {
for (watched& w : wlist) {
if (w.is_clause()) {
clause& c1 = get_clause(w);
clause_offset offset;
if (c1.was_used()) {
offset = c1.get_new_offset();
}
else {
clause* c2 = alloc.copy_clause(c1);
c1.mark_used();
if (c1.is_learned()) {
new_learned.push_back(c2);
}
else {
new_clauses.push_back(c2);
}
offset = get_offset(*c2);
c1.set_new_offset(offset);
}
w = watched(w.get_blocked_literal(), offset);
}
}
}
// reallocate ternary clauses.
for (clause* c : m_clauses) {
if (!c->was_used()) {
SASSERT(c->size() == 3);
new_clauses.push_back(alloc.copy_clause(*c));
}
dealloc_clause(c);
}
for (clause* c : m_learned) {
if (!c->was_used()) {
SASSERT(c->size() == 3);
new_learned.push_back(alloc.copy_clause(*c));
}
dealloc_clause(c);
}
m_clauses.swap(new_clauses);
m_learned.swap(new_learned);
cls_allocator().finalize();
m_cls_allocator_idx = !m_cls_allocator_idx;
}
void solver::set_learned(literal l1, literal l2, bool learned) {
set_learned1(l1, l2, learned);
set_learned1(l2, l1, learned);
@ -669,7 +755,6 @@ namespace sat {
TRACE("sat_assign_core", tout << l << " " << j << " level: " << scope_lvl() << "\n";);
if (at_base_lvl()) {
if (m_config.m_drat) m_drat.add(l, !j.is_none());
j = justification(); // erase justification for level 0
}
m_assignment[l.index()] = l_true;
@ -695,6 +780,7 @@ namespace sat {
m_reasoned[v] = 0;
break;
}
if (m_config.m_anti_exploration) {
uint64 age = m_stats.m_conflict - m_canceled[v];
if (age > 0) {
@ -705,7 +791,10 @@ namespace sat {
m_case_split_queue.activity_changed_eh(v, false);
}
}
if (m_config.m_propagate_prefetch) {
_mm_prefetch((const char*)(m_watches[l.index()].c_ptr()), 1);
}
SASSERT(!l.sign() || m_phase[v] == NEG_PHASE);
SASSERT(l.sign() || m_phase[v] == POS_PHASE);
@ -718,9 +807,8 @@ namespace sat {
lbool solver::status(clause const & c) const {
bool found_undef = false;
unsigned sz = c.size();
for (unsigned i = 0; i < sz; i++) {
switch (value(c[i])) {
for (literal lit : c) {
switch (value(lit)) {
case l_true:
return l_true;
case l_undef:
@ -999,7 +1087,7 @@ namespace sat {
return l_undef;
}
restart();
restart(!m_config.m_restart_fast);
simplify_problem();
if (check_inconsistent()) return l_false;
gc();
@ -1213,7 +1301,7 @@ namespace sat {
}
}
if (num_in > 0 || num_out > 0) {
IF_VERBOSE(1, verbose_stream() << "(sat-sync out: " << num_out << " in: " << num_in << ")\n";);
IF_VERBOSE(2, verbose_stream() << "(sat-sync out: " << num_out << " in: " << num_in << ")\n";);
}
}
}
@ -1412,7 +1500,6 @@ namespace sat {
SASSERT(m_search_lvl == 1);
}
void solver::update_min_core() {
if (!m_min_core_valid || m_core.size() < m_min_core.size()) {
m_min_core.reset();
@ -1443,8 +1530,7 @@ namespace sat {
push();
reset_assumptions();
TRACE("sat", tout << "reassert: " << m_min_core << "\n";);
for (unsigned i = 0; i < m_min_core.size(); ++i) {
literal lit = m_min_core[i];
for (literal lit : m_min_core) {
SASSERT(is_external(lit.var()));
add_assumption(lit);
assign(lit, justification());
@ -1464,12 +1550,12 @@ namespace sat {
assign(m_assumptions[i], justification());
}
TRACE("sat",
for (unsigned i = 0; i < m_assumptions.size(); ++i) {
index_set s;
if (m_antecedents.find(m_assumptions[i].var(), s)) {
tout << m_assumptions[i] << ": "; display_index_set(tout, s) << "\n";
}
});
for (literal a : m_assumptions) {
index_set s;
if (m_antecedents.find(a.var(), s)) {
tout << a << ": "; display_index_set(tout, s) << "\n";
}
});
}
}
@ -1496,10 +1582,11 @@ namespace sat {
m_restarts = 0;
m_simplifications = 0;
m_conflicts_since_init = 0;
m_next_simplify = 0;
m_next_simplify = m_config.m_simplify_delay;
m_min_d_tk = 1.0;
m_search_lvl = 0;
m_conflicts_since_gc = 0;
m_restart_next_out = 0;
m_asymm_branch.init_search();
m_stopwatch.reset();
m_stopwatch.start();
@ -1511,7 +1598,6 @@ namespace sat {
/**
\brief Apply all simplifications.
*/
void solver::simplify_problem() {
if (m_conflicts_since_init < m_next_simplify) {
@ -1566,7 +1652,7 @@ namespace sat {
reinit_assumptions();
if (m_next_simplify == 0) {
m_next_simplify = m_config.m_restart_initial * m_config.m_simplify_mult1;
m_next_simplify = m_config.m_next_simplify1;
}
else {
m_next_simplify = static_cast<unsigned>(m_conflicts_since_init * m_config.m_simplify_mult2);
@ -1652,10 +1738,14 @@ namespace sat {
// m_mc.set_solver(nullptr);
m_mc(m_model);
if (!check_clauses(m_model)) {
IF_VERBOSE(0, verbose_stream() << "failure checking clauses on transformed model\n";);
IF_VERBOSE(10, m_mc.display(verbose_stream()));
//IF_VERBOSE(0, display_units(verbose_stream()));
//IF_VERBOSE(0, display(verbose_stream()));
IF_VERBOSE(0, for (bool_var v = 0; v < num; v++) verbose_stream() << v << ": " << m_model[v] << "\n";);
throw solver_exception("check model failed");
}
@ -1666,7 +1756,9 @@ namespace sat {
if (!m_clone->check_model(m_model)) {
//IF_VERBOSE(0, display(verbose_stream()));
//IF_VERBOSE(0, display_watches(verbose_stream()));
//IF_VERBOSE(0, m_mc.display(verbose_stream()));
IF_VERBOSE(0, m_mc.display(verbose_stream()));
IF_VERBOSE(0, display_units(verbose_stream()));
//IF_VERBOSE(0, m_clone->display(verbose_stream() << "clone\n"));
throw solver_exception("check model failed (for cloned solver)");
}
}
@ -1739,15 +1831,42 @@ namespace sat {
return ok;
}
void solver::restart() {
void solver::restart(bool to_base) {
m_stats.m_restart++;
m_restarts++;
IF_VERBOSE(1,
verbose_stream() << "(sat-restart :conflicts " << m_stats.m_conflict << " :decisions " << m_stats.m_decision
<< " :restarts " << m_stats.m_restart << mk_stat(*this)
<< " :time " << std::fixed << std::setprecision(2) << m_stopwatch.get_current_seconds() << ")\n";);
if (m_conflicts_since_init > m_restart_next_out + 500) {
m_restart_next_out = m_conflicts_since_init;
IF_VERBOSE(1,
verbose_stream() << "(sat-restart :conflicts " << m_stats.m_conflict << " :decisions " << m_stats.m_decision
<< " :restarts " << m_stats.m_restart << mk_stat(*this)
<< " :time " << std::fixed << std::setprecision(2) << m_stopwatch.get_current_seconds() << ")\n";);
}
IF_VERBOSE(30, display_status(verbose_stream()););
pop_reinit(scope_lvl() - search_lvl());
unsigned num_scopes = 0;
if (to_base || scope_lvl() == search_lvl()) {
num_scopes = scope_lvl() - search_lvl();
}
else {
bool_var next = m_case_split_queue.min_var();
// Implementations of Marijn's idea of reusing the
// trail when the next decision literal has lower precedence.
#if 0
// pop the trail from top
do {
bool_var prev = scope_literal(scope_lvl() - num_scopes - 1).var();
if (m_case_split_queue.more_active(prev, next)) break;
++num_scopes;
}
while (num_scopes < scope_lvl() - search_lvl());
#else
// pop the trail from bottom
unsigned n = search_lvl();
for (; n < scope_lvl() && m_case_split_queue.more_active(scope_literal(n).var(), next); ++n) ;
num_scopes = n - search_lvl();
#endif
}
pop_reinit(num_scopes);
m_conflicts_since_restart = 0;
switch (m_config.m_restart) {
case RS_GEOMETRIC:
@ -1775,6 +1894,7 @@ namespace sat {
return;
if (m_config.m_gc_strategy == GC_DYN_PSM && !at_base_lvl())
return;
unsigned gc = m_stats.m_gc_clause;
IF_VERBOSE(10, verbose_stream() << "(sat.gc)\n";);
CASSERT("sat_gc_bug", check_invariant());
switch (m_config.m_gc_strategy) {
@ -1800,6 +1920,11 @@ namespace sat {
break;
}
if (m_ext) m_ext->gc();
if (gc > 0 && m_config.m_gc_defrag && !memory_pressure()) {
pop(scope_lvl());
defrag_clauses();
reinit_assumptions();
}
m_conflicts_since_gc = 0;
m_gc_threshold += m_config.m_gc_increment;
CASSERT("sat_gc_bug", check_invariant());
@ -2307,8 +2432,7 @@ namespace sat {
void solver::resolve_conflict_for_unsat_core() {
TRACE("sat", display(tout);
unsigned level = 0;
for (unsigned i = 0; i < m_trail.size(); ++i) {
literal l = m_trail[i];
for (literal l : m_trail) {
if (level != m_level[l.var()]) {
level = m_level[l.var()];
tout << level << ": ";
@ -2328,8 +2452,8 @@ namespace sat {
}
SASSERT(m_unmark.empty());
DEBUG_CODE({
for (unsigned i = 0; i < m_trail.size(); ++i) {
SASSERT(!is_marked(m_trail[i].var()));
for (literal lit : m_trail) {
SASSERT(!is_marked(lit.var()));
}});
unsigned old_size = m_unmark.size();
@ -2739,7 +2863,8 @@ 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) {
if (m_config.m_branching_heuristic == BH_LRB ||
m_config.m_branching_heuristic == BH_VSIDS) {
update_lrb_reasoned();
}
literal_vector::iterator it = m_lemma.begin();
@ -2785,8 +2910,7 @@ namespace sat {
}
}
reset_mark(m_lemma[0].var());
for (unsigned i = m_lemma.size(); i > sz; ) {
--i;
for (unsigned i = m_lemma.size(); i-- > sz; ) {
reset_mark(m_lemma[i].var());
}
m_lemma.shrink(sz);
@ -2797,6 +2921,7 @@ namespace sat {
if (!is_marked(v)) {
mark(v);
m_reasoned[v]++;
inc_activity(v);
m_lemma.push_back(lit);
}
}
@ -3426,7 +3551,7 @@ namespace sat {
}
void solver::display_watches(std::ostream & out, literal lit) const {
sat::display_watch_list(out << lit << ": ", m_cls_allocator, get_wlist(lit)) << "\n";
display_watch_list(out << lit << ": ", get_wlist(lit)) << "\n";
}
void solver::display_watches(std::ostream & out) const {
@ -3434,10 +3559,14 @@ namespace sat {
for (watch_list const& wlist : m_watches) {
literal l = to_literal(l_idx++);
if (!wlist.empty())
sat::display_watch_list(out << l << ": ", m_cls_allocator, wlist) << "\n";
display_watch_list(out << l << ": ", wlist) << "\n";
}
}
std::ostream& solver::display_watch_list(std::ostream& out, watch_list const& wl) const {
return sat::display_watch_list(out, cls_allocator(), wl);
}
void solver::display_assignment(std::ostream & out) const {
out << m_trail << "\n";
}
@ -3769,7 +3898,7 @@ namespace sat {
return l_undef;
}
restart();
restart(true);
simplify_problem();
if (check_inconsistent()) {
fixup_consequence_core();
@ -3862,7 +3991,7 @@ namespace sat {
else {
is_sat = bounded_search();
if (is_sat == l_undef) {
restart();
restart(true);
}
extract_fixed_consequences(unfixed_lits, assumptions, unfixed_vars, conseq);
}

View file

@ -86,7 +86,8 @@ namespace sat {
scoped_ptr<extension> m_ext;
parallel* m_par;
random_gen m_rand;
clause_allocator m_cls_allocator;
clause_allocator m_cls_allocator[2];
bool m_cls_allocator_idx;
cleaner m_cleaner;
model m_model;
model_converter m_mc;
@ -217,9 +218,16 @@ namespace sat {
void mk_clause(literal_vector const& lits, bool learned = false) { mk_clause(lits.size(), lits.c_ptr(), learned); }
void mk_clause(unsigned num_lits, literal * lits, bool learned = false);
void mk_clause(literal l1, literal l2, bool learned = false);
void mk_clause(literal l1, literal l2, literal l3, bool learned = false);
void mk_clause(literal l1, literal l2, literal l3, bool learned = false);
protected:
inline clause_allocator& cls_allocator() { return m_cls_allocator[m_cls_allocator_idx]; }
inline clause_allocator const& cls_allocator() const { return m_cls_allocator[m_cls_allocator_idx]; }
inline clause * alloc_clause(unsigned num_lits, literal const * lits, bool learned) { return cls_allocator().mk_clause(num_lits, lits, learned); }
inline void dealloc_clause(clause* c) { cls_allocator().del_clause(c); }
struct cmp_activity;
void defrag_clauses();
bool memory_pressure();
void del_clause(clause & c);
clause * mk_clause_core(unsigned num_lits, literal * lits, bool learned);
clause * mk_clause_core(literal_vector const& lits) { return mk_clause_core(lits.size(), lits.c_ptr()); }
@ -236,6 +244,10 @@ namespace sat {
void set_learned(clause& c, bool learned);
void set_learned(literal l1, literal l2, bool learned);
void set_learned1(literal l1, literal l2, bool learned);
void add_ate(clause& c) { m_mc.add_ate(c); }
void add_ate(literal l1, literal l2) { m_mc.add_ate(l1, l2); }
void add_ate(literal_vector const& lits) { m_mc.add_ate(lits); }
class scoped_disable_checkpoint {
solver& s;
public:
@ -285,6 +297,7 @@ namespace sat {
unsigned lvl(literal l) const { return m_level[l.var()]; }
unsigned init_trail_size() const { return at_base_lvl() ? m_trail.size() : m_scopes[0].m_trail_lim; }
literal trail_literal(unsigned i) const { return m_trail[i]; }
literal scope_literal(unsigned n) const { return m_trail[m_scopes[n].m_trail_lim]; }
void assign(literal l, justification j) {
TRACE("sat_assign", tout << l << " previous value: " << value(l) << "\n";);
switch (value(l)) {
@ -297,7 +310,7 @@ namespace sat {
void set_conflict(justification c, literal not_l);
void set_conflict(justification c) { set_conflict(c, null_literal); }
lbool status(clause const & c) const;
clause_offset get_offset(clause const & c) const { return m_cls_allocator.get_offset(&c); }
clause_offset get_offset(clause const & c) const { return cls_allocator().get_offset(&c); }
void checkpoint() {
if (!m_checkpoint_enabled) return;
if (!m_rlimit.inc()) {
@ -369,6 +382,7 @@ namespace sat {
unsigned m_conflicts_since_init;
unsigned m_restarts;
unsigned m_restart_next_out;
unsigned m_conflicts_since_restart;
unsigned m_simplifications;
unsigned m_restart_threshold;
@ -401,7 +415,7 @@ namespace sat {
void simplify_problem();
void mk_model();
bool check_model(model const & m) const;
void restart();
void restart(bool to_base);
void sort_watch_lits();
void exchange_par();
lbool check_par(unsigned num_lits, literal const* lits);
@ -433,7 +447,7 @@ namespace sat {
if (value(l0) != l_true)
return true;
justification const & jst = m_justification[l0.var()];
return !jst.is_clause() || m_cls_allocator.get_clause(jst.get_clause_offset()) != &c;
return !jst.is_clause() || cls_allocator().get_clause(jst.get_clause_offset()) != &c;
}
clause& get_clause(watch_list::iterator it) const {
@ -441,13 +455,18 @@ namespace sat {
return get_clause(it->get_clause_offset());
}
clause& get_clause(watched const& w) const {
SASSERT(w.get_kind() == watched::CLAUSE);
return get_clause(w.get_clause_offset());
}
clause& get_clause(justification const& j) const {
SASSERT(j.is_clause());
return get_clause(j.get_clause_offset());
}
clause& get_clause(clause_offset cls_off) const {
return *(m_cls_allocator.get_clause(cls_off));
return *(cls_allocator().get_clause(cls_off));
}
// -----------------------
@ -630,6 +649,7 @@ namespace sat {
void display_wcnf(std::ostream & out, unsigned sz, literal const* lits, unsigned const* weights) const;
void display_assignment(std::ostream & out) const;
std::ostream& display_justification(std::ostream & out, justification const& j) const;
std::ostream& display_watch_list(std::ostream& out, watch_list const& wl) const;
protected:
void display_binary(std::ostream & out) const;

View file

@ -24,6 +24,8 @@ Notes:
#include "ast/ast_util.h"
#include "solver/solver.h"
#include "solver/tactic2solver.h"
#include "solver/parallel_params.hpp"
#include "solver/parallel_tactic.h"
#include "tactic/tactical.h"
#include "tactic/aig/aig_tactic.h"
#include "tactic/core/propagate_values_tactic.h"
@ -31,14 +33,15 @@ Notes:
#include "tactic/arith/card2bv_tactic.h"
#include "tactic/bv/bit_blaster_tactic.h"
#include "tactic/core/simplify_tactic.h"
#include "tactic/core/solve_eqs_tactic.h"
#include "tactic/bv/bit_blaster_model_converter.h"
#include "model/model_smt2_pp.h"
#include "model/model_v2_pp.h"
#include "model/model_evaluator.h"
#include "tactic/bv/bit_blaster_model_converter.h"
#include "tactic/core/propagate_values_tactic.h"
#include "sat/sat_solver.h"
#include "sat/sat_params.hpp"
#include "sat/tactic/goal2sat.h"
#include "sat/tactic/sat_tactic.h"
#include "sat/sat_simplifier_params.hpp"
// incremental SAT solver.
@ -281,9 +284,12 @@ public:
m_params.append(p);
sat_params p1(p);
m_params.set_bool("keep_cardinality_constraints", p1.cardinality_solver());
m_params.set_sym("pb.solver", p1.pb_solver());
m_params.set_bool("keep_pb_constraints", m_solver.get_config().m_pb_solver == sat::PB_SOLVER);
m_params.set_bool("pb_num_system", m_solver.get_config().m_pb_solver == sat::PB_SORTING);
m_params.set_bool("pb_totalizer", m_solver.get_config().m_pb_solver == sat::PB_TOTALIZER);
m_params.set_bool("xor_solver", p1.xor_solver());
m_solver.updt_params(m_params);
m_solver.set_incremental(is_incremental() && !override_incremental());
@ -498,7 +504,10 @@ public:
simp2_p.set_bool("elim_and", true);
simp2_p.set_bool("blast_distinct", true);
m_preprocess =
and_then(mk_card2bv_tactic(m, m_params), // updates model converter
and_then(mk_simplify_tactic(m),
mk_propagate_values_tactic(m),
//time consuming if done in inner loop: mk_solve_eqs_tactic(m, simp2_p),
mk_card2bv_tactic(m, m_params), // updates model converter
using_params(mk_simplify_tactic(m), simp2_p),
mk_max_bv_sharing_tactic(m),
mk_bit_blaster_tactic(m, m_bb_rewriter.get()), // updates model converter
@ -859,3 +868,9 @@ void inc_sat_display(std::ostream& out, solver& _s, unsigned sz, expr*const* sof
s.display_weighted(out, sz, soft, weights.c_ptr());
}
tactic * mk_psat_tactic(ast_manager& m, params_ref const& p) {
parallel_params pp(p);
bool use_parallel = pp.enable();
return pp.enable() ? mk_parallel_tactic(mk_inc_sat_solver(m, p, false), p) : mk_sat_tactic(m);
}

View file

@ -22,8 +22,12 @@ Notes:
#include "solver/solver.h"
class tactic;
solver* mk_inc_sat_solver(ast_manager& m, params_ref const& p, bool incremental_mode = true);
tactic* mk_psat_tactic(ast_manager& m, params_ref const& p);
void inc_sat_display(std::ostream& out, solver& s, unsigned sz, expr*const* soft, rational const* _weights);

View file

@ -72,6 +72,8 @@ namespace sat {
bool_var next_var() { SASSERT(!empty()); return m_queue.erase_min(); }
bool_var min_var() { SASSERT(!empty()); return m_queue.min_value(); }
bool more_active(bool_var v1, bool_var v2) const { return m_queue.less_than(v1, v2); }
};
};

View file

@ -20,6 +20,8 @@ Notes:
#include "tactic/tactical.h"
#include "sat/tactic/goal2sat.h"
#include "sat/sat_solver.h"
#include "solver/parallel_tactic.h"
#include "solver/parallel_params.hpp"
#include "model/model_v2_pp.h"
class sat_tactic : public tactic {
@ -215,3 +217,4 @@ tactic * mk_sat_preprocessor_tactic(ast_manager & m, params_ref const & p) {
return t;
}