mirror of
https://github.com/Z3Prover/z3
synced 2025-04-23 09:05:31 +00:00
Reorganizing the code
Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
parent
8a6997960a
commit
c66b9ab615
39 changed files with 1 additions and 1 deletions
33
src/sat/luby.cpp
Normal file
33
src/sat/luby.cpp
Normal file
|
@ -0,0 +1,33 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
luby.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-03-04.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include<cmath>
|
||||
|
||||
unsigned get_luby(unsigned i) {
|
||||
if (i == 1)
|
||||
return 1;
|
||||
double k = log(static_cast<double>(i+1))/log(static_cast<double>(2));
|
||||
|
||||
if (k == floor(k + 0.5))
|
||||
return static_cast<unsigned>(pow(2,k-1));
|
||||
else {
|
||||
k = static_cast<unsigned>(floor(k));
|
||||
return get_luby(i - static_cast<unsigned>(pow(2, k)) + 1);
|
||||
}
|
||||
}
|
||||
|
31
src/sat/luby.h
Normal file
31
src/sat/luby.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
luby.h
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-03-04.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _LUBY_H_
|
||||
#define _LUBY_H_
|
||||
|
||||
/**
|
||||
\brief Return the i-th element of the Luby sequence: 1,1,2,1,1,2,4,1,1,2,1,1,2,4,8,...
|
||||
|
||||
get_luby(i) = 2^{i-1} if i = 2^k -1
|
||||
get_luby(i) = get_luby(i - 2^{k-1} + 1) if 2^{k-1} <= i < 2^k - 1
|
||||
*/
|
||||
unsigned get_luby(unsigned i);
|
||||
|
||||
#endif /* _LUBY_H_ */
|
||||
|
218
src/sat/sat_asymm_branch.cpp
Normal file
218
src/sat/sat_asymm_branch.cpp
Normal file
|
@ -0,0 +1,218 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
sat_asymm_branch.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
SAT solver asymmetric branching
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2011-05-30.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include"sat_asymm_branch.h"
|
||||
#include"sat_solver.h"
|
||||
#include"stopwatch.h"
|
||||
#include"trace.h"
|
||||
|
||||
namespace sat {
|
||||
|
||||
asymm_branch::asymm_branch(solver & _s, params_ref const & p):
|
||||
s(_s),
|
||||
m_counter(0) {
|
||||
updt_params(p);
|
||||
reset_statistics();
|
||||
}
|
||||
|
||||
struct clause_size_lt {
|
||||
bool operator()(clause * c1, clause * c2) const { return c1->size() > c2->size(); }
|
||||
};
|
||||
|
||||
struct asymm_branch::report {
|
||||
asymm_branch & m_asymm_branch;
|
||||
stopwatch m_watch;
|
||||
unsigned m_elim_literals;
|
||||
report(asymm_branch & a):
|
||||
m_asymm_branch(a),
|
||||
m_elim_literals(a.m_elim_literals) {
|
||||
m_watch.start();
|
||||
}
|
||||
|
||||
~report() {
|
||||
m_watch.stop();
|
||||
IF_VERBOSE(SAT_VB_LVL,
|
||||
verbose_stream() << " (sat-asymm-branch :elim-literals "
|
||||
<< (m_asymm_branch.m_elim_literals - m_elim_literals)
|
||||
<< " :cost " << m_asymm_branch.m_counter
|
||||
<< mem_stat()
|
||||
<< " :time " << std::fixed << std::setprecision(2) << m_watch.get_seconds() << ")\n";);
|
||||
}
|
||||
};
|
||||
|
||||
void asymm_branch::operator()(bool force) {
|
||||
if (!m_asymm_branch)
|
||||
return;
|
||||
s.propagate(false); // must propagate, since it uses s.push()
|
||||
if (s.m_inconsistent)
|
||||
return;
|
||||
if (!force && m_counter > 0)
|
||||
return;
|
||||
CASSERT("asymm_branch", s.check_invariant());
|
||||
TRACE("asymm_branch_detail", s.display(tout););
|
||||
report rpt(*this);
|
||||
svector<char> saved_phase(s.m_phase);
|
||||
m_counter = 0; // counter is moving down to capture propagate cost.
|
||||
int limit = -static_cast<int>(m_asymm_branch_limit);
|
||||
std::stable_sort(s.m_clauses.begin(), s.m_clauses.end(), clause_size_lt());
|
||||
m_counter -= s.m_clauses.size();
|
||||
clause_vector::iterator it = s.m_clauses.begin();
|
||||
clause_vector::iterator it2 = it;
|
||||
clause_vector::iterator end = s.m_clauses.end();
|
||||
try {
|
||||
for (; it != end; ++it) {
|
||||
SASSERT(s.m_qhead == s.m_trail.size());
|
||||
if (m_counter < limit || s.inconsistent()) {
|
||||
*it2 = *it;
|
||||
++it2;
|
||||
continue;
|
||||
}
|
||||
s.checkpoint();
|
||||
clause & c = *(*it);
|
||||
m_counter -= c.size();
|
||||
if (!process(c))
|
||||
continue; // clause was removed
|
||||
*it2 = *it;
|
||||
// throw exception to test bug fix: if (it2 != it) throw solver_exception("trigger bug");
|
||||
++it2;
|
||||
}
|
||||
s.m_clauses.set_end(it2);
|
||||
}
|
||||
catch (solver_exception & ex) {
|
||||
// put m_clauses in a consistent state...
|
||||
for (; it != end; ++it, ++it2) {
|
||||
*it2 = *it;
|
||||
}
|
||||
s.m_clauses.set_end(it2);
|
||||
m_counter = -m_counter;
|
||||
throw ex;
|
||||
}
|
||||
m_counter = -m_counter;
|
||||
s.m_phase = saved_phase;
|
||||
CASSERT("asymm_branch", s.check_invariant());
|
||||
}
|
||||
|
||||
bool asymm_branch::process(clause & c) {
|
||||
TRACE("asymm_branch_detail", tout << "processing: " << c << "\n";);
|
||||
SASSERT(s.scope_lvl() == 0);
|
||||
#ifdef Z3DEBUG
|
||||
unsigned trail_sz = s.m_trail.size();
|
||||
#endif
|
||||
SASSERT(!s.inconsistent());
|
||||
unsigned sz = c.size();
|
||||
SASSERT(sz > 0);
|
||||
unsigned i;
|
||||
// check if the clause is already satisfied
|
||||
for (i = 0; i < sz; i++) {
|
||||
if (s.value(c[i]) == l_true) {
|
||||
s.dettach_clause(c);
|
||||
s.del_clause(c);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// try asymmetric branching
|
||||
// clause must not be used for propagation
|
||||
s.dettach_clause(c);
|
||||
s.push();
|
||||
for (i = 0; i < sz - 1; i++) {
|
||||
literal l = c[i];
|
||||
SASSERT(!s.inconsistent());
|
||||
TRACE("asymm_branch_detail", tout << "assigning: " << ~l << "\n";);
|
||||
s.assign(~l, justification());
|
||||
s.propagate_core(false); // must not use propagate(), since check_missed_propagation may fail for c
|
||||
if (s.inconsistent())
|
||||
break;
|
||||
}
|
||||
s.pop(1);
|
||||
SASSERT(!s.inconsistent());
|
||||
SASSERT(s.scope_lvl() == 0);
|
||||
SASSERT(trail_sz == s.m_trail.size());
|
||||
if (i == sz - 1) {
|
||||
// clause size can't be reduced.
|
||||
s.attach_clause(c);
|
||||
return true;
|
||||
}
|
||||
// clause can be reduced
|
||||
unsigned new_sz = i+1;
|
||||
SASSERT(new_sz >= 1);
|
||||
SASSERT(new_sz < sz);
|
||||
TRACE("asymm_branch", tout << c << "\nnew_size: " << new_sz << "\n";
|
||||
for (unsigned i = 0; i < c.size(); i++) tout << static_cast<int>(s.value(c[i])) << " "; tout << "\n";);
|
||||
// cleanup reduced clause
|
||||
unsigned j = 0;
|
||||
for (i = 0; i < new_sz; i++) {
|
||||
literal l = c[i];
|
||||
switch (s.value(l)) {
|
||||
case l_undef:
|
||||
c[j] = l;
|
||||
j++;
|
||||
break;
|
||||
case l_false:
|
||||
break;
|
||||
case l_true:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
}
|
||||
new_sz = j;
|
||||
m_elim_literals += sz - new_sz;
|
||||
switch(new_sz) {
|
||||
case 0:
|
||||
s.set_conflict(justification());
|
||||
return false;
|
||||
case 1:
|
||||
TRACE("asymm_branch", tout << "produced unit clause: " << c[0] << "\n";);
|
||||
s.assign(c[0], justification());
|
||||
s.del_clause(c);
|
||||
s.propagate_core(false);
|
||||
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);
|
||||
s.mk_bin_clause(c[0], c[1], false);
|
||||
s.del_clause(c);
|
||||
return false;
|
||||
default:
|
||||
c.shrink(new_sz);
|
||||
s.attach_clause(c);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void asymm_branch::updt_params(params_ref const & p) {
|
||||
m_asymm_branch = p.get_bool(":asymm-branch", true);
|
||||
m_asymm_branch_rounds = p.get_uint(":asymm-branch-rounds", 32);
|
||||
m_asymm_branch_limit = p.get_uint(":asymm-branch-limit", 100000000);
|
||||
if (m_asymm_branch_limit > INT_MAX)
|
||||
m_asymm_branch_limit = INT_MAX;
|
||||
}
|
||||
|
||||
void asymm_branch::collect_param_descrs(param_descrs & d) {
|
||||
d.insert(":asymm-branch", CPK_BOOL, "(default: true) asymmetric branching.");
|
||||
d.insert(":asymm-branch-rounds", CPK_UINT, "(default: 32) maximum number of rounds of asymmetric branching.");
|
||||
d.insert(":asymm-branch-limit", CPK_UINT, "approx. maximum number of literals visited during asymmetric branching.");
|
||||
}
|
||||
|
||||
void asymm_branch::collect_statistics(statistics & st) {
|
||||
st.update("elim literals", m_elim_literals);
|
||||
}
|
||||
|
||||
void asymm_branch::reset_statistics() {
|
||||
m_elim_literals = 0;
|
||||
}
|
||||
|
||||
};
|
60
src/sat/sat_asymm_branch.h
Normal file
60
src/sat/sat_asymm_branch.h
Normal file
|
@ -0,0 +1,60 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
sat_asymm_branch.h
|
||||
|
||||
Abstract:
|
||||
|
||||
SAT solver asymmetric branching
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2011-05-30.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _SAT_ASYMM_BRANCH_H_
|
||||
#define _SAT_ASYMM_BRANCH_H_
|
||||
|
||||
#include"sat_types.h"
|
||||
#include"statistics.h"
|
||||
#include"params.h"
|
||||
|
||||
namespace sat {
|
||||
class solver;
|
||||
|
||||
class asymm_branch {
|
||||
struct report;
|
||||
|
||||
solver & s;
|
||||
int m_counter;
|
||||
|
||||
// config
|
||||
bool m_asymm_branch;
|
||||
unsigned m_asymm_branch_rounds;
|
||||
unsigned m_asymm_branch_limit;
|
||||
|
||||
// stats
|
||||
unsigned m_elim_literals;
|
||||
|
||||
bool process(clause & c);
|
||||
public:
|
||||
asymm_branch(solver & s, params_ref const & p);
|
||||
|
||||
void operator()(bool force = false);
|
||||
|
||||
void updt_params(params_ref const & p);
|
||||
static void collect_param_descrs(param_descrs & d);
|
||||
|
||||
void collect_statistics(statistics & st);
|
||||
void reset_statistics();
|
||||
|
||||
void dec(unsigned c) { m_counter -= c; }
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif
|
236
src/sat/sat_clause.cpp
Normal file
236
src/sat/sat_clause.cpp
Normal file
|
@ -0,0 +1,236 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
sat_clause.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Clauses
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2011-05-21.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include"memory.h"
|
||||
#include"sat_clause.h"
|
||||
#include"z3_exception.h"
|
||||
|
||||
namespace sat {
|
||||
|
||||
clause::clause(unsigned id, unsigned sz, literal const * lits, bool learned):
|
||||
m_id(id),
|
||||
m_size(sz),
|
||||
m_capacity(sz),
|
||||
m_removed(false),
|
||||
m_learned(learned),
|
||||
m_used(false),
|
||||
m_frozen(false),
|
||||
m_reinit_stack(false),
|
||||
m_inact_rounds(0) {
|
||||
memcpy(m_lits, lits, sizeof(literal) * sz);
|
||||
mark_strengthened();
|
||||
SASSERT(check_approx());
|
||||
}
|
||||
|
||||
var_approx_set clause::approx(unsigned num, literal const * lits) {
|
||||
var_approx_set r;
|
||||
for (unsigned i = 0; i < num; i++)
|
||||
r.insert(lits[i].var());
|
||||
return r;
|
||||
}
|
||||
|
||||
void clause::update_approx() {
|
||||
m_approx = approx(m_size, m_lits);
|
||||
}
|
||||
|
||||
bool clause::check_approx() const {
|
||||
var_approx_set curr = m_approx;
|
||||
const_cast<clause*>(this)->update_approx();
|
||||
SASSERT(may_eq(curr, m_approx));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool clause::contains(literal l) const {
|
||||
for (unsigned i = 0; i < m_size; i++)
|
||||
if (m_lits[i] == l)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool clause::contains(bool_var v) const {
|
||||
for (unsigned i = 0; i < m_size; i++)
|
||||
if (m_lits[i].var() == v)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void clause::elim(literal l) {
|
||||
unsigned i;
|
||||
for (i = 0; i < m_size; i++)
|
||||
if (m_lits[i] == l)
|
||||
break;
|
||||
SASSERT(i < m_size);
|
||||
i++;
|
||||
for (; i < m_size; i++)
|
||||
m_lits[i-1] = m_lits[i];
|
||||
m_size--;
|
||||
mark_strengthened();
|
||||
}
|
||||
|
||||
bool clause::satisfied_by(model const & m) const {
|
||||
for (unsigned i = 0; i < m_size; i++) {
|
||||
literal l = m_lits[i];
|
||||
if (l.sign()) {
|
||||
if (m[l.var()] == l_false)
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
if (m[l.var()] == l_true)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
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);
|
||||
m_clause = 0;
|
||||
}
|
||||
if (!m_clause) {
|
||||
void * mem = alloc_svect(char, clause::get_obj_size(num_lits));
|
||||
m_clause = new (mem) clause(UINT_MAX, num_lits, lits, learned);
|
||||
}
|
||||
else {
|
||||
SASSERT(m_clause->m_id == UINT_MAX);
|
||||
m_clause->m_size = num_lits;
|
||||
m_clause->m_learned = learned;
|
||||
memcpy(m_clause->m_lits, lits, sizeof(literal) * num_lits);
|
||||
}
|
||||
SASSERT(m_clause->m_size <= m_clause->m_capacity);
|
||||
for (unsigned i = 0; i < num_lits; i++) {
|
||||
SASSERT((*m_clause)[i] == lits[i]);
|
||||
}
|
||||
}
|
||||
|
||||
clause_allocator::clause_allocator():
|
||||
m_allocator("clause-allocator") {
|
||||
#ifdef _AMD64_
|
||||
m_num_segments = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
clause * clause_allocator::get_clause(clause_offset cls_off) const {
|
||||
#ifdef _AMD64_
|
||||
return reinterpret_cast<clause *>(m_segments[cls_off & c_aligment_mask] + (static_cast<size_t>(cls_off) & ~c_aligment_mask));
|
||||
#else
|
||||
return reinterpret_cast<clause *>(cls_off);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef _AMD64_
|
||||
unsigned clause_allocator::get_segment(size_t ptr) {
|
||||
SASSERT((ptr & c_aligment_mask) == 0);
|
||||
ptr &= ~0xFFFFFFFFull; // Keep only high part
|
||||
unsigned i = 0;
|
||||
for (i = 0; i < m_num_segments; ++i)
|
||||
if (m_segments[i] == ptr)
|
||||
return i;
|
||||
i = m_num_segments;
|
||||
m_num_segments++;
|
||||
if (i > c_max_segments)
|
||||
throw default_exception("segment out of range");
|
||||
m_segments[i] = ptr;
|
||||
return i;
|
||||
}
|
||||
#endif
|
||||
|
||||
clause_offset clause_allocator::get_offset(clause const * ptr) const {
|
||||
#ifdef _AMD64_
|
||||
return static_cast<unsigned>(reinterpret_cast<size_t>(ptr)) + const_cast<clause_allocator*>(this)->get_segment(reinterpret_cast<size_t>(ptr));
|
||||
#else
|
||||
return reinterpret_cast<size_t>(ptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
clause * clause_allocator::mk_clause(unsigned num_lits, literal const * lits, bool learned) {
|
||||
size_t size = clause::get_obj_size(num_lits);
|
||||
#ifdef _AMD64_
|
||||
size_t slot = size >> c_cls_alignment;
|
||||
if ((size & c_aligment_mask) != 0)
|
||||
slot++;
|
||||
size = slot << c_cls_alignment;
|
||||
#endif
|
||||
void * mem = m_allocator.allocate(size);
|
||||
clause * cls = new (mem) clause(m_id_gen.mk(), num_lits, lits, learned);
|
||||
SASSERT(!learned || cls->is_learned());
|
||||
return cls;
|
||||
}
|
||||
|
||||
void clause_allocator::del_clause(clause * cls) {
|
||||
m_id_gen.recycle(cls->id());
|
||||
size_t size = clause::get_obj_size(cls->m_capacity);
|
||||
#ifdef _AMD64_
|
||||
size_t slot = size >> c_cls_alignment;
|
||||
if ((size & c_aligment_mask) != 0)
|
||||
slot++;
|
||||
size = slot << c_cls_alignment;
|
||||
#endif
|
||||
cls->~clause();
|
||||
m_allocator.deallocate(size, cls);
|
||||
}
|
||||
|
||||
std::ostream & operator<<(std::ostream & out, clause const & c) {
|
||||
out << "(";
|
||||
for (unsigned i = 0; i < c.size(); i++) {
|
||||
if (i > 0) out << " ";
|
||||
out << c[i];
|
||||
}
|
||||
out << ")";
|
||||
if (c.was_removed()) out << "x";
|
||||
if (c.strengthened()) out << "+";
|
||||
if (c.is_learned()) out << "*";
|
||||
return out;
|
||||
}
|
||||
|
||||
std::ostream & operator<<(std::ostream & out, clause_vector const & cs) {
|
||||
clause_vector::const_iterator it = cs.begin();
|
||||
clause_vector::const_iterator end = cs.end();
|
||||
for (; it != end; ++it) {
|
||||
out << *(*it) << "\n";
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
bool clause_wrapper::contains(literal l) const {
|
||||
unsigned sz = size();
|
||||
for (unsigned i = 0; i < sz; i++)
|
||||
if (operator[](i) == l)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool clause_wrapper::contains(bool_var v) const {
|
||||
unsigned sz = size();
|
||||
for (unsigned i = 0; i < sz; i++)
|
||||
if (operator[](i).var() == v)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::ostream & operator<<(std::ostream & out, clause_wrapper const & c) {
|
||||
out << "(";
|
||||
for (unsigned i = 0; i < c.size(); i++) {
|
||||
if (i > 0) out << " ";
|
||||
out << c[i];
|
||||
}
|
||||
out << ")";
|
||||
return out;
|
||||
}
|
||||
|
||||
};
|
179
src/sat/sat_clause.h
Normal file
179
src/sat/sat_clause.h
Normal file
|
@ -0,0 +1,179 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
sat_clause.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Clauses
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2011-05-21.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _SAT_CLAUSE_H_
|
||||
#define _SAT_CLAUSE_H_
|
||||
|
||||
#include"sat_types.h"
|
||||
#include"small_object_allocator.h"
|
||||
#include"id_gen.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable : 4200)
|
||||
#pragma warning(disable : 4355)
|
||||
#endif
|
||||
|
||||
namespace sat {
|
||||
|
||||
class clause_allocator;
|
||||
|
||||
class clause {
|
||||
friend class clause_allocator;
|
||||
friend class tmp_clause;
|
||||
unsigned m_id;
|
||||
unsigned m_size;
|
||||
unsigned m_capacity;
|
||||
var_approx_set m_approx;
|
||||
unsigned m_strengthened:1;
|
||||
unsigned m_removed:1;
|
||||
unsigned m_learned:1;
|
||||
unsigned m_used:1;
|
||||
unsigned m_frozen:1;
|
||||
unsigned m_reinit_stack:1;
|
||||
unsigned m_inact_rounds:8;
|
||||
unsigned m_glue:8;
|
||||
unsigned m_psm:8; // transient field used during gc
|
||||
literal m_lits[0];
|
||||
|
||||
static size_t get_obj_size(unsigned num_lits) { return sizeof(clause) + num_lits * sizeof(literal); }
|
||||
size_t get_size() const { return get_obj_size(m_capacity); }
|
||||
clause(unsigned id, unsigned sz, literal const * lits, bool learned);
|
||||
public:
|
||||
unsigned id() const { return m_id; }
|
||||
unsigned size() const { return m_size; }
|
||||
literal & operator[](unsigned idx) { SASSERT(idx < m_size); return m_lits[idx]; }
|
||||
literal const & operator[](unsigned idx) const { SASSERT(idx < m_size); return m_lits[idx]; }
|
||||
bool is_learned() const { return m_learned; }
|
||||
void unset_learned() { SASSERT(is_learned()); m_learned = false; }
|
||||
void shrink(unsigned num_lits) { SASSERT(num_lits <= m_size); if (num_lits < m_size) { m_size = num_lits; mark_strengthened(); } }
|
||||
bool strengthened() const { return m_strengthened; }
|
||||
void mark_strengthened() { m_strengthened = true; update_approx(); }
|
||||
void unmark_strengthened() { m_strengthened = false; }
|
||||
void elim(literal l);
|
||||
bool was_removed() const { return m_removed; }
|
||||
void set_removed(bool f) { m_removed = f; }
|
||||
var_approx_set approx() const { return m_approx; }
|
||||
void update_approx();
|
||||
bool check_approx() const; // for debugging
|
||||
literal * begin() { return m_lits; }
|
||||
literal * end() { return m_lits + m_size; }
|
||||
bool contains(literal l) const;
|
||||
bool contains(bool_var v) const;
|
||||
bool satisfied_by(model const & m) const;
|
||||
void mark_used() { m_used = true; }
|
||||
void unmark_used() { m_used = false; }
|
||||
bool was_used() const { return m_used; }
|
||||
void inc_inact_rounds() { m_inact_rounds++; }
|
||||
void reset_inact_rounds() { m_inact_rounds = 0; }
|
||||
unsigned inact_rounds() const { return m_inact_rounds; }
|
||||
bool frozen() const { return m_frozen; }
|
||||
void freeze() { SASSERT(is_learned()); SASSERT(!frozen()); m_frozen = true; }
|
||||
void unfreeze() { SASSERT(is_learned()); SASSERT(frozen()); m_frozen = false; }
|
||||
static var_approx_set approx(unsigned num, literal const * lits);
|
||||
void set_glue(unsigned glue) { m_glue = glue > 255 ? 255 : glue; }
|
||||
unsigned glue() const { return m_glue; }
|
||||
void set_psm(unsigned psm) { m_psm = psm > 255 ? 255 : psm; }
|
||||
unsigned psm() const { return m_psm; }
|
||||
|
||||
bool on_reinit_stack() const { return m_reinit_stack; }
|
||||
void set_reinit_stack(bool f) { m_reinit_stack = f; }
|
||||
};
|
||||
|
||||
std::ostream & operator<<(std::ostream & out, clause const & c);
|
||||
std::ostream & operator<<(std::ostream & out, clause_vector const & cs);
|
||||
|
||||
class bin_clause {
|
||||
unsigned m_val1;
|
||||
unsigned m_val2;
|
||||
public:
|
||||
bin_clause(literal l1, literal l2, bool learned):m_val1(l1.to_uint()), m_val2((l2.to_uint() << 1) + static_cast<unsigned>(learned)) {}
|
||||
literal get_literal1() const { return to_literal(m_val1); }
|
||||
literal get_literal2() const { return to_literal(m_val2 >> 1); }
|
||||
bool is_learned() const { return (m_val2 & 1) == 1; }
|
||||
};
|
||||
|
||||
class tmp_clause {
|
||||
clause * m_clause;
|
||||
public:
|
||||
tmp_clause():m_clause(0) {}
|
||||
~tmp_clause() { if (m_clause) dealloc_svect(m_clause); }
|
||||
clause * get() const { return m_clause; }
|
||||
void set(unsigned num_lits, literal const * lits, bool learned);
|
||||
void set(literal l1, literal l2, bool learned) { literal ls[2] = { l1, l2 }; set(2, ls, learned); }
|
||||
void set(bin_clause const & c) { set(c.get_literal1(), c.get_literal2(), c.is_learned()); }
|
||||
};
|
||||
|
||||
/**
|
||||
\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;
|
||||
#ifdef _AMD64_
|
||||
unsigned get_segment(size_t ptr);
|
||||
static const unsigned c_cls_alignment = 3;
|
||||
static const unsigned c_max_segments = 1 << c_cls_alignment;
|
||||
static const size_t c_aligment_mask = (1ull << c_cls_alignment) - 1ull;
|
||||
unsigned m_num_segments;
|
||||
size_t m_segments[c_max_segments];
|
||||
#endif
|
||||
public:
|
||||
clause_allocator();
|
||||
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);
|
||||
void del_clause(clause * cls);
|
||||
};
|
||||
|
||||
/**
|
||||
\brief Wrapper for clauses & binary clauses.
|
||||
I do not create clause objects for binary clauses.
|
||||
clause_ref wraps a clause object or a pair of literals (i.e., a binary clause).
|
||||
*/
|
||||
class clause_wrapper {
|
||||
union {
|
||||
clause * m_cls;
|
||||
unsigned m_l1_idx;
|
||||
};
|
||||
unsigned m_l2_idx;
|
||||
public:
|
||||
clause_wrapper(literal l1, literal l2):m_l1_idx(l1.to_uint()), m_l2_idx(l2.to_uint()) {}
|
||||
clause_wrapper(clause & c):m_cls(&c), m_l2_idx(null_literal.to_uint()) {}
|
||||
|
||||
bool is_binary() const { return m_l2_idx != null_literal.to_uint(); }
|
||||
unsigned size() const { return is_binary() ? 2 : m_cls->size(); }
|
||||
literal operator[](unsigned idx) const {
|
||||
SASSERT(idx < size());
|
||||
if (is_binary())
|
||||
return idx == 0 ? to_literal(m_l1_idx) : to_literal(m_l2_idx);
|
||||
else
|
||||
return m_cls->operator[](idx);
|
||||
}
|
||||
|
||||
bool contains(literal l) const;
|
||||
bool contains(bool_var v) const;
|
||||
clause * get_clause() const { SASSERT(!is_binary()); return m_cls; }
|
||||
};
|
||||
|
||||
typedef svector<clause_wrapper> clause_wrapper_vector;
|
||||
|
||||
std::ostream & operator<<(std::ostream & out, clause_wrapper const & c);
|
||||
|
||||
};
|
||||
|
||||
#endif
|
84
src/sat/sat_clause_set.cpp
Normal file
84
src/sat/sat_clause_set.cpp
Normal file
|
@ -0,0 +1,84 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
sat_clause_set.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Set of clauses
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2011-05-25.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include"sat_clause_set.h"
|
||||
|
||||
namespace sat {
|
||||
|
||||
void clause_set::insert(clause & c) {
|
||||
unsigned id = c.id();
|
||||
m_id2pos.reserve(id+1, UINT_MAX);
|
||||
if (m_id2pos[id] != UINT_MAX)
|
||||
return; // already in the set
|
||||
unsigned pos = m_set.size();
|
||||
m_id2pos[id] = pos;
|
||||
m_set.push_back(&c);
|
||||
CASSERT("clause_set", check_invariant());
|
||||
}
|
||||
|
||||
void clause_set::erase(clause & c) {
|
||||
unsigned id = c.id();
|
||||
if (id >= m_id2pos.size())
|
||||
return;
|
||||
unsigned pos = m_id2pos[id];
|
||||
if (pos == UINT_MAX)
|
||||
return;
|
||||
m_id2pos[id] = UINT_MAX;
|
||||
unsigned last_pos = m_set.size() - 1;
|
||||
if (pos != last_pos) {
|
||||
clause * last_c = m_set[last_pos];
|
||||
m_set[pos] = last_c;
|
||||
m_id2pos[last_c->id()] = pos;
|
||||
}
|
||||
m_set.pop_back();
|
||||
CASSERT("clause_set", check_invariant());
|
||||
}
|
||||
|
||||
clause & clause_set::erase() {
|
||||
SASSERT(!empty());
|
||||
clause & c = *m_set.back();
|
||||
m_id2pos[c.id()] = UINT_MAX;
|
||||
m_set.pop_back();
|
||||
return c;
|
||||
}
|
||||
|
||||
bool clause_set::check_invariant() const {
|
||||
{
|
||||
clause_vector::const_iterator it = m_set.begin();
|
||||
clause_vector::const_iterator end = m_set.end();
|
||||
for (unsigned pos = 0; it != end; ++it, ++pos) {
|
||||
clause & c = *(*it);
|
||||
SASSERT(c.id() < m_id2pos.size());
|
||||
SASSERT(m_id2pos[c.id()] == pos);
|
||||
}
|
||||
}
|
||||
{
|
||||
unsigned_vector::const_iterator it = m_id2pos.begin();
|
||||
unsigned_vector::const_iterator end = m_id2pos.end();
|
||||
for (unsigned id = 0; it != end; ++it, ++id) {
|
||||
unsigned pos = *it;
|
||||
if (pos == UINT_MAX)
|
||||
continue;
|
||||
SASSERT(pos < m_set.size());
|
||||
SASSERT(m_set[pos]->id() == id);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
56
src/sat/sat_clause_set.h
Normal file
56
src/sat/sat_clause_set.h
Normal file
|
@ -0,0 +1,56 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
sat_clause_set.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Set of clauses
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2011-05-25.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _SAT_CLAUSE_SET_H_
|
||||
#define _SAT_CLAUSE_SET_H_
|
||||
|
||||
#include"sat_clause.h"
|
||||
|
||||
namespace sat {
|
||||
|
||||
class clause_set {
|
||||
unsigned_vector m_id2pos;
|
||||
clause_vector m_set;
|
||||
public:
|
||||
typedef clause_vector::const_iterator iterator;
|
||||
|
||||
bool contains(clause const & cls) const {
|
||||
if (cls.id() >= m_id2pos.size())
|
||||
return false;
|
||||
return m_id2pos[cls.id()] != UINT_MAX;
|
||||
}
|
||||
bool empty() const { return m_set.empty(); }
|
||||
unsigned size() const { return m_set.size(); }
|
||||
void insert(clause & c);
|
||||
void erase(clause & c);
|
||||
|
||||
// erase some clause from the set
|
||||
clause & erase();
|
||||
|
||||
void reset() { m_id2pos.reset(); m_set.reset(); }
|
||||
void finalize() { m_id2pos.finalize(); m_set.finalize(); }
|
||||
|
||||
iterator begin() const { return m_set.begin(); }
|
||||
iterator end() const { return m_set.end(); }
|
||||
|
||||
bool check_invariant() const;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif
|
57
src/sat/sat_clause_use_list.cpp
Normal file
57
src/sat/sat_clause_use_list.cpp
Normal file
|
@ -0,0 +1,57 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
sat_clause_use_list.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Clause use list
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2011-05-31.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include"sat_clause.h"
|
||||
#include"sat_clause_use_list.h"
|
||||
|
||||
namespace sat {
|
||||
|
||||
bool clause_use_list::check_invariant() const {
|
||||
#ifdef LAZY_USE_LIST
|
||||
unsigned sz = 0;
|
||||
for (unsigned i = 0; i < m_clauses.size(); i++)
|
||||
if (!m_clauses[i]->was_removed())
|
||||
sz++;
|
||||
SASSERT(sz == m_size);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef LAZY_USE_LIST
|
||||
void clause_use_list::iterator::consume() {
|
||||
while (true) {
|
||||
if (m_i == m_size)
|
||||
return;
|
||||
if (!m_clauses[m_i]->was_removed()) {
|
||||
m_clauses[m_j] = m_clauses[m_i];
|
||||
return;
|
||||
}
|
||||
m_i++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
clause_use_list::iterator::~iterator() {
|
||||
#ifdef LAZY_USE_LIST
|
||||
while (m_i < m_size)
|
||||
next();
|
||||
m_clauses.shrink(m_j);
|
||||
#endif
|
||||
}
|
||||
|
||||
};
|
118
src/sat/sat_clause_use_list.h
Normal file
118
src/sat/sat_clause_use_list.h
Normal file
|
@ -0,0 +1,118 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
sat_clause_use_list.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Clause use list
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2011-05-31.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _SAT_CLAUSE_USE_LIST_H_
|
||||
#define _SAT_CLAUSE_USE_LIST_H_
|
||||
|
||||
#include"sat_types.h"
|
||||
|
||||
namespace sat {
|
||||
|
||||
#define LAZY_USE_LIST
|
||||
|
||||
/**
|
||||
\brief Clause use list with delayed deletion.
|
||||
*/
|
||||
class clause_use_list {
|
||||
clause_vector m_clauses;
|
||||
#ifdef LAZY_USE_LIST
|
||||
unsigned m_size;
|
||||
#endif
|
||||
public:
|
||||
clause_use_list() {
|
||||
#ifdef LAZY_USE_LIST
|
||||
m_size = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned size() const {
|
||||
#ifdef LAZY_USE_LIST
|
||||
return m_size;
|
||||
#else
|
||||
return m_clauses.size();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool empty() const { return size() == 0; }
|
||||
|
||||
void insert(clause & c) {
|
||||
SASSERT(!m_clauses.contains(&c)); SASSERT(!c.was_removed());
|
||||
m_clauses.push_back(&c);
|
||||
#ifdef LAZY_USE_LIST
|
||||
m_size++;
|
||||
#endif
|
||||
}
|
||||
void erase_not_removed(clause & c) {
|
||||
#ifdef LAZY_USE_LIST
|
||||
SASSERT(m_clauses.contains(&c)); SASSERT(!c.was_removed()); m_clauses.erase(&c); m_size--;
|
||||
#else
|
||||
m_clauses.erase(&c);
|
||||
#endif
|
||||
}
|
||||
void erase(clause & c) {
|
||||
#ifdef LAZY_USE_LIST
|
||||
SASSERT(m_clauses.contains(&c)); SASSERT(c.was_removed()); m_size--;
|
||||
#else
|
||||
m_clauses.erase(&c);
|
||||
#endif
|
||||
}
|
||||
|
||||
void reset() {
|
||||
m_clauses.finalize();
|
||||
#ifdef LAZY_USE_LIST
|
||||
m_size = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool check_invariant() const;
|
||||
// iterate & compress
|
||||
class iterator {
|
||||
clause_vector & m_clauses;
|
||||
unsigned m_size;
|
||||
unsigned m_i;
|
||||
#ifdef LAZY_USE_LIST
|
||||
unsigned m_j;
|
||||
void consume();
|
||||
#endif
|
||||
public:
|
||||
iterator(clause_vector & v):m_clauses(v), m_size(v.size()), m_i(0) {
|
||||
#ifdef LAZY_USE_LIST
|
||||
m_j = 0;
|
||||
consume();
|
||||
#endif
|
||||
}
|
||||
~iterator();
|
||||
bool at_end() const { return m_i == m_size; }
|
||||
clause & curr() const { SASSERT(!at_end()); return *(m_clauses[m_i]); }
|
||||
void next() {
|
||||
SASSERT(!at_end());
|
||||
SASSERT(!m_clauses[m_i]->was_removed());
|
||||
m_i++;
|
||||
#ifdef LAZY_USE_LIST
|
||||
m_j++;
|
||||
consume();
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
iterator mk_iterator() const { return iterator(const_cast<clause_use_list*>(this)->m_clauses); }
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif
|
214
src/sat/sat_cleaner.cpp
Normal file
214
src/sat/sat_cleaner.cpp
Normal file
|
@ -0,0 +1,214 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
sat_cleaner.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Eliminate satisfied clauses, and literals assigned to false.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2011-05-24.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include"sat_cleaner.h"
|
||||
#include"sat_solver.h"
|
||||
#include"trace.h"
|
||||
#include"stopwatch.h"
|
||||
|
||||
namespace sat {
|
||||
|
||||
cleaner::cleaner(solver & _s):
|
||||
s(_s),
|
||||
m_last_num_units(0),
|
||||
m_cleanup_counter(0) {
|
||||
reset_statistics();
|
||||
}
|
||||
|
||||
/**
|
||||
- Delete watch lists of assigned literals.
|
||||
- Delete satisfied binary watched binary clauses
|
||||
- Delete watched clauses (they will be reinserted after they are cleaned).
|
||||
*/
|
||||
void cleaner::cleanup_watches() {
|
||||
vector<watch_list>::iterator it = s.m_watches.begin();
|
||||
vector<watch_list>::iterator end = s.m_watches.end();
|
||||
unsigned l_idx = 0;
|
||||
for (; it != end; ++it, ++l_idx) {
|
||||
if (s.value(to_literal(l_idx)) != l_undef) {
|
||||
it->finalize();
|
||||
SASSERT(it->empty());
|
||||
continue;
|
||||
}
|
||||
TRACE("cleanup_bug", tout << "processing wlist of " << to_literal(l_idx) << "\n";);
|
||||
watch_list & wlist = *it;
|
||||
watch_list::iterator it2 = wlist.begin();
|
||||
watch_list::iterator it_prev = it2;
|
||||
watch_list::iterator end2 = wlist.end();
|
||||
for (; it2 != end2; ++it2) {
|
||||
switch (it2->get_kind()) {
|
||||
case watched::BINARY:
|
||||
SASSERT(s.value(it2->get_literal()) == l_true || s.value(it2->get_literal()) == l_undef);
|
||||
if (s.value(it2->get_literal()) == l_undef) {
|
||||
*it_prev = *it2;
|
||||
++it_prev;
|
||||
}
|
||||
TRACE("cleanup_bug", tout << "keeping: " << ~to_literal(l_idx) << " " << it2->get_literal() << "\n";);
|
||||
break;
|
||||
case watched::TERNARY:
|
||||
case watched::CLAUSE:
|
||||
// skip
|
||||
break;
|
||||
case watched::EXT_CONSTRAINT:
|
||||
*it_prev = *it2;
|
||||
++it_prev;
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
}
|
||||
wlist.set_end(it_prev);
|
||||
}
|
||||
}
|
||||
|
||||
void cleaner::cleanup_clauses(clause_vector & cs) {
|
||||
clause_vector::iterator it = cs.begin();
|
||||
clause_vector::iterator it2 = it;
|
||||
clause_vector::iterator end = cs.end();
|
||||
for (; it != end; ++it) {
|
||||
clause & c = *(*it);
|
||||
TRACE("sat_cleaner_bug", tout << "cleaning: " << c << "\n";
|
||||
for (unsigned i = 0; i < c.size(); i++) tout << c[i] << ": " << s.value(c[i]) << "\n";);
|
||||
CTRACE("sat_cleaner_frozen", c.frozen(), tout << c << "\n";);
|
||||
unsigned sz = c.size();
|
||||
unsigned i = 0, j = 0;
|
||||
bool sat = false;
|
||||
m_cleanup_counter += sz;
|
||||
for (; i < sz; i++) {
|
||||
switch (s.value(c[i])) {
|
||||
case l_true:
|
||||
sat = true;
|
||||
goto end_loop;
|
||||
case l_false:
|
||||
m_elim_literals++;
|
||||
break;
|
||||
case l_undef:
|
||||
c[j] = c[i];
|
||||
j++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
end_loop:
|
||||
CTRACE("sat_cleaner_frozen", c.frozen(),
|
||||
tout << "sat: " << sat << ", new_size: " << j << "\n";
|
||||
tout << mk_lits_pp(j, c.begin()) << "\n";);
|
||||
if (sat) {
|
||||
m_elim_clauses++;
|
||||
s.del_clause(c);
|
||||
}
|
||||
else {
|
||||
unsigned new_sz = j;
|
||||
CTRACE("sat_cleaner_bug", new_sz < 2, tout << "new_sz: " << new_sz << "\n";
|
||||
if (c.size() > 0) tout << "unit: " << c[0] << "\n";);
|
||||
SASSERT(c.frozen() || new_sz >= 2);
|
||||
if (new_sz == 0) {
|
||||
// It can only happen with frozen clauses.
|
||||
// active clauses would have signed the conflict.
|
||||
SASSERT(c.frozen());
|
||||
s.set_conflict(justification());
|
||||
s.del_clause(c);
|
||||
}
|
||||
else if (new_sz == 1) {
|
||||
// It can only happen with frozen clauses.
|
||||
// active clauses would have propagated the literal
|
||||
SASSERT(c.frozen());
|
||||
s.assign(c[0], justification());
|
||||
s.del_clause(c);
|
||||
}
|
||||
else {
|
||||
SASSERT(s.value(c[0]) == l_undef && s.value(c[1]) == l_undef);
|
||||
if (new_sz == 2) {
|
||||
TRACE("cleanup_bug", tout << "clause became binary: " << c[0] << " " << c[1] << "\n";);
|
||||
s.mk_bin_clause(c[0], c[1], c.is_learned());
|
||||
s.del_clause(c);
|
||||
}
|
||||
else {
|
||||
c.shrink(new_sz);
|
||||
*it2 = *it;
|
||||
it2++;
|
||||
if (!c.frozen()) {
|
||||
if (new_sz == 3)
|
||||
s.attach_ter_clause(c);
|
||||
else
|
||||
s.attach_nary_clause(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
cs.set_end(it2);
|
||||
}
|
||||
|
||||
struct cleaner::report {
|
||||
cleaner & m_cleaner;
|
||||
stopwatch m_watch;
|
||||
unsigned m_elim_clauses;
|
||||
unsigned m_elim_literals;
|
||||
report(cleaner & c):
|
||||
m_cleaner(c),
|
||||
m_elim_clauses(c.m_elim_clauses),
|
||||
m_elim_literals(c.m_elim_literals) {
|
||||
m_watch.start();
|
||||
}
|
||||
~report() {
|
||||
m_watch.stop();
|
||||
IF_VERBOSE(SAT_VB_LVL,
|
||||
verbose_stream() << " (sat-cleaner :elim-literals " << (m_cleaner.m_elim_literals - m_elim_literals)
|
||||
<< " :elim-clauses " << (m_cleaner.m_elim_clauses - m_elim_clauses)
|
||||
<< " :cost " << m_cleaner.m_cleanup_counter
|
||||
<< mk_stat(m_cleaner.s)
|
||||
<< " :time " << std::fixed << std::setprecision(2) << m_watch.get_seconds() << ")\n";);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
\brief Return true if cleaner executed.
|
||||
*/
|
||||
bool cleaner::operator()(bool force) {
|
||||
CASSERT("cleaner_bug", s.check_invariant());
|
||||
unsigned trail_sz = s.m_trail.size();
|
||||
s.propagate(false); // make sure that everything was propagated.
|
||||
if (s.m_inconsistent)
|
||||
return false;
|
||||
if (m_last_num_units == trail_sz)
|
||||
return false; // there are no new assigned literals since last time... nothing to be done
|
||||
if (!force && m_cleanup_counter > 0)
|
||||
return false; // prevent simplifier from being executed over and over again.
|
||||
report rpt(*this);
|
||||
m_last_num_units = trail_sz;
|
||||
m_cleanup_counter = 0;
|
||||
cleanup_watches();
|
||||
cleanup_clauses(s.m_clauses);
|
||||
cleanup_clauses(s.m_learned);
|
||||
s.propagate(false);
|
||||
CASSERT("cleaner_bug", s.check_invariant());
|
||||
return true;
|
||||
}
|
||||
|
||||
void cleaner::reset_statistics() {
|
||||
m_elim_clauses = 0;
|
||||
m_elim_literals = 0;
|
||||
}
|
||||
|
||||
void cleaner::collect_statistics(statistics & st) {
|
||||
st.update("elim clauses", m_elim_clauses);
|
||||
st.update("elim literals", m_elim_literals);
|
||||
}
|
||||
|
||||
};
|
53
src/sat/sat_cleaner.h
Normal file
53
src/sat/sat_cleaner.h
Normal file
|
@ -0,0 +1,53 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
sat_cleaner.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Eliminate satisfied clauses, and literals assigned to false.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2011-05-24.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _SAT_CLEANER_H_
|
||||
#define _SAT_CLEANER_H_
|
||||
|
||||
#include"sat_types.h"
|
||||
#include"statistics.h"
|
||||
|
||||
namespace sat {
|
||||
|
||||
class cleaner {
|
||||
struct report;
|
||||
|
||||
solver & s;
|
||||
unsigned m_last_num_units;
|
||||
int m_cleanup_counter;
|
||||
|
||||
// stats
|
||||
unsigned m_elim_clauses;
|
||||
unsigned m_elim_literals;
|
||||
|
||||
void cleanup_watches();
|
||||
void cleanup_clauses(clause_vector & cs);
|
||||
public:
|
||||
cleaner(solver & s);
|
||||
|
||||
bool operator()(bool force = false);
|
||||
|
||||
void collect_statistics(statistics & st);
|
||||
void reset_statistics();
|
||||
|
||||
void dec() { m_cleanup_counter--; }
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif
|
126
src/sat/sat_config.cpp
Normal file
126
src/sat/sat_config.cpp
Normal file
|
@ -0,0 +1,126 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
sat_config.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
SAT configuration options
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2011-05-21.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include"sat_config.h"
|
||||
#include"sat_types.h"
|
||||
|
||||
namespace sat {
|
||||
|
||||
config::config(params_ref const & p):
|
||||
m_always_true("always-true"),
|
||||
m_always_false("always-false"),
|
||||
m_caching("caching"),
|
||||
m_random("random"),
|
||||
m_geometric("geometric"),
|
||||
m_luby("luby"),
|
||||
m_dyn_psm("dyn-psm"),
|
||||
m_psm("psm"),
|
||||
m_glue("glue"),
|
||||
m_glue_psm("glue-psm"),
|
||||
m_psm_glue("psm-glue") {
|
||||
updt_params(p);
|
||||
}
|
||||
|
||||
void config::updt_params(params_ref const & p) {
|
||||
m_max_memory = megabytes_to_bytes(p.get_uint(":max-memory", UINT_MAX));
|
||||
|
||||
symbol s = p.get_sym(":restart", m_luby);
|
||||
if (s == m_luby)
|
||||
m_restart = RS_LUBY;
|
||||
else if (s == m_geometric)
|
||||
m_restart = RS_GEOMETRIC;
|
||||
else
|
||||
throw sat_param_exception("invalid restart strategy");
|
||||
|
||||
s = p.get_sym(":phase", m_caching);
|
||||
if (s == m_always_false)
|
||||
m_phase = PS_ALWAYS_FALSE;
|
||||
else if (s == m_always_true)
|
||||
m_phase = PS_ALWAYS_TRUE;
|
||||
else if (s == m_caching)
|
||||
m_phase = PS_CACHING;
|
||||
else if (s == m_random)
|
||||
m_phase = PS_RANDOM;
|
||||
else
|
||||
throw sat_param_exception("invalid phase selection strategy");
|
||||
|
||||
m_phase_caching_on = p.get_uint(":phase-caching-on", 400);
|
||||
m_phase_caching_off = p.get_uint(":phase-caching-off", 100);
|
||||
|
||||
m_restart_initial = p.get_uint(":restart-initial", 100);
|
||||
m_restart_factor = p.get_double(":restart-factor", 1.5);
|
||||
|
||||
m_random_freq = p.get_double(":random-freq", 0.01);
|
||||
|
||||
m_burst_search = p.get_uint(":burst-search", 100);
|
||||
|
||||
m_max_conflicts = p.get_uint(":max-conflicts", UINT_MAX);
|
||||
|
||||
m_simplify_mult1 = p.get_uint(":simplify-mult1", 300);
|
||||
m_simplify_mult2 = p.get_double(":simplify-mult2", 1.5);
|
||||
m_simplify_max = p.get_uint(":simplify-max", 500000);
|
||||
|
||||
s = p.get_sym(":gc-strategy", m_glue_psm);
|
||||
if (s == m_dyn_psm) {
|
||||
m_gc_strategy = GC_DYN_PSM;
|
||||
m_gc_initial = p.get_uint(":gc-initial", 500);
|
||||
m_gc_increment = p.get_uint(":gc-increment", 100);
|
||||
m_gc_small_lbd = p.get_uint(":gc-small-lbd", 3);
|
||||
m_gc_k = p.get_uint(":gc-k", 7);
|
||||
if (m_gc_k > 255)
|
||||
m_gc_k = 255;
|
||||
}
|
||||
else {
|
||||
if (s == m_glue_psm)
|
||||
m_gc_strategy = GC_GLUE_PSM;
|
||||
else if (s == m_glue)
|
||||
m_gc_strategy = GC_GLUE;
|
||||
else if (s == m_psm)
|
||||
m_gc_strategy = GC_PSM;
|
||||
else if (s == m_psm_glue)
|
||||
m_gc_strategy = GC_PSM_GLUE;
|
||||
else
|
||||
throw sat_param_exception("invalid gc strategy");
|
||||
m_gc_initial = p.get_uint(":gc-initial", 20000);
|
||||
m_gc_increment = p.get_uint(":gc-increment", 500);
|
||||
}
|
||||
m_minimize_lemmas = p.get_bool(":minimize-lemmas", true);
|
||||
m_dyn_sub_res = p.get_bool(":dyn-sub-res", true);
|
||||
}
|
||||
|
||||
void config::collect_param_descrs(param_descrs & r) {
|
||||
insert_max_memory(r);
|
||||
r.insert(":phase", CPK_SYMBOL, "(default: caching) phase selection strategy: always-false, always-true, caching, random.");
|
||||
r.insert(":phase-caching-on", CPK_UINT, "(default: 400)");
|
||||
r.insert(":phase-caching-off", CPK_UINT, "(default: 100)");
|
||||
r.insert(":restart", CPK_SYMBOL, "(default: luby) restart strategy: luby or geometric.");
|
||||
r.insert(":restart-initial", CPK_UINT, "(default: 100) initial restart (number of conflicts).");
|
||||
r.insert(":restart-factor", CPK_DOUBLE, "(default: 1.5) restart increment factor for geometric strategy.");
|
||||
r.insert(":random-freq", CPK_DOUBLE, "(default: 0.01) frequency of random case splits.");
|
||||
r.insert(":burst-search", CPK_UINT, "(default: 100) number of conflicts before first global simplification.");
|
||||
r.insert(":max-conflicts", CPK_UINT, "(default: inf) maximum number of conflicts.");
|
||||
r.insert(":gc-strategy", CPK_SYMBOL, "(default: glue-psm) garbage collection strategy: psm, glue, glue-psm, dyn-psm.");
|
||||
r.insert(":gc-initial", CPK_UINT, "(default: 20000) learned clauses garbage collection frequence.");
|
||||
r.insert(":gc-increment", CPK_UINT, "(default: 500) increment to the garbage collection threshold.");
|
||||
r.insert(":gc-small-lbd", CPK_UINT, "(default: 3) learned clauses with small LBD are never deleted (only used in dyn-psm).");
|
||||
r.insert(":gc-k", CPK_UINT, "(default: 7) learned clauses that are inactive for k gc rounds are permanently deleted (only used in dyn-psm).");
|
||||
r.insert(":minimize-lemmas", CPK_BOOL, "(default: true) minimize learned clauses.");
|
||||
r.insert(":dyn-sub-res", CPK_BOOL, "(default: true) dynamic subsumption resolution for minimizing learned clauses.");
|
||||
}
|
||||
|
||||
};
|
91
src/sat/sat_config.h
Normal file
91
src/sat/sat_config.h
Normal file
|
@ -0,0 +1,91 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
sat_config.h
|
||||
|
||||
Abstract:
|
||||
|
||||
SAT main configuration options.
|
||||
Sub-components have their own options.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2011-05-21.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _SAT_CONFIG_H_
|
||||
#define _SAT_CONFIG_H_
|
||||
|
||||
#include"params.h"
|
||||
|
||||
namespace sat {
|
||||
|
||||
enum phase_selection {
|
||||
PS_ALWAYS_TRUE,
|
||||
PS_ALWAYS_FALSE,
|
||||
PS_CACHING,
|
||||
PS_RANDOM
|
||||
};
|
||||
|
||||
enum restart_strategy {
|
||||
RS_GEOMETRIC,
|
||||
RS_LUBY
|
||||
};
|
||||
|
||||
enum gc_strategy {
|
||||
GC_DYN_PSM,
|
||||
GC_PSM,
|
||||
GC_GLUE,
|
||||
GC_GLUE_PSM,
|
||||
GC_PSM_GLUE
|
||||
};
|
||||
|
||||
struct config {
|
||||
unsigned long long m_max_memory;
|
||||
phase_selection m_phase;
|
||||
unsigned m_phase_caching_on;
|
||||
unsigned m_phase_caching_off;
|
||||
restart_strategy m_restart;
|
||||
unsigned m_restart_initial;
|
||||
double m_restart_factor; // for geometric case
|
||||
double m_random_freq;
|
||||
unsigned m_burst_search;
|
||||
unsigned m_max_conflicts;
|
||||
|
||||
unsigned m_simplify_mult1;
|
||||
double m_simplify_mult2;
|
||||
unsigned m_simplify_max;
|
||||
|
||||
gc_strategy m_gc_strategy;
|
||||
unsigned m_gc_initial;
|
||||
unsigned m_gc_increment;
|
||||
unsigned m_gc_small_lbd;
|
||||
unsigned m_gc_k;
|
||||
|
||||
bool m_minimize_lemmas;
|
||||
bool m_dyn_sub_res;
|
||||
|
||||
symbol m_always_true;
|
||||
symbol m_always_false;
|
||||
symbol m_caching;
|
||||
symbol m_random;
|
||||
symbol m_geometric;
|
||||
symbol m_luby;
|
||||
|
||||
symbol m_dyn_psm;
|
||||
symbol m_psm;
|
||||
symbol m_glue;
|
||||
symbol m_glue_psm;
|
||||
symbol m_psm_glue;
|
||||
|
||||
config(params_ref const & p);
|
||||
void updt_params(params_ref const & p);
|
||||
static void collect_param_descrs(param_descrs & d);
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
220
src/sat/sat_elim_eqs.cpp
Normal file
220
src/sat/sat_elim_eqs.cpp
Normal file
|
@ -0,0 +1,220 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
sat_elim_eqs.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Helper class for eliminating eqs.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2011-05-27.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include"sat_elim_eqs.h"
|
||||
#include"sat_solver.h"
|
||||
#include"trace.h"
|
||||
|
||||
namespace sat {
|
||||
|
||||
elim_eqs::elim_eqs(solver & s):
|
||||
m_solver(s) {
|
||||
}
|
||||
|
||||
inline literal norm(literal_vector const & roots, literal l) {
|
||||
if (l.sign())
|
||||
return ~roots[l.var()];
|
||||
else
|
||||
return roots[l.var()];
|
||||
}
|
||||
|
||||
void elim_eqs::cleanup_bin_watches(literal_vector const & roots) {
|
||||
vector<watch_list>::iterator it = m_solver.m_watches.begin();
|
||||
vector<watch_list>::iterator end = m_solver.m_watches.end();
|
||||
for (unsigned l_idx = 0; it != end; ++it, ++l_idx) {
|
||||
watch_list & wlist = *it;
|
||||
literal l1 = ~to_literal(l_idx);
|
||||
literal r1 = norm(roots, l1);
|
||||
watch_list::iterator it2 = wlist.begin();
|
||||
watch_list::iterator itprev = it2;
|
||||
watch_list::iterator end2 = wlist.end();
|
||||
for (; it2 != end2; ++it2) {
|
||||
if (it2->is_binary_clause()) {
|
||||
literal l2 = it2->get_literal();
|
||||
literal r2 = norm(roots, l2);
|
||||
if (r1 == r2) {
|
||||
m_solver.assign(r1, justification());
|
||||
if (m_solver.inconsistent())
|
||||
return;
|
||||
// consume unit
|
||||
continue;
|
||||
}
|
||||
if (r1 == ~r2) {
|
||||
// consume tautology
|
||||
continue;
|
||||
}
|
||||
if (l1 != r1) {
|
||||
// add half r1 => r2, the other half ~r2 => ~r1 is added when traversing l2
|
||||
m_solver.m_watches[(~r1).index()].push_back(watched(r2, it2->is_learned()));
|
||||
continue;
|
||||
}
|
||||
it2->set_literal(r2); // keep it
|
||||
}
|
||||
*itprev = *it2;
|
||||
itprev++;
|
||||
}
|
||||
wlist.set_end(itprev);
|
||||
}
|
||||
}
|
||||
|
||||
void elim_eqs::cleanup_clauses(literal_vector const & roots, clause_vector & cs) {
|
||||
clause_vector::iterator it = cs.begin();
|
||||
clause_vector::iterator it2 = it;
|
||||
clause_vector::iterator end = cs.end();
|
||||
for (; it != end; ++it) {
|
||||
clause & c = *(*it);
|
||||
TRACE("elim_eqs", tout << "processing: " << c << "\n";);
|
||||
unsigned sz = c.size();
|
||||
unsigned i;
|
||||
for (i = 0; i < sz; i++) {
|
||||
literal l = c[i];
|
||||
literal r = norm(roots, l);
|
||||
if (l != r)
|
||||
break;
|
||||
}
|
||||
if (i == sz) {
|
||||
// clause was not affected
|
||||
*it2 = *it;
|
||||
it2++;
|
||||
continue;
|
||||
}
|
||||
if (!c.frozen())
|
||||
m_solver.dettach_clause(c);
|
||||
// apply substitution
|
||||
for (i = 0; i < sz; i++) {
|
||||
SASSERT(!m_solver.was_eliminated(c[i].var()));
|
||||
c[i] = norm(roots, c[i]);
|
||||
}
|
||||
std::sort(c.begin(), c.end());
|
||||
TRACE("elim_eqs", tout << "after normalization/sorting: " << c << "\n";);
|
||||
// remove duplicates, and check if it is a tautology
|
||||
literal l_prev = null_literal;
|
||||
unsigned j = 0;
|
||||
for (i = 0; i < sz; i++) {
|
||||
literal l = c[i];
|
||||
if (l == l_prev)
|
||||
continue;
|
||||
if (l == ~l_prev)
|
||||
break;
|
||||
l_prev = l;
|
||||
lbool val = m_solver.value(l);
|
||||
if (val == l_true)
|
||||
break; // clause was satisfied
|
||||
if (val == l_false)
|
||||
continue; // skip
|
||||
c[j] = l;
|
||||
j++;
|
||||
}
|
||||
if (i < sz) {
|
||||
// clause is a tautology or was simplified
|
||||
m_solver.del_clause(c);
|
||||
continue;
|
||||
}
|
||||
if (j == 0) {
|
||||
// empty clause
|
||||
m_solver.set_conflict(justification());
|
||||
return;
|
||||
}
|
||||
TRACE("elim_eqs", tout << "after removing duplicates: " << c << " j: " << j << "\n";);
|
||||
if (j < sz)
|
||||
c.shrink(j);
|
||||
else
|
||||
c.update_approx();
|
||||
SASSERT(c.size() == j);
|
||||
DEBUG_CODE({
|
||||
for (unsigned i = 0; i < c.size(); i++) {
|
||||
SASSERT(c[i] == norm(roots, c[i]));
|
||||
}
|
||||
});
|
||||
SASSERT(j >= 1);
|
||||
switch (j) {
|
||||
case 1:
|
||||
m_solver.assign(c[0], justification());
|
||||
m_solver.del_clause(c);
|
||||
break;
|
||||
case 2:
|
||||
m_solver.mk_bin_clause(c[0], c[1], c.is_learned());
|
||||
m_solver.del_clause(c);
|
||||
break;
|
||||
default:
|
||||
SASSERT(*it == &c);
|
||||
*it2 = *it;
|
||||
it2++;
|
||||
if (!c.frozen())
|
||||
m_solver.attach_clause(c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
cs.set_end(it2);
|
||||
}
|
||||
|
||||
void elim_eqs::save_elim(literal_vector const & roots, bool_var_vector const & to_elim) {
|
||||
model_converter & mc = m_solver.m_mc;
|
||||
bool_var_vector::const_iterator it = to_elim.begin();
|
||||
bool_var_vector::const_iterator end = to_elim.end();
|
||||
for (; it != end; ++it) {
|
||||
bool_var v = *it;
|
||||
literal l(v, false);
|
||||
literal r = roots[v];
|
||||
SASSERT(v != r.var());
|
||||
if (m_solver.is_external(v)) {
|
||||
// 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);
|
||||
}
|
||||
else {
|
||||
model_converter::entry & e = mc.mk(model_converter::ELIM_VAR, v);
|
||||
TRACE("save_elim", tout << "marking as deleted: " << v << " l: " << l << " r: " << r << "\n";);
|
||||
m_solver.m_eliminated[v] = true;
|
||||
mc.insert(e, ~l, r);
|
||||
mc.insert(e, l, ~r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool elim_eqs::check_clauses(literal_vector const & roots) const {
|
||||
clause_vector * vs[2] = { &m_solver.m_clauses, &m_solver.m_learned };
|
||||
for (unsigned i = 0; i < 2; i++) {
|
||||
clause_vector & cs = *(vs[i]);
|
||||
clause_vector::iterator it = cs.begin();
|
||||
clause_vector::iterator end = cs.end();
|
||||
for (; it != end; ++it) {
|
||||
clause & c = *(*it);
|
||||
unsigned sz = c.size();
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
CTRACE("elim_eqs_bug", m_solver.was_eliminated(c[i].var()), tout << "lit: " << c[i] << " " << norm(roots, c[i]) << "\n";
|
||||
tout << c << "\n";);
|
||||
SASSERT(!m_solver.was_eliminated(c[i].var()));
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void elim_eqs::operator()(literal_vector const & roots, bool_var_vector const & to_elim) {
|
||||
cleanup_bin_watches(roots);
|
||||
TRACE("elim_eqs", tout << "after bin cleanup\n"; m_solver.display(tout););
|
||||
cleanup_clauses(roots, m_solver.m_clauses);
|
||||
if (m_solver.inconsistent()) return;
|
||||
cleanup_clauses(roots, m_solver.m_learned);
|
||||
if (m_solver.inconsistent()) return;
|
||||
save_elim(roots, to_elim);
|
||||
m_solver.propagate(false);
|
||||
SASSERT(check_clauses(roots));
|
||||
}
|
||||
};
|
40
src/sat/sat_elim_eqs.h
Normal file
40
src/sat/sat_elim_eqs.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
sat_elim_eqs.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Helper class for eliminating eqs.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2011-05-27.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _SAT_ELIM_EQS_H_
|
||||
#define _SAT_ELIM_EQS_H_
|
||||
|
||||
#include"sat_types.h"
|
||||
|
||||
namespace sat {
|
||||
class solver;
|
||||
|
||||
class elim_eqs {
|
||||
solver & m_solver;
|
||||
void save_elim(literal_vector const & roots, bool_var_vector const & to_elim);
|
||||
void cleanup_clauses(literal_vector const & roots, clause_vector & cs);
|
||||
void cleanup_bin_watches(literal_vector const & roots);
|
||||
bool check_clauses(literal_vector const & roots) const;
|
||||
public:
|
||||
elim_eqs(solver & s);
|
||||
void operator()(literal_vector const & roots, bool_var_vector const & to_elim);
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif
|
46
src/sat/sat_extension.h
Normal file
46
src/sat/sat_extension.h
Normal file
|
@ -0,0 +1,46 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
sat_extension.h
|
||||
|
||||
Abstract:
|
||||
|
||||
An abstract class for SAT extensions.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2011-05-21.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _SAT_EXTENSION_H_
|
||||
#define _SAT_EXTENSION_H_
|
||||
|
||||
#include"sat_types.h"
|
||||
#include"params.h"
|
||||
|
||||
namespace sat {
|
||||
|
||||
enum check_result {
|
||||
CR_DONE, CR_CONTINUE, CR_GIVEUP
|
||||
};
|
||||
|
||||
class extension {
|
||||
public:
|
||||
virtual void propagate(literal l, ext_constraint_idx idx, bool & keep) = 0;
|
||||
virtual void get_antecedents(literal l, ext_justification_idx idx, literal_vector & r) = 0;
|
||||
virtual void asserted(literal l) = 0;
|
||||
virtual check_result check() = 0;
|
||||
virtual void push() = 0;
|
||||
virtual void pop(unsigned n) = 0;
|
||||
virtual void simplify() = 0;
|
||||
virtual void clauses_modifed() = 0;
|
||||
virtual lbool get_phase(bool_var v) = 0;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif
|
214
src/sat/sat_iff3_finder.cpp
Normal file
214
src/sat/sat_iff3_finder.cpp
Normal file
|
@ -0,0 +1,214 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
sat_iff3_finder.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Find constraints of the form x = l1 = l2
|
||||
That is, search for clauses of the form
|
||||
~x \/ l1 \/ ~l2
|
||||
~x \/ ~l1 \/ l2
|
||||
x \/ l1 \/ l2
|
||||
x \/ ~l1 \/ ~l2
|
||||
|
||||
The basic idea is to sort the watch lists.
|
||||
|
||||
This information can be used to propagate equivalences
|
||||
during probing (and search).
|
||||
|
||||
The initial experiments were disappointing.
|
||||
Not using it on the solver.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2011-06-04.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include"sat_iff3_finder.h"
|
||||
#include"sat_solver.h"
|
||||
|
||||
namespace sat {
|
||||
|
||||
struct iff3_lt {
|
||||
bool operator()(watched const & w1, watched const & w2) const {
|
||||
// keep th binary clauses in the beginning
|
||||
if (w2.is_binary_clause()) return false;
|
||||
if (w1.is_binary_clause()) return true;
|
||||
//
|
||||
if (w2.is_ternary_clause()) {
|
||||
if (w1.is_ternary_clause()) {
|
||||
literal l1_1 = w1.get_literal1();
|
||||
literal l1_2 = w1.get_literal2();
|
||||
literal l2_1 = w2.get_literal1();
|
||||
literal l2_2 = w2.get_literal2();
|
||||
if (l1_1.index() < l2_1.index()) return true;
|
||||
if (l1_1.index() > l2_1.index()) return false;
|
||||
return l1_2.index() < l2_2.index();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (w1.is_ternary_clause()) return true;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
static void unmark(svector<bool> & marks, literal_vector & to_unmark) {
|
||||
literal_vector::const_iterator it = to_unmark.begin();
|
||||
literal_vector::const_iterator end = to_unmark.end();
|
||||
for (; it != end; ++it) {
|
||||
marks[it->index()] = false;
|
||||
}
|
||||
to_unmark.reset();
|
||||
}
|
||||
|
||||
#define SMALL_WLIST 16
|
||||
|
||||
/**
|
||||
\brief Return true if wlist contains (l1, l2)
|
||||
It assumes wlist have been sorted using iff3_lt
|
||||
*/
|
||||
static bool contains(watch_list const & wlist, literal l1, literal l2) {
|
||||
watched k(l1, l2);
|
||||
if (wlist.size() < SMALL_WLIST)
|
||||
return wlist.contains(k);
|
||||
iff3_lt lt;
|
||||
int low = 0;
|
||||
int high = wlist.size();
|
||||
while (true) {
|
||||
int mid = low + ((high - low) / 2);
|
||||
watched const & m = wlist[mid];
|
||||
if (m == k)
|
||||
return true;
|
||||
if (lt(m, k)) {
|
||||
low = mid + 1;
|
||||
}
|
||||
else {
|
||||
SASSERT(lt(k, m));
|
||||
high = mid - 1;
|
||||
}
|
||||
if (low > high)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
iff3_finder::iff3_finder(solver & _s):
|
||||
s(_s) {
|
||||
}
|
||||
|
||||
void iff3_finder::sort_watches() {
|
||||
vector<watch_list>::iterator it = s.m_watches.begin();
|
||||
vector<watch_list>::iterator end = s.m_watches.end();
|
||||
for (; it != end; ++it) {
|
||||
watch_list & wlist = *it;
|
||||
std::stable_sort(wlist.begin(), wlist.end(), iff3_lt());
|
||||
}
|
||||
}
|
||||
|
||||
void iff3_finder::mk_eq(literal l1, literal l2) {
|
||||
s.mk_clause(l1, ~l2);
|
||||
s.mk_clause(~l1, l2);
|
||||
}
|
||||
|
||||
void iff3_finder::operator()() {
|
||||
TRACE("iff3_finder", tout << "starting iff3_finder\n";);
|
||||
sort_watches();
|
||||
|
||||
unsigned counter = 0;
|
||||
|
||||
svector<bool> found;
|
||||
found.resize(s.num_vars()*2, false);
|
||||
literal_vector to_unmark;
|
||||
|
||||
typedef std::pair<literal, literal> lit_pair;
|
||||
svector<lit_pair> pairs;
|
||||
|
||||
for (bool_var x = 0; x < s.num_vars(); x++) {
|
||||
literal pos_x(x, false);
|
||||
literal neg_x(x, true);
|
||||
watch_list & pos_wlist = s.get_wlist(neg_x);
|
||||
watch_list & neg_wlist = s.get_wlist(pos_x);
|
||||
//
|
||||
TRACE("iff3_finder",
|
||||
tout << "visiting: " << x << "\n";
|
||||
tout << "pos:\n";
|
||||
display(tout, s.m_cls_allocator, pos_wlist);
|
||||
tout << "\nneg:\n";
|
||||
display(tout, s.m_cls_allocator, neg_wlist);
|
||||
tout << "\n--------------\n";);
|
||||
// traverse the ternary clauses x \/ l1 \/ l2
|
||||
bool_var curr_v1 = null_bool_var;
|
||||
watch_list::iterator it = pos_wlist.begin();
|
||||
watch_list::iterator end = pos_wlist.end();
|
||||
for (; it != end; ++it) {
|
||||
if (it->is_binary_clause())
|
||||
continue;
|
||||
if (it->is_ternary_clause()) {
|
||||
literal l1 = it->get_literal1();
|
||||
if (l1.index() < pos_x.index())
|
||||
break; // stop
|
||||
literal l2 = it->get_literal2();
|
||||
bool_var v1 = l1.var();
|
||||
if (v1 != curr_v1) {
|
||||
curr_v1 = v1;
|
||||
unmark(found, to_unmark);
|
||||
pairs.reset();
|
||||
}
|
||||
if (!l1.sign()) {
|
||||
if (!found[l2.index()]) {
|
||||
found[l2.index()] = true;
|
||||
to_unmark.push_back(l2);
|
||||
}
|
||||
}
|
||||
else {
|
||||
l2.neg();
|
||||
if (found[l2.index()]) {
|
||||
// Found clauses x \/ v1 \/ l2 and x \/ ~v1 \/ ~l2
|
||||
// So, I have to find the clauses
|
||||
// ~x \/ v1 \/ ~l2
|
||||
// ~x \/ ~v1 \/ l2
|
||||
if (contains(neg_wlist, literal(v1, false), ~l2) &&
|
||||
contains(neg_wlist, literal(v1, true), l2)) {
|
||||
// found new iff3
|
||||
// x = v1 = l2
|
||||
counter++;
|
||||
// verbose_stream() << counter << ": " << x << " = " << v1 << " = " << l2 << "\n";
|
||||
TRACE("iff3_finder", tout << counter << ": " << x << " = " << v1 << " = " << l2 << "\n";);
|
||||
l1.neg();
|
||||
svector<lit_pair>::iterator it2 = pairs.begin();
|
||||
svector<lit_pair>::iterator end2 = pairs.end();
|
||||
for (; it2 != end2; ++it2) {
|
||||
if (it2->first == l1) {
|
||||
// l2 == it2->second
|
||||
mk_eq(l2, it2->second);
|
||||
}
|
||||
else if (it2->second == l1) {
|
||||
// l2 == it2->first
|
||||
mk_eq(l2, it2->first);
|
||||
}
|
||||
else if (it2->first == l2) {
|
||||
// l1 == it2->second
|
||||
mk_eq(l1, it2->second);
|
||||
}
|
||||
else if (it2->second == l2) {
|
||||
// l1 == it2->first
|
||||
mk_eq(l1, it2->first);
|
||||
}
|
||||
}
|
||||
pairs.push_back(lit_pair(l1, l2));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
break; // stop, no more ternary clauses from this point
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
48
src/sat/sat_iff3_finder.h
Normal file
48
src/sat/sat_iff3_finder.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
sat_iff3_finder.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Find constraints of the form x = l1 = l2
|
||||
That is, search for clauses of the form
|
||||
~x \/ l1 \/ ~l2
|
||||
~x \/ ~l1 \/ l2
|
||||
x \/ l1 \/ l2
|
||||
x \/ ~l1 \/ ~l2
|
||||
|
||||
The basic idea is to sort the watch lists.
|
||||
|
||||
This information can be used to propagate equivalences
|
||||
during probing (and search).
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2011-06-04.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _SAT_IFF3_FINDER_H_
|
||||
#define _SAT_IFF3_FINDER_H_
|
||||
|
||||
#include"sat_types.h"
|
||||
|
||||
namespace sat {
|
||||
|
||||
class iff3_finder {
|
||||
solver & s;
|
||||
void sort_watches();
|
||||
void mk_eq(literal l1, literal l2);
|
||||
public:
|
||||
iff3_finder(solver & s);
|
||||
|
||||
void operator()();
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif
|
221
src/sat/sat_integrity_checker.cpp
Normal file
221
src/sat/sat_integrity_checker.cpp
Normal file
|
@ -0,0 +1,221 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
sat_integrity_checker.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Checker whether the SAT solver internal datastructures
|
||||
are consistent or not.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2011-05-21.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include"sat_integrity_checker.h"
|
||||
#include"sat_solver.h"
|
||||
#include"trace.h"
|
||||
|
||||
namespace sat {
|
||||
|
||||
integrity_checker::integrity_checker(solver const & _s):
|
||||
s(_s) {
|
||||
}
|
||||
|
||||
// for ternary clauses
|
||||
static bool contains_watched(watch_list const & wlist, literal l1, literal l2) {
|
||||
return wlist.contains(watched(l1, l2));
|
||||
}
|
||||
|
||||
// for nary clauses
|
||||
static bool contains_watched(watch_list const & wlist, clause const & c, clause_offset cls_off) {
|
||||
watch_list::const_iterator it = wlist.begin();
|
||||
watch_list::const_iterator end = wlist.end();
|
||||
for (; it != end; ++it) {
|
||||
if (it->is_clause()) {
|
||||
if (it->get_clause_offset() == cls_off) {
|
||||
// the blocked literal must be in the clause.
|
||||
literal l = it->get_blocked_literal();
|
||||
SASSERT(c.contains(l));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
UNREACHABLE();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool integrity_checker::check_clause(clause const & c) const {
|
||||
SASSERT(!c.was_removed());
|
||||
for (unsigned i = 0; i < c.size(); i++) {
|
||||
SASSERT(c[i].var() <= s.num_vars());
|
||||
CTRACE("sat_bug", s.was_eliminated(c[i].var()),
|
||||
tout << "l: " << c[i].var() << "\n";
|
||||
tout << "c: " << c << "\n";
|
||||
s.display(tout););
|
||||
SASSERT(!s.was_eliminated(c[i].var()));
|
||||
}
|
||||
|
||||
SASSERT(c.check_approx());
|
||||
|
||||
if (c.frozen())
|
||||
return true;
|
||||
|
||||
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(tout, s.m_cls_allocator, s.get_wlist(~c[0]));
|
||||
tout << "\n";);
|
||||
SASSERT(contains_watched(s.get_wlist(~c[0]), c[1], c[2]));
|
||||
SASSERT(contains_watched(s.get_wlist(~c[1]), c[0], c[2]));
|
||||
SASSERT(contains_watched(s.get_wlist(~c[2]), c[0], c[1]));
|
||||
}
|
||||
else {
|
||||
if (s.value(c[0]) == l_false || s.value(c[1]) == l_false) {
|
||||
bool on_prop_stack = false;
|
||||
for (unsigned i = s.m_qhead; i < s.m_trail.size(); i++) {
|
||||
if (s.m_trail[i].var() == c[0].var() ||
|
||||
s.m_trail[i].var() == c[1].var()) {
|
||||
on_prop_stack = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// the clause has been satisfied or all other literals are assigned to false.
|
||||
if (!on_prop_stack && s.status(c) != l_true) {
|
||||
for (unsigned i = 2; i < c.size(); i++) {
|
||||
CTRACE("sat_bug", s.value(c[i]) != l_false,
|
||||
tout << c << " status: " << s.status(c) << "\n";
|
||||
for (unsigned i = 0; i < c.size(); i++) tout << "val(" << i << "): " << s.value(c[i]) << "\n";);
|
||||
SASSERT(s.value(c[i]) == l_false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// the first two literals must be watched.
|
||||
SASSERT(contains_watched(s.get_wlist(~c[0]), c, s.get_offset(c)));
|
||||
SASSERT(contains_watched(s.get_wlist(~c[1]), c, s.get_offset(c)));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool integrity_checker::check_clauses(clause * const * begin, clause * const * end) const {
|
||||
for (clause * const * it = begin; it != end; ++it) {
|
||||
SASSERT(check_clause(*(*it)));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool integrity_checker::check_clauses() const {
|
||||
return check_clauses(s.begin_clauses(), s.end_clauses());
|
||||
}
|
||||
|
||||
bool integrity_checker::check_learned_clauses() const {
|
||||
unsigned num_frozen = 0;
|
||||
clause * const * end = s.end_clauses();
|
||||
for (clause * const * it = s.begin_clauses(); it != end; ++it) {
|
||||
clause & c = *(*it);
|
||||
if (c.frozen())
|
||||
num_frozen++;
|
||||
}
|
||||
SASSERT(num_frozen == s.m_num_frozen);
|
||||
return check_clauses(s.begin_learned(), s.end_learned());
|
||||
}
|
||||
|
||||
bool integrity_checker::check_assignment() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool integrity_checker::check_bool_vars() const {
|
||||
SASSERT(s.m_watches.size() == s.num_vars() * 2);
|
||||
SASSERT(s.m_assignment.size() == s.num_vars() * 2);
|
||||
SASSERT(s.m_lit_mark.size() == s.num_vars() * 2);
|
||||
SASSERT(s.m_justification.size() == s.num_vars());
|
||||
SASSERT(s.m_decision.size() == s.num_vars());
|
||||
SASSERT(s.m_eliminated.size() == s.num_vars());
|
||||
SASSERT(s.m_external.size() == s.num_vars());
|
||||
SASSERT(s.m_level.size() == s.num_vars());
|
||||
SASSERT(s.m_mark.size() == s.num_vars());
|
||||
SASSERT(s.m_activity.size() == s.num_vars());
|
||||
SASSERT(s.m_phase.size() == s.num_vars());
|
||||
SASSERT(s.m_prev_phase.size() == s.num_vars());
|
||||
SASSERT(s.m_assigned_since_gc.size() == s.num_vars());
|
||||
for (bool_var v = 0; v < s.num_vars(); v++) {
|
||||
if (s.was_eliminated(v)) {
|
||||
SASSERT(s.get_wlist(literal(v, false)).empty());
|
||||
SASSERT(s.get_wlist(literal(v, true)).empty());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool integrity_checker::check_watches() const {
|
||||
vector<watch_list>::const_iterator it = s.m_watches.begin();
|
||||
vector<watch_list>::const_iterator end = s.m_watches.end();
|
||||
for (unsigned l_idx = 0; it != end; ++it, ++l_idx) {
|
||||
literal l = ~to_literal(l_idx);
|
||||
watch_list const & wlist = *it;
|
||||
CTRACE("sat_bug", s.was_eliminated(l.var()) && !wlist.empty(),
|
||||
tout << "l: " << l << "\n";
|
||||
s.display_watches(tout);
|
||||
s.display(tout););
|
||||
SASSERT(!s.was_eliminated(l.var()) || wlist.empty());
|
||||
watch_list::const_iterator it2 = wlist.begin();
|
||||
watch_list::const_iterator end2 = wlist.end();
|
||||
for (; it2 != end2; ++it2) {
|
||||
switch (it2->get_kind()) {
|
||||
case watched::BINARY:
|
||||
SASSERT(!s.was_eliminated(it2->get_literal().var()));
|
||||
CTRACE("sat_watched_bug", !s.get_wlist(~(it2->get_literal())).contains(watched(l, it2->is_learned())),
|
||||
tout << "l: " << l << " l2: " << it2->get_literal() << "\n";
|
||||
tout << "was_eliminated1: " << s.was_eliminated(l.var());
|
||||
tout << " was_eliminated2: " << s.was_eliminated(it2->get_literal().var());
|
||||
tout << " learned: " << it2->is_learned() << "\n";
|
||||
sat::display(tout, s.m_cls_allocator, wlist);
|
||||
tout << "\n";
|
||||
sat::display(tout, s.m_cls_allocator, s.get_wlist(~(it2->get_literal())));
|
||||
tout << "\n";);
|
||||
SASSERT(s.get_wlist(~(it2->get_literal())).contains(watched(l, it2->is_learned())));
|
||||
break;
|
||||
case watched::TERNARY:
|
||||
SASSERT(!s.was_eliminated(it2->get_literal1().var()));
|
||||
SASSERT(!s.was_eliminated(it2->get_literal2().var()));
|
||||
SASSERT(it2->get_literal1().index() < it2->get_literal2().index());
|
||||
break;
|
||||
case watched::CLAUSE:
|
||||
SASSERT(!s.m_cls_allocator.get_clause(it2->get_clause_offset())->was_removed());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool integrity_checker::check_reinit_stack() const {
|
||||
clause_wrapper_vector::const_iterator it = s.m_clauses_to_reinit.begin();
|
||||
clause_wrapper_vector::const_iterator end = s.m_clauses_to_reinit.end();
|
||||
for (; it != end; ++it) {
|
||||
if (it->is_binary())
|
||||
continue;
|
||||
SASSERT(it->get_clause()->on_reinit_stack());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool integrity_checker::operator()() const {
|
||||
if (s.inconsistent())
|
||||
return true;
|
||||
SASSERT(check_clauses());
|
||||
SASSERT(check_learned_clauses());
|
||||
SASSERT(check_watches());
|
||||
SASSERT(check_bool_vars());
|
||||
SASSERT(check_reinit_stack());
|
||||
return true;
|
||||
}
|
||||
};
|
42
src/sat/sat_integrity_checker.h
Normal file
42
src/sat/sat_integrity_checker.h
Normal file
|
@ -0,0 +1,42 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
sat_integrity_checker.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Checker whether the SAT solver internal datastructures
|
||||
are consistent or not.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2011-05-21.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _SAT_INTEGRITY_CHECKER_H_
|
||||
#define _SAT_INTEGRITY_CHECKER_H_
|
||||
|
||||
#include"sat_types.h"
|
||||
|
||||
namespace sat {
|
||||
class integrity_checker {
|
||||
solver const & s;
|
||||
public:
|
||||
integrity_checker(solver const & s);
|
||||
|
||||
bool check_clause(clause const & c) const;
|
||||
bool check_clauses(clause * const * begin, clause * const * end) const;
|
||||
bool check_clauses() const;
|
||||
bool check_learned_clauses() const;
|
||||
bool check_assignment() const;
|
||||
bool check_bool_vars() const;
|
||||
bool check_watches() const;
|
||||
bool check_reinit_stack() const;
|
||||
bool operator()() const;
|
||||
};
|
||||
};
|
||||
#endif
|
57
src/sat/sat_justification.h
Normal file
57
src/sat/sat_justification.h
Normal file
|
@ -0,0 +1,57 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
sat_justification.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Justifications for SAT assignments
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2011-05-21.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _SAT_JUSTIFICATIONS_H_
|
||||
#define _SAT_JUSTIFICATIONS_H_
|
||||
|
||||
namespace sat {
|
||||
|
||||
class justification {
|
||||
public:
|
||||
enum kind { NONE, BINARY, TERNARY, CLAUSE, EXT_JUSTIFICATION };
|
||||
private:
|
||||
unsigned m_val1;
|
||||
unsigned m_val2;
|
||||
justification(ext_justification_idx idx, kind k):m_val1(idx), m_val2(k) {}
|
||||
public:
|
||||
justification():m_val1(0), m_val2(NONE) {}
|
||||
justification(literal l):m_val1(l.to_uint()), m_val2(BINARY) {}
|
||||
justification(literal l1, literal l2):m_val1(l1.to_uint()), m_val2(TERNARY + (l2.to_uint() << 3)) {}
|
||||
justification(clause_offset cls_off):m_val1(cls_off), m_val2(CLAUSE) {}
|
||||
justification mk_ext_justification(ext_justification_idx idx) { return justification(idx, EXT_JUSTIFICATION); }
|
||||
|
||||
kind get_kind() const { return static_cast<kind>(m_val2 & 7); }
|
||||
|
||||
bool is_none() const { return m_val2 == NONE; }
|
||||
|
||||
bool is_binary_clause() const { return m_val2 == BINARY; }
|
||||
literal get_literal() const { SASSERT(is_binary_clause()); return to_literal(m_val1); }
|
||||
|
||||
bool is_ternary_clause() const { return get_kind() == TERNARY; }
|
||||
literal get_literal1() const { SASSERT(is_ternary_clause()); return to_literal(m_val1); }
|
||||
literal get_literal2() const { SASSERT(is_ternary_clause()); return to_literal(m_val2 >> 3); }
|
||||
|
||||
bool is_clause() const { return m_val2 == CLAUSE; }
|
||||
clause_offset get_clause_offset() const { return m_val1; }
|
||||
|
||||
bool is_ext_justification() const { return m_val2 == EXT_JUSTIFICATION; }
|
||||
ext_justification_idx get_ext_justification_idx() const { return m_val1; }
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
240
src/sat/sat_model_converter.cpp
Normal file
240
src/sat/sat_model_converter.cpp
Normal file
|
@ -0,0 +1,240 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
sat_model_converter.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Low level model converter for SAT solver.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2011-05-26.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include"sat_model_converter.h"
|
||||
#include"sat_clause.h"
|
||||
#include"trace.h"
|
||||
|
||||
namespace sat {
|
||||
|
||||
model_converter::model_converter() {
|
||||
}
|
||||
|
||||
model_converter::~model_converter() {
|
||||
reset();
|
||||
}
|
||||
|
||||
void model_converter::reset() {
|
||||
m_entries.finalize();
|
||||
}
|
||||
|
||||
void model_converter::operator()(model & m) const {
|
||||
vector<entry>::const_iterator begin = m_entries.begin();
|
||||
vector<entry>::const_iterator it = m_entries.end();
|
||||
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,
|
||||
// and the following procedure flips its value.
|
||||
bool sat = false;
|
||||
bool var_sign;
|
||||
literal_vector::const_iterator it2 = it->m_clauses.begin();
|
||||
literal_vector::const_iterator end2 = it->m_clauses.end();
|
||||
for (; it2 != end2; ++it2) {
|
||||
literal l = *it2;
|
||||
if (l == null_literal) {
|
||||
// end of clause
|
||||
if (!sat) {
|
||||
m[it->var()] = var_sign ? l_false : l_true;
|
||||
break;
|
||||
}
|
||||
sat = false;
|
||||
continue;
|
||||
}
|
||||
if (sat)
|
||||
continue;
|
||||
bool sign = l.sign();
|
||||
bool_var v = l.var();
|
||||
if (v == it->var())
|
||||
var_sign = sign;
|
||||
if (value_at(l, m) == l_true)
|
||||
sat = true;
|
||||
else if (!sat && v != it->var() && m[v] == l_undef) {
|
||||
// clause can be satisfied by assigning v.
|
||||
m[v] = sign ? l_false : l_true;
|
||||
sat = true;
|
||||
}
|
||||
}
|
||||
DEBUG_CODE({
|
||||
// all clauses must be satisfied
|
||||
bool sat = false;
|
||||
it2 = it->m_clauses.begin();
|
||||
for (; it2 != end2; ++it2) {
|
||||
literal l = *it2;
|
||||
if (l == null_literal) {
|
||||
SASSERT(sat);
|
||||
sat = false;
|
||||
continue;
|
||||
}
|
||||
if (sat)
|
||||
continue;
|
||||
if (value_at(l, m) == l_true)
|
||||
sat = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Test if after applying the model converter, all eliminated clauses are
|
||||
satisfied by m.
|
||||
*/
|
||||
bool model_converter::check_model(model const & m) const {
|
||||
bool ok = true;
|
||||
vector<entry>::const_iterator begin = m_entries.begin();
|
||||
vector<entry>::const_iterator it = m_entries.end();
|
||||
while (it != begin) {
|
||||
--it;
|
||||
bool sat = false;
|
||||
literal_vector::const_iterator it2 = it->m_clauses.begin();
|
||||
literal_vector::const_iterator itbegin = it2;
|
||||
literal_vector::const_iterator end2 = it->m_clauses.end();
|
||||
for (; it2 != end2; ++it2) {
|
||||
literal l = *it2;
|
||||
if (l == null_literal) {
|
||||
// end of clause
|
||||
if (!sat) {
|
||||
TRACE("sat_model_bug", tout << "failed eliminated: " << mk_lits_pp(static_cast<unsigned>(it2 - itbegin), itbegin) << "\n";);
|
||||
ok = false;
|
||||
}
|
||||
sat = false;
|
||||
itbegin = it2;
|
||||
itbegin++;
|
||||
continue;
|
||||
}
|
||||
if (sat)
|
||||
continue;
|
||||
if (value_at(l, m) == l_true)
|
||||
sat = true;
|
||||
}
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
model_converter::entry & model_converter::mk(kind k, bool_var v) {
|
||||
m_entries.push_back(entry(k, v));
|
||||
entry & e = m_entries.back();
|
||||
SASSERT(e.var() == v);
|
||||
SASSERT(e.get_kind() == k);
|
||||
return e;
|
||||
}
|
||||
|
||||
void model_converter::insert(entry & e, clause const & c) {
|
||||
SASSERT(c.contains(e.var()));
|
||||
SASSERT(m_entries.begin() <= &e);
|
||||
SASSERT(&e < m_entries.end());
|
||||
unsigned sz = c.size();
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
e.m_clauses.push_back(c[i]);
|
||||
}
|
||||
e.m_clauses.push_back(null_literal);
|
||||
TRACE("sat_mc_bug", tout << "adding: " << c << "\n";);
|
||||
}
|
||||
|
||||
void model_converter::insert(entry & e, literal l1, literal l2) {
|
||||
SASSERT(l1.var() == e.var() || l2.var() == e.var());
|
||||
SASSERT(m_entries.begin() <= &e);
|
||||
SASSERT(&e < m_entries.end());
|
||||
e.m_clauses.push_back(l1);
|
||||
e.m_clauses.push_back(l2);
|
||||
e.m_clauses.push_back(null_literal);
|
||||
TRACE("sat_mc_bug", tout << "adding (binary): " << l1 << " " << l2 << "\n";);
|
||||
}
|
||||
|
||||
void model_converter::insert(entry & e, clause_wrapper const & c) {
|
||||
SASSERT(c.contains(e.var()));
|
||||
SASSERT(m_entries.begin() <= &e);
|
||||
SASSERT(&e < m_entries.end());
|
||||
unsigned sz = c.size();
|
||||
for (unsigned i = 0; i < sz; i++)
|
||||
e.m_clauses.push_back(c[i]);
|
||||
e.m_clauses.push_back(null_literal);
|
||||
TRACE("sat_mc_bug", tout << "adding (wrapper): "; for (unsigned i = 0; i < c.size(); i++) tout << c[i] << " "; tout << "\n";);
|
||||
}
|
||||
|
||||
bool model_converter::check_invariant(unsigned num_vars) const {
|
||||
// After a variable v occurs in an entry n and the entry has kind ELIM_VAR,
|
||||
// then the variable must not occur in any other entry occurring after it.
|
||||
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);
|
||||
if (it->get_kind() == ELIM_VAR) {
|
||||
svector<entry>::const_iterator it2 = it;
|
||||
it2++;
|
||||
for (; it2 != end; ++it2) {
|
||||
SASSERT(it2->var() != it->var());
|
||||
literal_vector::const_iterator it3 = it2->m_clauses.begin();
|
||||
literal_vector::const_iterator end3 = it2->m_clauses.end();
|
||||
for (; it3 != end3; ++it3) {
|
||||
CTRACE("sat_model_converter", it3->var() == it->var(), tout << "var: " << it->var() << "\n"; display(tout););
|
||||
SASSERT(it3->var() != it->var());
|
||||
SASSERT(*it3 == null_literal || it3->var() < num_vars);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void model_converter::display(std::ostream & out) const {
|
||||
out << "(sat::model-converter";
|
||||
vector<entry>::const_iterator it = m_entries.begin();
|
||||
vector<entry>::const_iterator end = m_entries.end();
|
||||
for (; it != end; ++it) {
|
||||
out << "\n (" << (it->get_kind() == ELIM_VAR ? "elim" : "blocked") << " " << it->var();
|
||||
bool start = true;
|
||||
literal_vector::const_iterator it2 = it->m_clauses.begin();
|
||||
literal_vector::const_iterator end2 = it->m_clauses.end();
|
||||
for (; it2 != end2; ++it2) {
|
||||
if (start) {
|
||||
out << "\n (";
|
||||
start = false;
|
||||
}
|
||||
else {
|
||||
if (*it2 != null_literal)
|
||||
out << " ";
|
||||
}
|
||||
if (*it2 == null_literal) {
|
||||
out << ")";
|
||||
start = true;
|
||||
continue;
|
||||
}
|
||||
out << *it2;
|
||||
}
|
||||
out << ")";
|
||||
}
|
||||
out << ")\n";
|
||||
}
|
||||
|
||||
void model_converter::copy(model_converter const & src) {
|
||||
vector<entry>::const_iterator it = src.m_entries.begin();
|
||||
vector<entry>::const_iterator end = src.m_entries.end();
|
||||
for (; it != end; ++it)
|
||||
m_entries.push_back(*it);
|
||||
}
|
||||
|
||||
void model_converter::collect_vars(bool_var_set & s) const {
|
||||
vector<entry>::const_iterator it = m_entries.begin();
|
||||
vector<entry>::const_iterator end = m_entries.end();
|
||||
for (; it != end; ++it) {
|
||||
s.insert(it->m_var);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
81
src/sat/sat_model_converter.h
Normal file
81
src/sat/sat_model_converter.h
Normal file
|
@ -0,0 +1,81 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
sat_model_converter.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Low level model converter for SAT solver.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2011-05-26.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _SAT_MODEL_CONVERTER_H_
|
||||
#define _SAT_MODEL_CONVERTER_H_
|
||||
|
||||
#include"sat_types.h"
|
||||
|
||||
namespace sat {
|
||||
/**
|
||||
\brief Stores eliminated variables and Blocked clauses.
|
||||
It uses these clauses to extend/patch the model produced for the
|
||||
simplified CNF formula.
|
||||
|
||||
This information may also be used to support incremental solving.
|
||||
If new clauses are asserted into the SAT engine, then we can
|
||||
restore the state by re-asserting all clauses in the model
|
||||
converter.
|
||||
|
||||
This is a low-level model_converter. Given a mapping from bool_var to expr,
|
||||
it can be converted into a general Z3 model_converter
|
||||
*/
|
||||
class model_converter {
|
||||
public:
|
||||
enum kind { ELIM_VAR = 0, BLOCK_LIT };
|
||||
class entry {
|
||||
friend class model_converter;
|
||||
unsigned m_var:31;
|
||||
unsigned m_kind:1;
|
||||
literal_vector m_clauses; // the different clauses are separated by null_literal
|
||||
entry(kind k, bool_var v):m_var(v), m_kind(k) {}
|
||||
public:
|
||||
entry(entry const & src):
|
||||
m_var(src.m_var),
|
||||
m_kind(src.m_kind),
|
||||
m_clauses(src.m_clauses) {
|
||||
}
|
||||
bool_var var() const { return m_var; }
|
||||
kind get_kind() const { return static_cast<kind>(m_kind); }
|
||||
};
|
||||
private:
|
||||
vector<entry> m_entries;
|
||||
public:
|
||||
model_converter();
|
||||
~model_converter();
|
||||
void operator()(model & m) const;
|
||||
|
||||
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);
|
||||
|
||||
bool empty() const { return m_entries.empty(); }
|
||||
|
||||
void reset();
|
||||
bool check_invariant(unsigned num_vars) const;
|
||||
void display(std::ostream & out) const;
|
||||
bool check_model(model const & m) const;
|
||||
|
||||
void copy(model_converter const & src);
|
||||
void collect_vars(bool_var_set & s) const;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif
|
269
src/sat/sat_probing.cpp
Normal file
269
src/sat/sat_probing.cpp
Normal file
|
@ -0,0 +1,269 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
sat_probing.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Probing (aka failed literal detection).
|
||||
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2011-06-04.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include"sat_probing.h"
|
||||
#include"sat_solver.h"
|
||||
|
||||
namespace sat {
|
||||
probing::probing(solver & _s, params_ref const & p):
|
||||
s(_s) {
|
||||
updt_params(p);
|
||||
reset_statistics();
|
||||
m_stopped_at = 0;
|
||||
m_counter = 0;
|
||||
}
|
||||
|
||||
// reset the cache for the given literal
|
||||
void probing::reset_cache(literal l) {
|
||||
if (l.index() < m_cached_bins.size()) {
|
||||
m_cached_bins[l.index()].m_available = false;
|
||||
m_cached_bins[l.index()].m_lits.finalize();
|
||||
}
|
||||
}
|
||||
|
||||
// l implied the literals on the trail stack starting at position old_tr_sz
|
||||
// Thus, ~l \/ l2 is a binary clause for every l2 on this fragment of the trail stack.
|
||||
void probing::cache_bins(literal l, unsigned old_tr_sz) {
|
||||
if (!m_probing_cache)
|
||||
return;
|
||||
if (memory::get_allocation_size() > m_probing_cache_limit)
|
||||
return; // not enough memory to spare
|
||||
m_cached_bins.reserve(l.index() + 1);
|
||||
cache_entry & entry = m_cached_bins[l.index()];
|
||||
entry.m_available = true;
|
||||
entry.m_lits.reset();
|
||||
unsigned tr_sz = s.m_trail.size();
|
||||
for (unsigned i = old_tr_sz; i < tr_sz; i++) {
|
||||
entry.m_lits.push_back(s.m_trail[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Return true if should keep going.
|
||||
// It will assert literals implied by l that are already marked
|
||||
// as assigned.
|
||||
bool probing::try_lit(literal l, bool updt_cache) {
|
||||
SASSERT(s.m_qhead == s.m_trail.size());
|
||||
SASSERT(s.value(l.var()) == l_undef);
|
||||
literal_vector * implied_lits = updt_cache ? 0 : cached_implied_lits(l);
|
||||
if (implied_lits) {
|
||||
literal_vector::iterator it = implied_lits->begin();
|
||||
literal_vector::iterator end = implied_lits->end();
|
||||
for (; it != end; ++it) {
|
||||
if (m_assigned.contains(*it)) {
|
||||
s.assign(*it, justification());
|
||||
m_num_assigned++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
m_to_assert.reset();
|
||||
s.push();
|
||||
s.assign(l, justification());
|
||||
m_counter--;
|
||||
unsigned old_tr_sz = s.m_trail.size();
|
||||
s.propagate(false);
|
||||
if (s.inconsistent()) {
|
||||
// ~l must be true
|
||||
s.pop(1);
|
||||
s.assign(~l, justification());
|
||||
s.propagate(false);
|
||||
return false;
|
||||
}
|
||||
// collect literals that were assigned after assigning l
|
||||
unsigned tr_sz = s.m_trail.size();
|
||||
for (unsigned i = old_tr_sz; i < tr_sz; i++) {
|
||||
if (m_assigned.contains(s.m_trail[i])) {
|
||||
m_to_assert.push_back(s.m_trail[i]);
|
||||
}
|
||||
}
|
||||
if (updt_cache)
|
||||
cache_bins(l, old_tr_sz);
|
||||
s.pop(1);
|
||||
|
||||
literal_vector::iterator it = m_to_assert.begin();
|
||||
literal_vector::iterator end = m_to_assert.end();
|
||||
for (; it != end; ++it) {
|
||||
s.assign(*it, justification());
|
||||
m_num_assigned++;
|
||||
}
|
||||
}
|
||||
s.propagate(false);
|
||||
return !s.inconsistent();
|
||||
}
|
||||
|
||||
void probing::process_core(bool_var v) {
|
||||
TRACE("probing", tout << "processing: " << v << " counter: " << -m_counter << "\n";);
|
||||
SASSERT(s.m_qhead == s.m_trail.size());
|
||||
SASSERT(s.value(v) == l_undef);
|
||||
m_counter--;
|
||||
s.push();
|
||||
literal l(v, false);
|
||||
s.assign(l, justification());
|
||||
unsigned old_tr_sz = s.m_trail.size();
|
||||
s.propagate(false);
|
||||
if (s.inconsistent()) {
|
||||
// ~l must be true
|
||||
s.pop(1);
|
||||
s.assign(~l, justification());
|
||||
s.propagate(false);
|
||||
m_num_assigned++;
|
||||
return;
|
||||
}
|
||||
// collect literals that were assigned after assigning l
|
||||
m_assigned.reset();
|
||||
unsigned tr_sz = s.m_trail.size();
|
||||
for (unsigned i = old_tr_sz; i < tr_sz; i++) {
|
||||
m_assigned.insert(s.m_trail[i]);
|
||||
}
|
||||
cache_bins(l, old_tr_sz);
|
||||
s.pop(1);
|
||||
|
||||
if (!try_lit(~l, true))
|
||||
return;
|
||||
|
||||
if (m_probing_binary) {
|
||||
watch_list & wlist = s.get_wlist(~l);
|
||||
watch_list::iterator it = wlist.begin();
|
||||
watch_list::iterator end = wlist.end();
|
||||
for (; it != end ; ++it) {
|
||||
if (!it->is_binary_clause())
|
||||
break;
|
||||
literal l2 = it->get_literal();
|
||||
if (l.index() > l2.index())
|
||||
continue;
|
||||
if (s.value(l2) != l_undef)
|
||||
continue;
|
||||
// verbose_stream() << "probing " << l << " " << l2 << " " << m_counter << "\n";
|
||||
if (!try_lit(l2, false))
|
||||
return;
|
||||
if (s.inconsistent())
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void probing::process(bool_var v) {
|
||||
int old_counter = m_counter;
|
||||
unsigned old_num_assigned = m_num_assigned;
|
||||
process_core(v);
|
||||
if (m_num_assigned > old_num_assigned) {
|
||||
// if new variables were assigned when probing x,
|
||||
// then assume the cost is 0.
|
||||
m_counter = old_counter;
|
||||
}
|
||||
}
|
||||
|
||||
struct probing::report {
|
||||
probing & m_probing;
|
||||
stopwatch m_watch;
|
||||
unsigned m_num_assigned;
|
||||
report(probing & p):
|
||||
m_probing(p),
|
||||
m_num_assigned(p.m_num_assigned) {
|
||||
m_watch.start();
|
||||
}
|
||||
|
||||
~report() {
|
||||
m_watch.stop();
|
||||
IF_VERBOSE(SAT_VB_LVL,
|
||||
verbose_stream() << " (sat-probing :probing-assigned "
|
||||
<< (m_probing.m_num_assigned - m_num_assigned)
|
||||
<< " :cost " << m_probing.m_counter;
|
||||
if (m_probing.m_stopped_at != 0) verbose_stream() << " :stopped-at " << m_probing.m_stopped_at;
|
||||
verbose_stream() << mem_stat() << " :time " << std::fixed << std::setprecision(2) << m_watch.get_seconds() << ")\n";);
|
||||
}
|
||||
};
|
||||
|
||||
bool probing::operator()(bool force) {
|
||||
if (!m_probing)
|
||||
return true;
|
||||
s.propagate(false); // make sure propagation queue is empty
|
||||
if (s.inconsistent())
|
||||
return true;
|
||||
CASSERT("probing", s.check_invariant());
|
||||
if (!force && m_counter > 0)
|
||||
return true;
|
||||
|
||||
if (m_probing_cache && memory::get_allocation_size() > m_probing_cache_limit)
|
||||
m_cached_bins.finalize();
|
||||
|
||||
report rpt(*this);
|
||||
bool r = true;
|
||||
m_counter = 0;
|
||||
int limit = -static_cast<int>(m_probing_limit);
|
||||
unsigned i;
|
||||
unsigned num = s.num_vars();
|
||||
for (i = 0; i < num; i++) {
|
||||
bool_var v = (m_stopped_at + i) % num;
|
||||
if (m_counter < limit) {
|
||||
m_stopped_at = v;
|
||||
r = false;
|
||||
break;
|
||||
}
|
||||
if (s.inconsistent()) {
|
||||
break;
|
||||
}
|
||||
if (s.value(v) != l_undef || s.was_eliminated(v)) {
|
||||
if (m_probing_cache) {
|
||||
// cache for v literals is not needed anymore.
|
||||
reset_cache(literal(v, false));
|
||||
reset_cache(literal(v, true));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
s.checkpoint();
|
||||
process(v);
|
||||
}
|
||||
if (r)
|
||||
m_stopped_at = 0;
|
||||
m_counter = -m_counter;
|
||||
if (rpt.m_num_assigned == m_num_assigned) {
|
||||
// penalize
|
||||
m_counter *= 2;
|
||||
}
|
||||
CASSERT("probing", s.check_invariant());
|
||||
free_memory();
|
||||
return r;
|
||||
}
|
||||
|
||||
void probing::updt_params(params_ref const & p) {
|
||||
m_probing = p.get_bool(":probing", true);
|
||||
m_probing_limit = p.get_uint(":probing-limit", 5000000);
|
||||
m_probing_cache = p.get_bool(":probing-cache", true);
|
||||
m_probing_binary = p.get_bool(":probing-binary", true);
|
||||
m_probing_cache_limit = megabytes_to_bytes(p.get_uint(":probing-chache-limit", 1024));
|
||||
}
|
||||
|
||||
void probing::collect_param_descrs(param_descrs & d) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
void probing::free_memory() {
|
||||
m_assigned.cleanup();
|
||||
m_to_assert.finalize();
|
||||
}
|
||||
|
||||
void probing::collect_statistics(statistics & st) {
|
||||
st.update("probing assigned", m_num_assigned);
|
||||
}
|
||||
|
||||
void probing::reset_statistics() {
|
||||
m_num_assigned = 0;
|
||||
}
|
||||
};
|
92
src/sat/sat_probing.h
Normal file
92
src/sat/sat_probing.h
Normal file
|
@ -0,0 +1,92 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
sat_probing.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Probing (aka failed literal detection).
|
||||
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2011-06-04.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _SAT_PROBING_H_
|
||||
#define _SAT_PROBING_H_
|
||||
|
||||
#include"sat_types.h"
|
||||
#include"params.h"
|
||||
#include"statistics.h"
|
||||
|
||||
namespace sat {
|
||||
|
||||
class probing {
|
||||
solver & s;
|
||||
unsigned m_stopped_at; // where did it stop
|
||||
literal_set m_assigned; // literals assigned in the first branch
|
||||
literal_vector m_to_assert;
|
||||
|
||||
// counters
|
||||
int m_counter; // track cost
|
||||
|
||||
// config
|
||||
bool m_probing; // enabled/disabled
|
||||
unsigned m_probing_limit; // max cost per round
|
||||
bool m_probing_cache; // cache implicit binary clauses
|
||||
bool m_probing_binary; // try l1 and l2 for binary clauses l1 \/ l2
|
||||
unsigned long long m_probing_cache_limit; // memory limit for enabling caching.
|
||||
|
||||
// stats
|
||||
unsigned m_num_assigned;
|
||||
|
||||
struct cache_entry {
|
||||
bool m_available;
|
||||
literal_vector m_lits;
|
||||
cache_entry():m_available(false) {}
|
||||
};
|
||||
|
||||
vector<cache_entry> m_cached_bins;
|
||||
|
||||
struct report;
|
||||
|
||||
void reset_cache(literal l);
|
||||
void cache_bins(literal l, unsigned old_tr_sz);
|
||||
bool try_lit(literal l, bool updt_cache);
|
||||
void process(bool_var v);
|
||||
void process_core(bool_var v);
|
||||
|
||||
public:
|
||||
probing(solver & s, params_ref const & p);
|
||||
|
||||
bool operator()(bool force = false);
|
||||
|
||||
void updt_params(params_ref const & p);
|
||||
static void collect_param_descrs(param_descrs & d);
|
||||
|
||||
void free_memory();
|
||||
|
||||
void collect_statistics(statistics & st);
|
||||
void reset_statistics();
|
||||
|
||||
// return the literals implied by l.
|
||||
// return 0, if the cache is not available
|
||||
literal_vector * cached_implied_lits(literal l) {
|
||||
if (!m_probing_cache) return 0;
|
||||
if (l.index() >= m_cached_bins.size()) return 0;
|
||||
cache_entry & e = m_cached_bins[l.index()];
|
||||
if (!e.m_available) return 0;
|
||||
return &(e.m_lits);
|
||||
}
|
||||
|
||||
void dec(unsigned c) { m_counter -= c; }
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif
|
241
src/sat/sat_scc.cpp
Normal file
241
src/sat/sat_scc.cpp
Normal file
|
@ -0,0 +1,241 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
sat_scc.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Use binary clauses to compute strongly connected components.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2011-05-26.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include"sat_scc.h"
|
||||
#include"sat_solver.h"
|
||||
#include"sat_elim_eqs.h"
|
||||
#include"stopwatch.h"
|
||||
#include"trace.h"
|
||||
|
||||
namespace sat {
|
||||
|
||||
scc::scc(solver & s, params_ref const & p):
|
||||
m_solver(s) {
|
||||
reset_statistics();
|
||||
updt_params(p);
|
||||
}
|
||||
|
||||
struct frame {
|
||||
unsigned m_lidx;
|
||||
bool m_first;
|
||||
watched * m_it;
|
||||
watched * m_end;
|
||||
frame(unsigned lidx, watched * it, watched * end):m_lidx(lidx), m_first(true), m_it(it), m_end(end) {}
|
||||
};
|
||||
typedef svector<frame> frames;
|
||||
|
||||
struct scc::report {
|
||||
scc & m_scc;
|
||||
stopwatch m_watch;
|
||||
unsigned m_num_elim;
|
||||
report(scc & c):
|
||||
m_scc(c),
|
||||
m_num_elim(c.m_num_elim) {
|
||||
m_watch.start();
|
||||
}
|
||||
~report() {
|
||||
m_watch.stop();
|
||||
IF_VERBOSE(SAT_VB_LVL,
|
||||
verbose_stream() << " (sat-scc :elim-vars " << (m_scc.m_num_elim - m_num_elim)
|
||||
<< mk_stat(m_scc.m_solver)
|
||||
<< " :time " << std::fixed << std::setprecision(2) << m_watch.get_seconds() << ")\n";);
|
||||
}
|
||||
};
|
||||
|
||||
unsigned scc::operator()() {
|
||||
if (m_solver.m_inconsistent)
|
||||
return 0;
|
||||
if (!m_scc)
|
||||
return 0;
|
||||
CASSERT("scc_bug", m_solver.check_invariant());
|
||||
report rpt(*this);
|
||||
TRACE("scc", m_solver.display(tout););
|
||||
TRACE("scc_details", m_solver.display_watches(tout););
|
||||
unsigned_vector index;
|
||||
unsigned_vector lowlink;
|
||||
unsigned_vector s;
|
||||
svector<char> in_s;
|
||||
unsigned num_lits = m_solver.num_vars() * 2;
|
||||
index.resize(num_lits, UINT_MAX);
|
||||
lowlink.resize(num_lits, UINT_MAX);
|
||||
in_s.resize(num_lits, false);
|
||||
literal_vector roots;
|
||||
roots.resize(m_solver.num_vars(), null_literal);
|
||||
unsigned next_index = 0;
|
||||
svector<frame> frames;
|
||||
bool_var_vector to_elim;
|
||||
|
||||
for (unsigned l_idx = 0; l_idx < num_lits; l_idx++) {
|
||||
if (index[l_idx] != UINT_MAX)
|
||||
continue;
|
||||
if (m_solver.was_eliminated(to_literal(l_idx).var()))
|
||||
continue;
|
||||
|
||||
m_solver.checkpoint();
|
||||
|
||||
#define NEW_NODE(LIDX) { \
|
||||
index[LIDX] = next_index; \
|
||||
lowlink[LIDX] = next_index; \
|
||||
next_index++; \
|
||||
s.push_back(LIDX); \
|
||||
in_s[LIDX] = true; \
|
||||
watch_list & wlist = m_solver.get_wlist(LIDX); \
|
||||
frames.push_back(frame(LIDX, wlist.begin(), wlist.end())); \
|
||||
}
|
||||
|
||||
NEW_NODE(l_idx);
|
||||
|
||||
while (!frames.empty()) {
|
||||
loop:
|
||||
frame & fr = frames.back();
|
||||
unsigned l_idx = fr.m_lidx;
|
||||
if (!fr.m_first) {
|
||||
// after visiting child
|
||||
literal l2 = fr.m_it->get_literal();
|
||||
unsigned l2_idx = l2.index();
|
||||
SASSERT(index[l2_idx] != UINT_MAX);
|
||||
if (lowlink[l2_idx] < lowlink[l_idx])
|
||||
lowlink[l_idx] = lowlink[l2_idx];
|
||||
fr.m_it++;
|
||||
}
|
||||
fr.m_first = false;
|
||||
while (fr.m_it != fr.m_end) {
|
||||
if (!fr.m_it->is_binary_clause()) {
|
||||
fr.m_it++;
|
||||
continue;
|
||||
}
|
||||
literal l2 = fr.m_it->get_literal();
|
||||
unsigned l2_idx = l2.index();
|
||||
if (index[l2_idx] == UINT_MAX) {
|
||||
NEW_NODE(l2_idx);
|
||||
goto loop;
|
||||
}
|
||||
else if (in_s[l2_idx]) {
|
||||
if (index[l2_idx] < lowlink[l_idx])
|
||||
lowlink[l_idx] = index[l2_idx];
|
||||
}
|
||||
fr.m_it++;
|
||||
}
|
||||
// visited all successors
|
||||
if (lowlink[l_idx] == index[l_idx]) {
|
||||
// found new SCC
|
||||
CTRACE("scc_cycle", s.back() != l_idx, {
|
||||
tout << "cycle: ";
|
||||
unsigned j = s.size() - 1;
|
||||
unsigned l2_idx;
|
||||
do {
|
||||
l2_idx = s[j];
|
||||
j--;
|
||||
tout << to_literal(l2_idx) << " ";
|
||||
}
|
||||
while (l2_idx != l_idx);
|
||||
tout << "\n";
|
||||
});
|
||||
|
||||
SASSERT(!s.empty());
|
||||
literal l = to_literal(l_idx);
|
||||
bool_var v = l.var();
|
||||
if (roots[v] != null_literal) {
|
||||
// variable was already assigned... just consume stack
|
||||
TRACE("scc_detail", tout << "consuming stack...\n";);
|
||||
unsigned l2_idx;
|
||||
do {
|
||||
l2_idx = s.back();
|
||||
s.pop_back();
|
||||
in_s[l2_idx] = false;
|
||||
SASSERT(roots[to_literal(l2_idx).var()].var() == roots[v].var());
|
||||
}
|
||||
while (l2_idx != l_idx);
|
||||
}
|
||||
else {
|
||||
// check if the SCC has an external variable, and check for conflicts
|
||||
TRACE("scc_detail", tout << "assigning roots...\n";);
|
||||
literal r = null_literal;
|
||||
unsigned j = s.size() - 1;
|
||||
unsigned l2_idx;
|
||||
do {
|
||||
l2_idx = s[j];
|
||||
j--;
|
||||
if (to_literal(l2_idx) == ~l) {
|
||||
m_solver.set_conflict(justification());
|
||||
return 0;
|
||||
}
|
||||
if (m_solver.is_external(to_literal(l2_idx).var())) {
|
||||
r = to_literal(l2_idx);
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (l2_idx != l_idx);
|
||||
|
||||
if (r == null_literal) {
|
||||
// SCC does not contain external variable
|
||||
r = to_literal(l_idx);
|
||||
}
|
||||
|
||||
TRACE("scc_detail", tout << "r: " << r << "\n";);
|
||||
|
||||
do {
|
||||
l2_idx = s.back();
|
||||
s.pop_back();
|
||||
in_s[l2_idx] = false;
|
||||
literal l2 = to_literal(l2_idx);
|
||||
bool_var v2 = l2.var();
|
||||
if (roots[v2] == null_literal) {
|
||||
if (l2.sign()) {
|
||||
roots[v2] = ~r;
|
||||
}
|
||||
else {
|
||||
roots[v2] = r;
|
||||
}
|
||||
if (v2 != r.var())
|
||||
to_elim.push_back(v2);
|
||||
}
|
||||
}
|
||||
while (l2_idx != l_idx);
|
||||
}
|
||||
}
|
||||
frames.pop_back();
|
||||
}
|
||||
}
|
||||
TRACE("scc", for (unsigned i = 0; i < roots.size(); i++) { tout << i << " -> " << roots[i] << "\n"; }
|
||||
tout << "to_elim: "; for (unsigned i = 0; i < to_elim.size(); i++) tout << to_elim[i] << " "; tout << "\n";);
|
||||
m_num_elim += to_elim.size();
|
||||
elim_eqs eliminator(m_solver);
|
||||
eliminator(roots, to_elim);
|
||||
TRACE("scc_detail", m_solver.display(tout););
|
||||
CASSERT("scc_bug", m_solver.check_invariant());
|
||||
return to_elim.size();
|
||||
}
|
||||
|
||||
void scc::collect_statistics(statistics & st) {
|
||||
st.update("elim bool vars", m_num_elim);
|
||||
}
|
||||
|
||||
void scc::reset_statistics() {
|
||||
m_num_elim = 0;
|
||||
}
|
||||
|
||||
void scc::updt_params(params_ref const & p) {
|
||||
m_scc = p.get_bool(":scc", true);
|
||||
}
|
||||
|
||||
void scc::collect_param_descrs(param_descrs & d) {
|
||||
d.insert(":scc", CPK_BOOL, "(default: true) eliminate Boolean variables by computing strongly connected components.");
|
||||
}
|
||||
|
||||
};
|
48
src/sat/sat_scc.h
Normal file
48
src/sat/sat_scc.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
sat_scc.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Use binary clauses to compute strongly connected components.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2011-05-26.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _SAT_SCC_H_
|
||||
#define _SAT_SCC_H_
|
||||
|
||||
#include"sat_types.h"
|
||||
#include"statistics.h"
|
||||
#include"params.h"
|
||||
|
||||
namespace sat {
|
||||
class solver;
|
||||
|
||||
class scc {
|
||||
struct report;
|
||||
solver & m_solver;
|
||||
// config
|
||||
bool m_scc;
|
||||
// stats
|
||||
unsigned m_num_elim;
|
||||
public:
|
||||
scc(solver & s, params_ref const & p);
|
||||
unsigned operator()();
|
||||
|
||||
void updt_params(params_ref const & p);
|
||||
static void collect_param_descrs(param_descrs & d);
|
||||
|
||||
void collect_statistics(statistics & st);
|
||||
void reset_statistics();
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
1489
src/sat/sat_simplifier.cpp
Normal file
1489
src/sat/sat_simplifier.cpp
Normal file
File diff suppressed because it is too large
Load diff
188
src/sat/sat_simplifier.h
Normal file
188
src/sat/sat_simplifier.h
Normal file
|
@ -0,0 +1,188 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
sat_simplifier.h
|
||||
|
||||
Abstract:
|
||||
|
||||
SAT simplification procedures that use a "full" occurrence list:
|
||||
Subsumption, Blocked Clause Removal, Variable Elimination, ...
|
||||
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2011-05-24.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _SAT_SIMPLIFIER_H_
|
||||
#define _SAT_SIMPLIFIER_H_
|
||||
|
||||
#include"sat_types.h"
|
||||
#include"sat_clause.h"
|
||||
#include"sat_clause_set.h"
|
||||
#include"sat_clause_use_list.h"
|
||||
#include"sat_watched.h"
|
||||
#include"sat_model_converter.h"
|
||||
#include"heap.h"
|
||||
#include"statistics.h"
|
||||
#include"params.h"
|
||||
|
||||
namespace sat {
|
||||
class solver;
|
||||
|
||||
class use_list {
|
||||
vector<clause_use_list> m_use_list;
|
||||
public:
|
||||
void init(unsigned num_vars);
|
||||
void insert(clause & c);
|
||||
void erase(clause & c);
|
||||
void erase(clause & c, literal l);
|
||||
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(); }
|
||||
};
|
||||
|
||||
class simplifier {
|
||||
solver & s;
|
||||
unsigned m_num_calls;
|
||||
use_list m_use_list;
|
||||
clause_set m_sub_todo;
|
||||
svector<bin_clause> m_sub_bin_todo;
|
||||
unsigned m_last_sub_trail_sz; // size of the trail since last cleanup
|
||||
bool_var_set m_elim_todo;
|
||||
bool m_need_cleanup;
|
||||
tmp_clause m_dummy;
|
||||
|
||||
// simplifier extra variable fields.
|
||||
svector<char> m_visited; // transient
|
||||
|
||||
// counters
|
||||
int m_sub_counter;
|
||||
int m_elim_counter;
|
||||
|
||||
// config
|
||||
bool m_elim_blocked_clauses;
|
||||
unsigned m_elim_blocked_clauses_at;
|
||||
unsigned m_blocked_clause_limit;
|
||||
bool m_resolution;
|
||||
unsigned m_res_limit;
|
||||
unsigned m_res_occ_cutoff;
|
||||
unsigned m_res_occ_cutoff1;
|
||||
unsigned m_res_occ_cutoff2;
|
||||
unsigned m_res_occ_cutoff3;
|
||||
unsigned m_res_lit_cutoff1;
|
||||
unsigned m_res_lit_cutoff2;
|
||||
unsigned m_res_lit_cutoff3;
|
||||
unsigned m_res_cls_cutoff1;
|
||||
unsigned m_res_cls_cutoff2;
|
||||
|
||||
bool m_subsumption;
|
||||
unsigned m_subsumption_limit;
|
||||
|
||||
// stats
|
||||
unsigned m_num_blocked_clauses;
|
||||
unsigned m_num_subsumed;
|
||||
unsigned m_num_elim_vars;
|
||||
unsigned m_num_sub_res;
|
||||
unsigned m_num_elim_lits;
|
||||
|
||||
struct size_lt {
|
||||
bool operator()(clause const * c1, clause const * c2) const { return c1->size() > c2->size(); }
|
||||
};
|
||||
|
||||
void checkpoint();
|
||||
|
||||
void init_visited();
|
||||
void mark_visited(literal l) { m_visited[l.index()] = true; }
|
||||
void unmark_visited(literal l) { m_visited[l.index()] = false; }
|
||||
bool is_marked(literal l) const { return m_visited[l.index()] != 0; }
|
||||
void mark_all_but(clause const & c, literal l);
|
||||
void unmark_all(clause const & c);
|
||||
|
||||
void register_clauses(clause_vector & cs);
|
||||
|
||||
void remove_clause_core(clause & c);
|
||||
void remove_clause(clause & c);
|
||||
void remove_clause(clause & c, literal l);
|
||||
void remove_bin_clause_half(literal l1, literal l2, bool learned);
|
||||
|
||||
bool_var get_min_occ_var(clause const & c) const;
|
||||
bool subsumes1(clause const & c1, clause const & c2, literal & l);
|
||||
void collect_subsumed1_core(clause const & c, clause_vector & out, literal_vector & out_lits, literal target);
|
||||
void collect_subsumed1(clause const & c, clause_vector & out, literal_vector & out_lits);
|
||||
clause_vector m_bs_cs;
|
||||
literal_vector m_bs_ls;
|
||||
void back_subsumption1(clause & c);
|
||||
void back_subsumption1(literal l1, literal l2, bool learned);
|
||||
|
||||
literal get_min_occ_var0(clause const & c) const;
|
||||
bool subsumes0(clause const & c1, clause const & c2);
|
||||
void collect_subsumed0_core(clause const & c1, clause_vector & out, literal target);
|
||||
void collect_subsumed0(clause const & c1, clause_vector & out);
|
||||
void back_subsumption0(clause & c1);
|
||||
|
||||
bool cleanup_clause(clause & c);
|
||||
bool cleanup_clause(literal_vector & c);
|
||||
void propagate_unit(literal l);
|
||||
void elim_lit(clause & c, literal l);
|
||||
void elim_dup_bins();
|
||||
bool subsume_with_binaries();
|
||||
void mark_as_not_learned_core(watch_list & wlist, literal l2);
|
||||
void mark_as_not_learned(literal l1, literal l2);
|
||||
void subsume();
|
||||
|
||||
void cleanup_watches();
|
||||
void cleanup_clauses(clause_vector & cs, bool learned, bool vars_eliminated);
|
||||
|
||||
bool is_external(bool_var v) const;
|
||||
bool was_eliminated(bool_var v) const;
|
||||
lbool value(bool_var v) const;
|
||||
lbool value(literal l) const;
|
||||
watch_list & get_wlist(literal l);
|
||||
watch_list const & get_wlist(literal l) const;
|
||||
|
||||
struct blocked_clause_elim;
|
||||
void elim_blocked_clauses();
|
||||
|
||||
unsigned get_num_non_learned_bin(literal l) const;
|
||||
unsigned get_to_elim_cost(bool_var v) const;
|
||||
void order_vars_for_elim(bool_var_vector & r);
|
||||
void collect_clauses(literal l, clause_wrapper_vector & r);
|
||||
clause_wrapper_vector m_pos_cls;
|
||||
clause_wrapper_vector m_neg_cls;
|
||||
literal_vector m_new_cls;
|
||||
bool resolve(clause_wrapper const & c1, clause_wrapper const & c2, literal l, literal_vector & r);
|
||||
void save_clauses(model_converter::entry & mc_entry, clause_wrapper_vector const & cs);
|
||||
void add_non_learned_binary_clause(literal l1, literal l2);
|
||||
void remove_bin_clauses(literal l);
|
||||
void remove_clauses(clause_use_list const & cs, literal l);
|
||||
bool try_eliminate(bool_var v);
|
||||
void elim_vars();
|
||||
|
||||
struct blocked_cls_report;
|
||||
struct subsumption_report;
|
||||
struct elim_var_report;
|
||||
|
||||
public:
|
||||
simplifier(solver & s, params_ref const & p);
|
||||
~simplifier();
|
||||
|
||||
void insert_todo(bool_var v) { m_elim_todo.insert(v); }
|
||||
|
||||
void operator()(bool learned);
|
||||
|
||||
void updt_params(params_ref const & p);
|
||||
static void collect_param_descrs(param_descrs & d);
|
||||
|
||||
void free_memory();
|
||||
|
||||
void collect_statistics(statistics & st);
|
||||
void reset_statistics();
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
2330
src/sat/sat_solver.cpp
Normal file
2330
src/sat/sat_solver.cpp
Normal file
File diff suppressed because it is too large
Load diff
428
src/sat/sat_solver.h
Normal file
428
src/sat/sat_solver.h
Normal file
|
@ -0,0 +1,428 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
sat_solver.h
|
||||
|
||||
Abstract:
|
||||
|
||||
SAT solver main class.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2011-05-21.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _SAT_SOLVER_H_
|
||||
#define _SAT_SOLVER_H_
|
||||
|
||||
#include"sat_types.h"
|
||||
#include"sat_clause.h"
|
||||
#include"sat_watched.h"
|
||||
#include"sat_justification.h"
|
||||
#include"sat_var_queue.h"
|
||||
#include"sat_extension.h"
|
||||
#include"sat_config.h"
|
||||
#include"sat_cleaner.h"
|
||||
#include"sat_simplifier.h"
|
||||
#include"sat_scc.h"
|
||||
#include"sat_asymm_branch.h"
|
||||
#include"sat_iff3_finder.h"
|
||||
#include"sat_probing.h"
|
||||
#include"params.h"
|
||||
#include"statistics.h"
|
||||
#include"stopwatch.h"
|
||||
#include"trace.h"
|
||||
|
||||
namespace sat {
|
||||
|
||||
/**
|
||||
\brief Main statistic counters.
|
||||
*/
|
||||
struct stats {
|
||||
unsigned m_mk_var;
|
||||
unsigned m_mk_bin_clause;
|
||||
unsigned m_mk_ter_clause;
|
||||
unsigned m_mk_clause;
|
||||
unsigned m_conflict;
|
||||
unsigned m_propagate;
|
||||
unsigned m_bin_propagate;
|
||||
unsigned m_ter_propagate;
|
||||
unsigned m_decision;
|
||||
unsigned m_restart;
|
||||
unsigned m_gc_clause;
|
||||
unsigned m_del_clause;
|
||||
unsigned m_minimized_lits;
|
||||
unsigned m_dyn_sub_res;
|
||||
stats() { reset(); }
|
||||
void reset();
|
||||
void collect_statistics(statistics & st) const;
|
||||
};
|
||||
|
||||
class solver {
|
||||
public:
|
||||
struct abort_solver {};
|
||||
protected:
|
||||
volatile bool m_cancel;
|
||||
config m_config;
|
||||
stats m_stats;
|
||||
extension * m_ext;
|
||||
random_gen m_rand;
|
||||
clause_allocator m_cls_allocator;
|
||||
cleaner m_cleaner;
|
||||
model m_model;
|
||||
model_converter m_mc;
|
||||
simplifier m_simplifier;
|
||||
scc m_scc;
|
||||
asymm_branch m_asymm_branch;
|
||||
probing m_probing;
|
||||
bool m_inconsistent;
|
||||
// A conflict is usually a single justification. That is, a justification
|
||||
// for false. If m_not_l is not null_literal, then m_conflict is a
|
||||
// justification for l, and the conflict is union of m_no_l and m_conflict;
|
||||
justification m_conflict;
|
||||
literal m_not_l;
|
||||
clause_vector m_clauses;
|
||||
clause_vector m_learned;
|
||||
unsigned m_num_frozen;
|
||||
vector<watch_list> m_watches;
|
||||
svector<lbool> m_assignment;
|
||||
svector<justification> m_justification;
|
||||
svector<char> m_decision;
|
||||
svector<char> m_mark;
|
||||
svector<char> m_lit_mark;
|
||||
svector<char> m_eliminated;
|
||||
svector<char> m_external;
|
||||
svector<unsigned> m_level;
|
||||
svector<unsigned> m_activity;
|
||||
unsigned m_activity_inc;
|
||||
svector<char> m_phase;
|
||||
svector<char> m_prev_phase;
|
||||
svector<char> m_assigned_since_gc;
|
||||
bool m_phase_cache_on;
|
||||
unsigned m_phase_counter;
|
||||
var_queue m_case_split_queue;
|
||||
unsigned m_qhead;
|
||||
unsigned m_scope_lvl;
|
||||
literal_vector m_trail;
|
||||
clause_wrapper_vector m_clauses_to_reinit;
|
||||
struct scope {
|
||||
unsigned m_trail_lim;
|
||||
unsigned m_clauses_to_reinit_lim;
|
||||
bool m_inconsistent;
|
||||
};
|
||||
svector<scope> m_scopes;
|
||||
stopwatch m_stopwatch;
|
||||
params_ref m_params;
|
||||
scoped_ptr<solver> m_clone; // for debugging purposes
|
||||
|
||||
void del_clauses(clause * const * begin, clause * const * end);
|
||||
|
||||
friend class integrity_checker;
|
||||
friend class cleaner;
|
||||
friend class simplifier;
|
||||
friend class scc;
|
||||
friend class elim_eqs;
|
||||
friend class asymm_branch;
|
||||
friend class probing;
|
||||
friend class iff3_finder;
|
||||
friend struct mk_stat;
|
||||
public:
|
||||
solver(params_ref const & p, extension * ext);
|
||||
~solver();
|
||||
|
||||
// -----------------------
|
||||
//
|
||||
// Misc
|
||||
//
|
||||
// -----------------------
|
||||
void updt_params(params_ref const & p);
|
||||
static void collect_param_descrs(param_descrs & d);
|
||||
|
||||
void set_cancel(bool f);
|
||||
void collect_statistics(statistics & st);
|
||||
void reset_statistics();
|
||||
void display_status(std::ostream & out) const;
|
||||
|
||||
/**
|
||||
\brief Copy (non learned) clauses from src to this solver.
|
||||
Create missing variables if needed.
|
||||
|
||||
\pre the model converter of src and this must be empty
|
||||
*/
|
||||
void copy(solver const & src);
|
||||
|
||||
// -----------------------
|
||||
//
|
||||
// Variable & Clause creation
|
||||
//
|
||||
// -----------------------
|
||||
bool_var mk_var(bool ext = false, bool dvar = true);
|
||||
void mk_clause(unsigned num_lits, literal * lits);
|
||||
void mk_clause(literal l1, literal l2);
|
||||
void mk_clause(literal l1, literal l2, literal l3);
|
||||
|
||||
protected:
|
||||
void del_clause(clause & c) { m_cls_allocator.del_clause(&c); m_stats.m_del_clause++; }
|
||||
clause * mk_clause_core(unsigned num_lits, literal * lits, bool learned);
|
||||
void mk_bin_clause(literal l1, literal l2, bool learned);
|
||||
bool propagate_bin_clause(literal l1, literal l2);
|
||||
clause * mk_ter_clause(literal * lits, bool learned);
|
||||
void attach_ter_clause(clause & c, bool & reinit);
|
||||
void attach_ter_clause(clause & c) { bool reinit; attach_ter_clause(c, reinit); }
|
||||
clause * mk_nary_clause(unsigned num_lits, literal * lits, bool learned);
|
||||
void attach_nary_clause(clause & c, bool & reinit);
|
||||
void attach_nary_clause(clause & c) { bool reinit; attach_nary_clause(c, reinit); }
|
||||
void attach_clause(clause & c, bool & reinit);
|
||||
void attach_clause(clause & c) { bool reinit; attach_clause(c, reinit); }
|
||||
unsigned select_watch_lit(clause const & cls, unsigned starting_at) const;
|
||||
unsigned select_learned_watch_lit(clause const & cls) const;
|
||||
bool simplify_clause(unsigned & num_lits, literal * lits) const;
|
||||
template<bool lvl0>
|
||||
bool simplify_clause_core(unsigned & num_lits, literal * lits) const;
|
||||
void dettach_bin_clause(literal l1, literal l2, bool learned);
|
||||
void dettach_clause(clause & c);
|
||||
void dettach_nary_clause(clause & c);
|
||||
void dettach_ter_clause(clause & c);
|
||||
void push_reinit_stack(clause & c);
|
||||
|
||||
// -----------------------
|
||||
//
|
||||
// Basic
|
||||
//
|
||||
// -----------------------
|
||||
public:
|
||||
bool inconsistent() const { return m_inconsistent; }
|
||||
unsigned num_vars() const { return m_level.size(); }
|
||||
bool is_external(bool_var v) const { return m_external[v] != 0; }
|
||||
bool was_eliminated(bool_var v) const { return m_eliminated[v] != 0; }
|
||||
unsigned scope_lvl() const { return m_scope_lvl; }
|
||||
lbool value(literal l) const { return m_assignment[l.index()]; }
|
||||
lbool value(bool_var v) const { return m_assignment[literal(v, false).index()]; }
|
||||
unsigned lvl(bool_var v) const { return m_level[v]; }
|
||||
unsigned lvl(literal l) const { return m_level[l.var()]; }
|
||||
void assign(literal l, justification j) {
|
||||
TRACE("sat_assign", tout << l << " previous value: " << value(l) << "\n";);
|
||||
switch (value(l)) {
|
||||
case l_false: set_conflict(j, ~l); break;
|
||||
case l_undef: assign_core(l, j); break;
|
||||
case l_true: return;
|
||||
}
|
||||
}
|
||||
void assign_core(literal l, justification jst);
|
||||
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); }
|
||||
void checkpoint() {
|
||||
if (m_cancel) throw solver_exception(TACTIC_CANCELED_MSG);
|
||||
if (memory::get_allocation_size() > m_config.m_max_memory) throw solver_exception(TACTIC_MAX_MEMORY_MSG);
|
||||
}
|
||||
protected:
|
||||
watch_list & get_wlist(literal l) { return m_watches[l.index()]; }
|
||||
watch_list const & get_wlist(literal l) const { return m_watches[l.index()]; }
|
||||
watch_list & get_wlist(unsigned l_idx) { return m_watches[l_idx]; }
|
||||
bool is_marked(bool_var v) const { return m_mark[v] != 0; }
|
||||
void mark(bool_var v) { SASSERT(!is_marked(v)); m_mark[v] = true; }
|
||||
void reset_mark(bool_var v) { SASSERT(is_marked(v)); m_mark[v] = false; }
|
||||
bool is_marked_lit(literal l) const { return m_lit_mark[l.index()] != 0; }
|
||||
void mark_lit(literal l) { SASSERT(!is_marked_lit(l)); m_lit_mark[l.index()] = true; }
|
||||
void unmark_lit(literal l) { SASSERT(is_marked_lit(l)); m_lit_mark[l.index()] = false; }
|
||||
|
||||
// -----------------------
|
||||
//
|
||||
// Propagation
|
||||
//
|
||||
// -----------------------
|
||||
public:
|
||||
// if update == true, then glue of learned clauses is updated.
|
||||
bool propagate(bool update);
|
||||
|
||||
protected:
|
||||
bool propagate_core(bool update);
|
||||
|
||||
// -----------------------
|
||||
//
|
||||
// Search
|
||||
//
|
||||
// -----------------------
|
||||
public:
|
||||
lbool check();
|
||||
model const & get_model() const { return m_model; }
|
||||
model_converter const & get_model_converter() const { return m_mc; }
|
||||
|
||||
protected:
|
||||
unsigned m_conflicts;
|
||||
unsigned m_conflicts_since_restart;
|
||||
unsigned m_restart_threshold;
|
||||
unsigned m_luby_idx;
|
||||
unsigned m_conflicts_since_gc;
|
||||
unsigned m_gc_threshold;
|
||||
double m_min_d_tk;
|
||||
unsigned m_next_simplify;
|
||||
bool decide();
|
||||
bool_var next_var();
|
||||
lbool bounded_search();
|
||||
void init_search();
|
||||
void simplify_problem();
|
||||
void mk_model();
|
||||
bool check_model(model const & m) const;
|
||||
void restart();
|
||||
void sort_watch_lits();
|
||||
|
||||
// -----------------------
|
||||
//
|
||||
// GC
|
||||
//
|
||||
// -----------------------
|
||||
protected:
|
||||
void gc();
|
||||
void gc_glue();
|
||||
void gc_psm();
|
||||
void gc_glue_psm();
|
||||
void gc_psm_glue();
|
||||
void save_psm();
|
||||
void gc_half(char const * st_name);
|
||||
void gc_dyn_psm();
|
||||
bool activate_frozen_clause(clause & c);
|
||||
unsigned psm(clause const & c) const;
|
||||
bool can_delete(clause const & c) const {
|
||||
if (c.on_reinit_stack())
|
||||
return false;
|
||||
if (c.size() == 3)
|
||||
return true; // not needed to justify anything.
|
||||
literal l0 = c[0];
|
||||
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;
|
||||
}
|
||||
|
||||
// -----------------------
|
||||
//
|
||||
// Conflict resolution
|
||||
//
|
||||
// -----------------------
|
||||
protected:
|
||||
unsigned m_conflict_lvl;
|
||||
literal_vector m_lemma;
|
||||
literal_vector m_ext_antecedents;
|
||||
bool resolve_conflict();
|
||||
bool resolve_conflict_core();
|
||||
unsigned get_max_lvl(literal consequent, justification js);
|
||||
void process_antecedent(literal antecedent, unsigned & num_marks);
|
||||
void fill_ext_antecedents(literal consequent, justification js);
|
||||
unsigned skip_literals_above_conflict_level();
|
||||
void forget_phase_of_vars(unsigned from_lvl);
|
||||
void updt_phase_counters();
|
||||
svector<char> m_diff_levels;
|
||||
unsigned num_diff_levels(unsigned num, literal const * lits);
|
||||
|
||||
// lemma minimization
|
||||
typedef approx_set_tpl<unsigned, u2u, unsigned> level_approx_set;
|
||||
bool_var_vector m_unmark;
|
||||
level_approx_set m_lvl_set;
|
||||
bool_var_vector m_lemma_min_stack;
|
||||
bool process_antecedent_for_minimization(literal antecedent);
|
||||
bool implied_by_marked(literal lit);
|
||||
void reset_unmark(unsigned old_size);
|
||||
void updt_lemma_lvl_set();
|
||||
void minimize_lemma();
|
||||
void reset_lemma_var_marks();
|
||||
void dyn_sub_res();
|
||||
|
||||
// -----------------------
|
||||
//
|
||||
// Backtracking
|
||||
//
|
||||
// -----------------------
|
||||
public:
|
||||
void push();
|
||||
void pop(unsigned num_scopes);
|
||||
|
||||
protected:
|
||||
void unassign_vars(unsigned old_sz);
|
||||
void reinit_clauses(unsigned old_sz);
|
||||
|
||||
// -----------------------
|
||||
//
|
||||
// Simplification
|
||||
//
|
||||
// -----------------------
|
||||
public:
|
||||
void cleanup();
|
||||
void simplify(bool learned = true);
|
||||
void asymmetric_branching();
|
||||
unsigned scc_bin();
|
||||
|
||||
// -----------------------
|
||||
//
|
||||
// Activity related stuff
|
||||
//
|
||||
// -----------------------
|
||||
public:
|
||||
void inc_activity(bool_var v) {
|
||||
unsigned & act = m_activity[v];
|
||||
act += m_activity_inc;
|
||||
m_case_split_queue.activity_increased_eh(v);
|
||||
if (act > (1 << 24))
|
||||
rescale_activity();
|
||||
}
|
||||
|
||||
void decay_activity() {
|
||||
m_activity_inc *= 11;
|
||||
m_activity_inc /= 10;
|
||||
}
|
||||
|
||||
private:
|
||||
void rescale_activity();
|
||||
|
||||
// -----------------------
|
||||
//
|
||||
// Iterators
|
||||
//
|
||||
// -----------------------
|
||||
public:
|
||||
clause * const * begin_clauses() const { return m_clauses.begin(); }
|
||||
clause * const * end_clauses() const { return m_clauses.end(); }
|
||||
clause * const * begin_learned() const { return m_learned.begin(); }
|
||||
clause * const * end_learned() const { return m_learned.end(); }
|
||||
typedef std::pair<literal, literal> bin_clause;
|
||||
void collect_bin_clauses(svector<bin_clause> & r, bool learned) const;
|
||||
|
||||
// -----------------------
|
||||
//
|
||||
// Debugging
|
||||
//
|
||||
// -----------------------
|
||||
public:
|
||||
bool check_invariant() const;
|
||||
void display(std::ostream & out) const;
|
||||
void display_watches(std::ostream & out) const;
|
||||
void display_dimacs(std::ostream & out) const;
|
||||
|
||||
protected:
|
||||
void display_binary(std::ostream & out) const;
|
||||
void display_units(std::ostream & out) const;
|
||||
void display_assignment(std::ostream & out) const;
|
||||
unsigned num_clauses() const;
|
||||
bool is_unit(clause const & c) const;
|
||||
bool is_empty(clause const & c) const;
|
||||
bool check_missed_propagation(clause_vector const & cs) const;
|
||||
bool check_missed_propagation() const;
|
||||
bool check_marks() const;
|
||||
};
|
||||
|
||||
struct mk_stat {
|
||||
solver const & m_solver;
|
||||
mk_stat(solver const & s):m_solver(s) {}
|
||||
void display(std::ostream & out) const;
|
||||
};
|
||||
|
||||
std::ostream & operator<<(std::ostream & out, mk_stat const & stat);
|
||||
};
|
||||
|
||||
#endif
|
237
src/sat/sat_types.h
Normal file
237
src/sat/sat_types.h
Normal file
|
@ -0,0 +1,237 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
sat_types.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Basic types used in the SAT solver
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2011-05-21.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _SAT_TYPES_H_
|
||||
#define _SAT_TYPES_H_
|
||||
|
||||
#include"debug.h"
|
||||
#include"approx_set.h"
|
||||
#include"lbool.h"
|
||||
#include"tactic_exception.h"
|
||||
#include"vector.h"
|
||||
#include<iomanip>
|
||||
|
||||
namespace sat {
|
||||
#define SAT_VB_LVL 10
|
||||
|
||||
// TODO: there is some duplication in the sat and smt namespaces.
|
||||
// The sat namespace should be the base.
|
||||
// I should cleanup the smt namespace later.
|
||||
|
||||
/**
|
||||
\brief A boolean variable is just an integer.
|
||||
*/
|
||||
typedef unsigned bool_var;
|
||||
|
||||
typedef svector<bool_var> bool_var_vector;
|
||||
|
||||
const bool_var null_bool_var = UINT_MAX >> 1;
|
||||
|
||||
/**
|
||||
\brief The literal b is represented by the value 2*b, and
|
||||
the literal (not b) by the value 2*b + 1
|
||||
*/
|
||||
class literal {
|
||||
unsigned m_val;
|
||||
explicit literal(unsigned v):m_val(v) {}
|
||||
public:
|
||||
literal():m_val(null_bool_var << 1) {
|
||||
SASSERT(var() == null_bool_var && !sign());
|
||||
}
|
||||
|
||||
literal(bool_var v, bool _sign):
|
||||
m_val((v << 1) + static_cast<unsigned>(_sign)) {
|
||||
SASSERT(var() == v);
|
||||
SASSERT(sign() == _sign);
|
||||
}
|
||||
|
||||
bool_var var() const {
|
||||
return m_val >> 1;
|
||||
}
|
||||
|
||||
bool sign() const {
|
||||
return m_val & 1;
|
||||
}
|
||||
|
||||
literal unsign() const {
|
||||
return literal(m_val & ~1);
|
||||
}
|
||||
|
||||
unsigned index() const {
|
||||
return m_val;
|
||||
}
|
||||
|
||||
void neg() {
|
||||
m_val = m_val ^ 1;
|
||||
}
|
||||
|
||||
friend literal operator~(literal l) {
|
||||
return literal(l.m_val ^ 1);
|
||||
}
|
||||
|
||||
unsigned to_uint() const { return m_val; }
|
||||
|
||||
unsigned hash() const { return to_uint(); }
|
||||
|
||||
friend literal to_literal(unsigned x);
|
||||
friend bool operator<(literal const & l1, literal const & l2);
|
||||
friend bool operator==(literal const & l1, literal const & l2);
|
||||
friend bool operator!=(literal const & l1, literal const & l2);
|
||||
};
|
||||
|
||||
const literal null_literal;
|
||||
|
||||
inline literal to_literal(unsigned x) { return literal(x); }
|
||||
inline bool operator<(literal const & l1, literal const & l2) { return l1.m_val < l2.m_val; }
|
||||
inline bool operator==(literal const & l1, literal const & l2) { return l1.m_val == l2.m_val; }
|
||||
inline bool operator!=(literal const & l1, literal const & l2) { return l1.m_val != l2.m_val; }
|
||||
|
||||
inline std::ostream & operator<<(std::ostream & out, literal l) { out << (l.sign() ? "-" : "") << l.var(); return out; }
|
||||
|
||||
typedef svector<literal> literal_vector;
|
||||
|
||||
typedef unsigned clause_offset;
|
||||
typedef unsigned ext_constraint_idx;
|
||||
typedef unsigned ext_justification_idx;
|
||||
|
||||
struct literal2unsigned { unsigned operator()(literal l) const { return l.to_uint(); } };
|
||||
|
||||
typedef approx_set_tpl<literal, literal2unsigned, unsigned> literal_approx_set;
|
||||
|
||||
typedef approx_set_tpl<bool_var, u2u, unsigned> var_approx_set;
|
||||
|
||||
enum phase {
|
||||
POS_PHASE, NEG_PHASE, PHASE_NOT_AVAILABLE
|
||||
};
|
||||
|
||||
class solver;
|
||||
class clause;
|
||||
class clause_wrapper;
|
||||
class integrity_checker;
|
||||
typedef ptr_vector<clause> clause_vector;
|
||||
|
||||
class solver_exception : public tactic_exception {
|
||||
public:
|
||||
solver_exception(char const * msg):tactic_exception(msg) {}
|
||||
};
|
||||
|
||||
typedef default_exception sat_param_exception;
|
||||
|
||||
typedef svector<lbool> model;
|
||||
|
||||
inline lbool value_at(bool_var v, model const & m) { return m[v]; }
|
||||
inline lbool value_at(literal l, model const & m) { lbool r = value_at(l.var(), m); return l.sign() ? ~r : r; }
|
||||
|
||||
inline std::ostream & operator<<(std::ostream & out, model const & m) {
|
||||
bool first = true;
|
||||
for (bool_var v = 0; v < m.size(); v++) {
|
||||
if (m[v] == l_undef) continue;
|
||||
if (first) first = false; else out << " ";
|
||||
if (m[v] == l_true) out << v; else out << "-" << v;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
class uint_set {
|
||||
svector<char> m_in_set;
|
||||
svector<unsigned> m_set;
|
||||
public:
|
||||
typedef svector<unsigned>::const_iterator iterator;
|
||||
void insert(unsigned v) {
|
||||
m_in_set.reserve(v+1, false);
|
||||
if (m_in_set[v])
|
||||
return;
|
||||
m_in_set[v] = true;
|
||||
m_set.push_back(v);
|
||||
}
|
||||
|
||||
bool contains(unsigned v) const {
|
||||
return v < m_in_set.size() && m_in_set[v] != 0;
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
return m_set.empty();
|
||||
}
|
||||
|
||||
// erase some variable from the set
|
||||
unsigned erase() {
|
||||
SASSERT(!empty());
|
||||
unsigned v = m_set.back();
|
||||
m_set.pop_back();
|
||||
m_in_set[v] = false;
|
||||
return v;
|
||||
}
|
||||
iterator begin() const { return m_set.begin(); }
|
||||
iterator end() const { return m_set.end(); }
|
||||
void reset() { m_set.reset(); m_in_set.reset(); }
|
||||
void cleanup() { m_set.finalize(); m_in_set.finalize(); }
|
||||
};
|
||||
|
||||
typedef uint_set bool_var_set;
|
||||
|
||||
class literal_set {
|
||||
uint_set m_set;
|
||||
public:
|
||||
void insert(literal l) { m_set.insert(l.index()); }
|
||||
bool contains(literal l) const { return m_set.contains(l.index()); }
|
||||
bool empty() const { return m_set.empty(); }
|
||||
void reset() { m_set.reset(); }
|
||||
void cleanup() { m_set.cleanup(); }
|
||||
};
|
||||
|
||||
struct mem_stat {
|
||||
};
|
||||
|
||||
inline std::ostream & operator<<(std::ostream & out, mem_stat const & m) {
|
||||
double mem = static_cast<double>(memory::get_allocation_size())/static_cast<double>(1024*1024);
|
||||
out << " :memory " << std::fixed << std::setprecision(2) << mem;
|
||||
return out;
|
||||
}
|
||||
|
||||
struct dimacs_lit {
|
||||
literal m_lit;
|
||||
dimacs_lit(literal l):m_lit(l) {}
|
||||
};
|
||||
|
||||
inline std::ostream & operator<<(std::ostream & out, dimacs_lit const & dl) {
|
||||
literal l = dl.m_lit;
|
||||
if (l.sign()) out << "-" << (l.var() + 1);
|
||||
else out << (l.var() + 1);
|
||||
return out;
|
||||
}
|
||||
|
||||
struct mk_lits_pp {
|
||||
unsigned m_num;
|
||||
literal const * m_lits;
|
||||
mk_lits_pp(unsigned num, literal const * ls):m_num(num), m_lits(ls) {}
|
||||
};
|
||||
|
||||
inline std::ostream & operator<<(std::ostream & out, mk_lits_pp const & ls) {
|
||||
for (unsigned i = 0; i < ls.m_num; i++) {
|
||||
if (i > 0) out << " ";
|
||||
out << ls.m_lits[i];
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
inline std::ostream & operator<<(std::ostream & out, literal_vector const & ls) {
|
||||
return out << mk_lits_pp(ls.size(), ls.c_ptr());
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
67
src/sat/sat_var_queue.h
Normal file
67
src/sat/sat_var_queue.h
Normal file
|
@ -0,0 +1,67 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
sat_var_queue.h
|
||||
|
||||
Abstract:
|
||||
|
||||
SAT variable priority queue.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2011-05-21.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _SAT_VAR_QUEUE_H_
|
||||
#define _SAT_VAR_QUEUE_H_
|
||||
|
||||
#include"heap.h"
|
||||
#include"sat_types.h"
|
||||
|
||||
namespace sat {
|
||||
|
||||
class var_queue {
|
||||
struct lt {
|
||||
svector<unsigned> & m_activity;
|
||||
lt(svector<unsigned> & act):m_activity(act) {}
|
||||
bool operator()(bool_var v1, bool_var v2) const { return m_activity[v1] > m_activity[v2]; }
|
||||
};
|
||||
heap<lt> m_queue;
|
||||
public:
|
||||
var_queue(svector<unsigned> & act):m_queue(128, lt(act)) {}
|
||||
|
||||
void activity_increased_eh(bool_var v) {
|
||||
if (m_queue.contains(v))
|
||||
m_queue.decreased(v);
|
||||
}
|
||||
|
||||
void mk_var_eh(bool_var v) {
|
||||
m_queue.reserve(v+1);
|
||||
m_queue.insert(v);
|
||||
}
|
||||
|
||||
void del_var_eh(bool_var v) {
|
||||
if (m_queue.contains(v))
|
||||
m_queue.erase(v);
|
||||
}
|
||||
|
||||
void unassign_var_eh(bool_var v) {
|
||||
if (!m_queue.contains(v))
|
||||
m_queue.insert(v);
|
||||
}
|
||||
|
||||
void reset() {
|
||||
m_queue.reset();
|
||||
}
|
||||
|
||||
bool empty() const { return m_queue.empty(); }
|
||||
|
||||
bool_var next_var() { SASSERT(!empty()); return m_queue.erase_min(); }
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
71
src/sat/sat_watched.cpp
Normal file
71
src/sat/sat_watched.cpp
Normal file
|
@ -0,0 +1,71 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
sat_watched.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Element of the SAT solver watchlist.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2011-05-24.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include"sat_watched.h"
|
||||
#include"sat_clause.h"
|
||||
|
||||
namespace sat {
|
||||
|
||||
bool erase_clause_watch(watch_list & wlist, clause_offset c) {
|
||||
watch_list::iterator it = wlist.begin();
|
||||
watch_list::iterator end = wlist.end();
|
||||
for (; it != end; ++it) {
|
||||
if (it->is_clause() && it->get_clause_offset() == c) {
|
||||
watch_list::iterator it2 = it;
|
||||
++it;
|
||||
for (; it != end; ++it) {
|
||||
*it2 = *it;
|
||||
++it2;
|
||||
}
|
||||
wlist.set_end(it2);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void display(std::ostream & out, clause_allocator const & ca, watch_list const & wlist) {
|
||||
watch_list::const_iterator it = wlist.begin();
|
||||
watch_list::const_iterator end = wlist.end();
|
||||
for (bool first = true; it != end; ++it) {
|
||||
if (first)
|
||||
first = false;
|
||||
else
|
||||
out << " ";
|
||||
switch (it->get_kind()) {
|
||||
case watched::BINARY:
|
||||
out << it->get_literal();
|
||||
if (it->is_learned())
|
||||
out << "*";
|
||||
break;
|
||||
case watched::TERNARY:
|
||||
out << "(" << it->get_literal1() << " " << it->get_literal2() << ")";
|
||||
break;
|
||||
case watched::CLAUSE:
|
||||
out << "(" << it->get_blocked_literal() << " " << *(ca.get_clause(it->get_clause_offset())) << ")";
|
||||
break;
|
||||
case watched::EXT_CONSTRAINT:
|
||||
out << it->get_ext_constraint_idx();
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
136
src/sat/sat_watched.h
Normal file
136
src/sat/sat_watched.h
Normal file
|
@ -0,0 +1,136 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
sat_watched.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Element of the SAT solver watchlist.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2011-05-21.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _SAT_WATCHED_H_
|
||||
#define _SAT_WATCHED_H_
|
||||
|
||||
#include"sat_types.h"
|
||||
#include"vector.h"
|
||||
|
||||
namespace sat {
|
||||
/**
|
||||
A watched element can be:
|
||||
|
||||
1) A literal: for watched binary clauses
|
||||
2) A pair of literals: for watched ternary clauses
|
||||
3) A pair (literal, clause-offset): for watched clauses, where the first element of the pair is a literal of the clause.
|
||||
4) A external constraint-idx: for external constraints.
|
||||
|
||||
For binary clauses: we use a bit to store whether the binary clause was learned or not.
|
||||
|
||||
Remark: there is not Clause object for binary clauses.
|
||||
*/
|
||||
class watched {
|
||||
public:
|
||||
enum kind {
|
||||
BINARY = 0, TERNARY, CLAUSE, EXT_CONSTRAINT
|
||||
};
|
||||
private:
|
||||
unsigned m_val1;
|
||||
unsigned m_val2;
|
||||
public:
|
||||
watched(literal l, bool learned):
|
||||
m_val1(l.to_uint()),
|
||||
m_val2(static_cast<unsigned>(BINARY) + (static_cast<unsigned>(learned) << 2)) {
|
||||
SASSERT(is_binary_clause());
|
||||
SASSERT(get_literal() == l);
|
||||
SASSERT(is_learned() == learned);
|
||||
SASSERT(learned || is_binary_non_learned_clause());
|
||||
}
|
||||
|
||||
watched(literal l1, literal l2) {
|
||||
SASSERT(l1 != l2);
|
||||
if (l1.index() > l2.index())
|
||||
std::swap(l1, l2);
|
||||
m_val1 = l1.to_uint();
|
||||
m_val2 = static_cast<unsigned>(TERNARY) + (l2.to_uint() << 2);
|
||||
SASSERT(is_ternary_clause());
|
||||
SASSERT(get_literal1() == l1);
|
||||
SASSERT(get_literal2() == l2);
|
||||
}
|
||||
|
||||
watched(literal blocked_lit, clause_offset cls_off):
|
||||
m_val1(cls_off),
|
||||
m_val2(static_cast<unsigned>(CLAUSE) + (blocked_lit.to_uint() << 2)) {
|
||||
SASSERT(is_clause());
|
||||
SASSERT(get_blocked_literal() == blocked_lit);
|
||||
SASSERT(get_clause_offset() == cls_off);
|
||||
}
|
||||
|
||||
watched(ext_constraint_idx cnstr_idx):
|
||||
m_val1(cnstr_idx),
|
||||
m_val2(static_cast<unsigned>(EXT_CONSTRAINT)) {
|
||||
SASSERT(is_ext_constraint());
|
||||
SASSERT(get_ext_constraint_idx() == cnstr_idx);
|
||||
}
|
||||
|
||||
kind get_kind() const { return static_cast<kind>(m_val2 & 3); }
|
||||
|
||||
bool is_binary_clause() const { return get_kind() == BINARY; }
|
||||
literal get_literal() const { SASSERT(is_binary_clause()); return to_literal(m_val1); }
|
||||
void set_literal(literal l) { SASSERT(is_binary_clause()); m_val1 = l.to_uint(); }
|
||||
bool is_learned() const { SASSERT(is_binary_clause()); return (m_val2 >> 2) == 1; }
|
||||
bool is_binary_non_learned_clause() const { return m_val2 == 0; }
|
||||
void mark_not_learned() { SASSERT(is_learned()); m_val2 = static_cast<unsigned>(BINARY); SASSERT(!is_learned()); }
|
||||
|
||||
bool is_ternary_clause() const { return get_kind() == TERNARY; }
|
||||
literal get_literal1() const { SASSERT(is_ternary_clause()); return to_literal(m_val1); }
|
||||
literal get_literal2() const { SASSERT(is_ternary_clause()); return to_literal(m_val2 >> 2); }
|
||||
|
||||
bool is_clause() const { return get_kind() == CLAUSE; }
|
||||
clause_offset get_clause_offset() const { SASSERT(is_clause()); return m_val1; }
|
||||
literal get_blocked_literal() const { SASSERT(is_clause()); return to_literal(m_val2 >> 2); }
|
||||
void set_clause_offset(clause_offset c) { SASSERT(is_clause()); m_val1 = c; }
|
||||
void set_blocked_literal(literal l) { SASSERT(is_clause()); m_val2 = static_cast<unsigned>(CLAUSE) + (l.to_uint() << 2); }
|
||||
void set_clause(literal blocked_lit, clause_offset cls_off) {
|
||||
m_val1 = cls_off;
|
||||
m_val2 = static_cast<unsigned>(CLAUSE) + (blocked_lit.to_uint() << 2);
|
||||
}
|
||||
|
||||
bool is_ext_constraint() const { return get_kind() == EXT_CONSTRAINT; }
|
||||
ext_constraint_idx get_ext_constraint_idx() const { SASSERT(is_ext_constraint()); return m_val2; }
|
||||
|
||||
bool operator==(watched const & w) const { return m_val1 == w.m_val1 && m_val2 == w.m_val2; }
|
||||
bool operator!=(watched const & w) const { return !operator==(w); }
|
||||
};
|
||||
|
||||
COMPILE_TIME_ASSERT(0 <= watched::BINARY && watched::BINARY <= 3);
|
||||
COMPILE_TIME_ASSERT(0 <= watched::TERNARY && watched::TERNARY <= 3);
|
||||
COMPILE_TIME_ASSERT(0 <= watched::CLAUSE && watched::CLAUSE <= 3);
|
||||
COMPILE_TIME_ASSERT(0 <= watched::EXT_CONSTRAINT && watched::EXT_CONSTRAINT <= 3);
|
||||
|
||||
struct watched_lt {
|
||||
bool operator()(watched const & w1, watched const & w2) const {
|
||||
if (w2.is_binary_clause()) return false;
|
||||
if (w1.is_binary_clause()) return true;
|
||||
if (w2.is_ternary_clause()) return false;
|
||||
if (w1.is_ternary_clause()) return true;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
typedef vector<watched> watch_list;
|
||||
|
||||
bool erase_clause_watch(watch_list & wlist, clause_offset c);
|
||||
inline void erase_ternary_watch(watch_list & wlist, literal l1, literal l2) { wlist.erase(watched(l1, l2)); }
|
||||
|
||||
class clause_allocator;
|
||||
void display(std::ostream & out, clause_allocator const & ca, watch_list const & wlist);
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Add table
Add a link
Reference in a new issue