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:
commit
859c68c2ac
58 changed files with 1329 additions and 526 deletions
|
@ -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
101
src/sat/sat_allocator.h
Normal 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_ */
|
||||
|
|
@ -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;
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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')))
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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); }
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue