mirror of
https://github.com/Z3Prover/z3
synced 2025-04-24 01:25:31 +00:00
use clause structure for nary
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
a0cd6e0fca
commit
8b32c15ac9
4 changed files with 455 additions and 18 deletions
|
@ -98,7 +98,7 @@ namespace sat {
|
|||
// apply substitution
|
||||
for (i = 0; i < sz; i++) {
|
||||
c[i] = norm(roots, c[i]);
|
||||
SASSERT(!m_solver.was_eliminated(c[i].var()));
|
||||
VERIFY(!m_solver.was_eliminated(c[i].var()));
|
||||
}
|
||||
std::sort(c.begin(), c.end());
|
||||
for (literal l : c) VERIFY(l == norm(roots, l));
|
||||
|
|
|
@ -312,10 +312,11 @@ namespace sat {
|
|||
}
|
||||
|
||||
bool lookahead::is_unsat() const {
|
||||
bool all_false = true;
|
||||
bool first = true;
|
||||
// check if there is a clause whose literals are false.
|
||||
// every clause is terminated by a null-literal.
|
||||
#if OLD_NARY
|
||||
bool all_false = true;
|
||||
bool first = true;
|
||||
for (unsigned l_idx : m_nary_literals) {
|
||||
literal l = to_literal(l_idx);
|
||||
if (first) {
|
||||
|
@ -332,6 +333,15 @@ namespace sat {
|
|||
all_false &= is_false(l);
|
||||
}
|
||||
}
|
||||
#else
|
||||
for (nary* n : m_nary_clauses) {
|
||||
bool all_false = true;
|
||||
for (literal l : *n) {
|
||||
all_false &= is_false(l);
|
||||
}
|
||||
if (all_false) return true;
|
||||
}
|
||||
#endif
|
||||
// check if there is a ternary whose literals are false.
|
||||
for (unsigned idx = 0; idx < m_ternary.size(); ++idx) {
|
||||
literal lit = to_literal(idx);
|
||||
|
@ -366,10 +376,11 @@ namespace sat {
|
|||
}
|
||||
}
|
||||
}
|
||||
bool no_true = true;
|
||||
bool first = true;
|
||||
// check if there is a clause whose literals are false.
|
||||
// every clause is terminated by a null-literal.
|
||||
#if OLD_NARY
|
||||
bool no_true = true;
|
||||
bool first = true;
|
||||
for (unsigned l_idx : m_nary_literals) {
|
||||
literal l = to_literal(l_idx);
|
||||
if (first) {
|
||||
|
@ -385,6 +396,15 @@ namespace sat {
|
|||
no_true &= !is_true(l);
|
||||
}
|
||||
}
|
||||
#else
|
||||
for (nary * n : m_nary_clauses) {
|
||||
bool no_true = true;
|
||||
for (literal l : *n) {
|
||||
no_true &= !is_true(l);
|
||||
}
|
||||
if (no_true) return false;
|
||||
}
|
||||
#endif
|
||||
// check if there is a ternary whose literals are false.
|
||||
for (unsigned idx = 0; idx < m_ternary.size(); ++idx) {
|
||||
literal lit = to_literal(idx);
|
||||
|
@ -457,6 +477,7 @@ namespace sat {
|
|||
sum += (literal_occs(b.m_u) + literal_occs(b.m_v)) / 8.0;
|
||||
}
|
||||
sz = m_nary_count[(~l).index()];
|
||||
#if OLD_NARY
|
||||
for (unsigned idx : m_nary[(~l).index()]) {
|
||||
if (sz-- == 0) break;
|
||||
literal lit;
|
||||
|
@ -470,6 +491,9 @@ namespace sat {
|
|||
unsigned len = m_nary_literals[idx];
|
||||
sum += pow(0.5, len) * to_add / len;
|
||||
}
|
||||
#else
|
||||
|
||||
#endif
|
||||
return sum;
|
||||
}
|
||||
|
||||
|
@ -488,10 +512,17 @@ namespace sat {
|
|||
}
|
||||
sum += 0.25 * m_ternary_count[(~l).index()];
|
||||
unsigned sz = m_nary_count[(~l).index()];
|
||||
#if OLD_NARY
|
||||
for (unsigned cls_idx : m_nary[(~l).index()]) {
|
||||
if (sz-- == 0) break;
|
||||
sum += pow(0.5, m_nary_literals[cls_idx]);
|
||||
}
|
||||
#else
|
||||
for (nary * n : m_nary[(~l).index()]) {
|
||||
if (sz-- == 0) break;
|
||||
sum += pow(0.5, n->size());
|
||||
}
|
||||
#endif
|
||||
return sum;
|
||||
}
|
||||
|
||||
|
@ -866,8 +897,13 @@ namespace sat {
|
|||
m_ternary.push_back(svector<binary>());
|
||||
m_ternary_count.push_back(0);
|
||||
m_ternary_count.push_back(0);
|
||||
#if OLD_NARY
|
||||
m_nary.push_back(unsigned_vector());
|
||||
m_nary.push_back(unsigned_vector());
|
||||
#else
|
||||
m_nary.push_back(ptr_vector<nary>());
|
||||
m_nary.push_back(ptr_vector<nary>());
|
||||
#endif
|
||||
m_nary_count.push_back(0);
|
||||
m_nary_count.push_back(0);
|
||||
m_bstamp.push_back(0);
|
||||
|
@ -1254,8 +1290,10 @@ namespace sat {
|
|||
// new n-ary clause managment
|
||||
|
||||
void lookahead::add_clause(clause const& c) {
|
||||
SASSERT(c.size() > 3);
|
||||
|
||||
#if OLD_NARY
|
||||
unsigned sz = c.size();
|
||||
SASSERT(sz > 3);
|
||||
unsigned idx = m_nary_literals.size();
|
||||
m_nary_literals.push_back(sz);
|
||||
for (literal l : c) {
|
||||
|
@ -1264,7 +1302,15 @@ namespace sat {
|
|||
m_nary[l.index()].push_back(idx);
|
||||
SASSERT(m_nary_count[l.index()] == m_nary[l.index()].size());
|
||||
}
|
||||
m_nary_literals.push_back(null_literal.index());
|
||||
m_nary_literals.push_back(null_literal.index());
|
||||
#else
|
||||
void * mem = m_allocator.allocate(nary::get_obj_size(c.size()));
|
||||
nary * n = new (mem) nary(c.size(), c.begin());
|
||||
m_nary_clauses.push_back(n);
|
||||
for (literal l : c) {
|
||||
m_nary[l.index()].push_back(n);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -1274,6 +1320,7 @@ namespace sat {
|
|||
literal lit;
|
||||
SASSERT(m_search_mode == lookahead_mode::searching);
|
||||
|
||||
#if OLD_NARY
|
||||
for (unsigned idx : m_nary[(~l).index()]) {
|
||||
if (sz-- == 0) break;
|
||||
unsigned len = --m_nary_literals[idx];
|
||||
|
@ -1323,12 +1370,69 @@ namespace sat {
|
|||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
for (nary * n : m_nary[(~l).index()]) {
|
||||
if (sz-- == 0) break;
|
||||
unsigned len = n->dec_size();
|
||||
if (m_inconsistent) continue;
|
||||
if (len <= 1) continue; // already processed
|
||||
// find the two unassigned literals, if any
|
||||
if (len == 2) {
|
||||
literal l1 = null_literal;
|
||||
literal l2 = null_literal;
|
||||
bool found_true = false;
|
||||
for (literal lit : *n) {
|
||||
if (!is_fixed(lit)) {
|
||||
if (l1 == null_literal) {
|
||||
l1 = lit;
|
||||
}
|
||||
else {
|
||||
SASSERT(l2 == null_literal);
|
||||
l2 = lit;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (is_true(lit)) {
|
||||
n->set_head(lit);
|
||||
found_true = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found_true) {
|
||||
// skip, the clause will be removed when propagating on 'lit'
|
||||
}
|
||||
else if (l1 == null_literal) {
|
||||
set_conflict();
|
||||
}
|
||||
else if (l2 == null_literal) {
|
||||
// clause may get revisited during propagation, when l2 is true in this clause.
|
||||
// m_removed_clauses.push_back(std::make_pair(~l, idx));
|
||||
// remove_clause_at(~l, idx);
|
||||
propagated(l1);
|
||||
}
|
||||
else {
|
||||
// extract binary clause. A unary or empty clause may get revisited,
|
||||
// but we skip it then because it is already handled as a binary clause.
|
||||
// m_removed_clauses.push_back(std::make_pair(~l, idx)); // need to restore this clause.
|
||||
// remove_clause_at(~l, idx);
|
||||
try_add_binary(l1, l2);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// clauses where l is positive:
|
||||
sz = m_nary_count[l.index()];
|
||||
#if OLD_NARY
|
||||
for (unsigned idx : m_nary[l.index()]) {
|
||||
if (sz-- == 0) break;
|
||||
remove_clause_at(l, idx);
|
||||
}
|
||||
#else
|
||||
for (nary* n : m_nary[l.index()]) {
|
||||
if (sz-- == 0) break;
|
||||
remove_clause_at(l, *n);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void lookahead::propagate_clauses_lookahead(literal l) {
|
||||
|
@ -1338,6 +1442,7 @@ namespace sat {
|
|||
SASSERT(m_search_mode == lookahead_mode::lookahead1 ||
|
||||
m_search_mode == lookahead_mode::lookahead2);
|
||||
|
||||
#if OLD_NARY
|
||||
for (unsigned idx : m_nary[(~l).index()]) {
|
||||
if (sz-- == 0) break;
|
||||
literal l1 = null_literal;
|
||||
|
@ -1404,9 +1509,75 @@ namespace sat {
|
|||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
for (nary* n : m_nary[(~l).index()]) {
|
||||
if (sz-- == 0) break;
|
||||
literal l1 = null_literal;
|
||||
literal l2 = null_literal;
|
||||
bool found_true = false;
|
||||
unsigned nonfixed = 0;
|
||||
for (literal lit : *n) {
|
||||
if (!is_fixed(lit)) {
|
||||
++nonfixed;
|
||||
if (l1 == null_literal) {
|
||||
l1 = lit;
|
||||
}
|
||||
else if (l2 == null_literal) {
|
||||
l2 = lit;
|
||||
}
|
||||
}
|
||||
else if (is_true(lit)) {
|
||||
found_true = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found_true) {
|
||||
// skip, the clause will be removed when propagating on 'lit'
|
||||
}
|
||||
else if (l1 == null_literal) {
|
||||
set_conflict();
|
||||
return;
|
||||
}
|
||||
else if (l2 == null_literal) {
|
||||
propagated(l1);
|
||||
}
|
||||
else if (m_search_mode == lookahead_mode::lookahead2) {
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
SASSERT(nonfixed >= 2);
|
||||
SASSERT(m_search_mode == lookahead_mode::lookahead1);
|
||||
switch (m_config.m_reward_type) {
|
||||
case heule_schur_reward: {
|
||||
double to_add = 0;
|
||||
for (literal lit : *n) {
|
||||
if (!is_fixed(lit)) {
|
||||
to_add += literal_occs(lit);
|
||||
}
|
||||
}
|
||||
m_lookahead_reward += pow(0.5, nonfixed) * to_add / nonfixed;
|
||||
break;
|
||||
}
|
||||
case heule_unit_reward:
|
||||
m_lookahead_reward += pow(0.5, nonfixed);
|
||||
break;
|
||||
case ternary_reward:
|
||||
if (nonfixed == 2) {
|
||||
m_lookahead_reward += (*m_heur)[l1.index()] * (*m_heur)[l2.index()];
|
||||
}
|
||||
else {
|
||||
m_lookahead_reward += (double)0.001;
|
||||
}
|
||||
break;
|
||||
case unit_literal_reward:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if OLD_NARY
|
||||
void lookahead::remove_clause_at(literal l, unsigned clause_idx) {
|
||||
unsigned j = clause_idx;
|
||||
literal lit;
|
||||
|
@ -1429,21 +1600,50 @@ namespace sat {
|
|||
}
|
||||
UNREACHABLE();
|
||||
}
|
||||
#else
|
||||
|
||||
void lookahead::remove_clause_at(literal l, nary& n) {
|
||||
for (literal lit : n) {
|
||||
if (lit != l) {
|
||||
remove_clause(lit, n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void lookahead::remove_clause(literal l, nary& n) {
|
||||
ptr_vector<nary>& pclauses = m_nary[l.index()];
|
||||
unsigned sz = m_nary_count[l.index()]--;
|
||||
for (unsigned i = sz; i > 0; ) {
|
||||
--i;
|
||||
if (&n == pclauses[i]) {
|
||||
std::swap(pclauses[i], pclauses[sz-1]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
UNREACHABLE();
|
||||
}
|
||||
#endif
|
||||
|
||||
void lookahead::restore_clauses(literal l) {
|
||||
SASSERT(m_search_mode == lookahead_mode::searching);
|
||||
|
||||
// increase the length of clauses where l is negative
|
||||
unsigned sz = m_nary_count[(~l).index()];
|
||||
#if OLD_NARY
|
||||
for (unsigned idx : m_nary[(~l).index()]) {
|
||||
if (sz-- == 0) break;
|
||||
++m_nary_literals[idx];
|
||||
}
|
||||
|
||||
#else
|
||||
for (nary* n : m_nary[(~l).index()]) {
|
||||
if (sz-- == 0) break;
|
||||
n->inc_size();
|
||||
}
|
||||
#endif
|
||||
// add idx back to clause list where l is positive
|
||||
// add them back in the same order as they were inserted
|
||||
// in this way we can check that the clauses are the same.
|
||||
sz = m_nary_count[l.index()];
|
||||
#if OLD_NARY
|
||||
unsigned_vector const& pclauses = m_nary[l.index()];
|
||||
for (unsigned i = sz; i > 0; ) {
|
||||
--i;
|
||||
|
@ -1456,6 +1656,17 @@ namespace sat {
|
|||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
ptr_vector<nary>& pclauses = m_nary[l.index()];
|
||||
for (unsigned i = sz; i-- > 0; ) {
|
||||
for (literal lit : *pclauses[i]) {
|
||||
if (lit != l) {
|
||||
// SASSERT(m_nary[lit.index()] == pclauses[i]);
|
||||
m_nary_count[lit.index()]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void lookahead::propagate_clauses(literal l) {
|
||||
|
@ -1527,7 +1738,7 @@ namespace sat {
|
|||
// Sum_{ clause C that contains ~l } 1
|
||||
double lookahead::literal_occs(literal l) {
|
||||
double result = m_binary[l.index()].size();
|
||||
unsigned_vector const& nclauses = m_nary[(~l).index()];
|
||||
// unsigned_vector const& nclauses = m_nary[(~l).index()];
|
||||
result += m_nary_count[(~l).index()];
|
||||
result += m_ternary_count[(~l).index()];
|
||||
return result;
|
||||
|
@ -1684,7 +1895,7 @@ namespace sat {
|
|||
return false;
|
||||
#if 0
|
||||
// no propagations are allowed to reduce clauses.
|
||||
for (clause * cp : m_full_watches[l.index()]) {
|
||||
for (nary * cp : m_nary[(~l).index()]) {
|
||||
clause& c = *cp;
|
||||
unsigned sz = c.size();
|
||||
bool found = false;
|
||||
|
@ -2026,6 +2237,7 @@ namespace sat {
|
|||
}
|
||||
}
|
||||
|
||||
#if OLD_NARY
|
||||
for (unsigned l_idx : m_nary_literals) {
|
||||
literal l = to_literal(l_idx);
|
||||
if (first) {
|
||||
|
@ -2041,6 +2253,12 @@ namespace sat {
|
|||
out << l << " ";
|
||||
}
|
||||
}
|
||||
#else
|
||||
for (nary * n : m_nary_clauses) {
|
||||
for (literal l : *n) out << l << " ";
|
||||
out << "\n";
|
||||
}
|
||||
#endif
|
||||
|
||||
return out;
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ Notes:
|
|||
#ifndef _SAT_LOOKAHEAD_H_
|
||||
#define _SAT_LOOKAHEAD_H_
|
||||
|
||||
#define OLD_NARY 0
|
||||
|
||||
#include "sat_elim_eqs.h"
|
||||
|
||||
|
@ -129,6 +130,36 @@ namespace sat {
|
|||
literal m_u, m_v;
|
||||
};
|
||||
|
||||
class nary {
|
||||
unsigned m_size; // number of non-false literals
|
||||
size_t m_obj_size; // object size (counting all literals)
|
||||
literal m_head; // head literal
|
||||
literal m_literals[0]; // list of literals, put any true literal in head.
|
||||
size_t num_lits() const {
|
||||
return (m_obj_size - sizeof(nary)) / sizeof(literal);
|
||||
}
|
||||
public:
|
||||
static size_t get_obj_size(unsigned sz) { return sizeof(nary) + sz * sizeof(literal); }
|
||||
size_t obj_size() const { return m_obj_size; }
|
||||
nary(unsigned sz, literal const* lits):
|
||||
m_size(sz),
|
||||
m_obj_size(get_obj_size(sz)) {
|
||||
for (unsigned i = 0; i < sz; ++i) m_literals[i] = lits[i];
|
||||
m_head = lits[0];
|
||||
}
|
||||
unsigned size() const { return m_size; }
|
||||
unsigned dec_size() { SASSERT(m_size > 0); return --m_size; }
|
||||
void inc_size() { SASSERT(m_size < num_lits()); ++m_size; }
|
||||
literal get_head() const { return m_head; }
|
||||
void set_head(literal l) { m_head = l; }
|
||||
|
||||
literal operator[](unsigned i) { SASSERT(i < num_lits()); return m_literals[i]; }
|
||||
literal const* begin() const { return m_literals; }
|
||||
literal const* end() const { return m_literals + num_lits(); }
|
||||
// swap the true literal to the head.
|
||||
// void swap(unsigned i, unsigned j) { SASSERT(i < num_lits() && j < num_lits()); std::swap(m_literals[i], m_literals[j]); }
|
||||
};
|
||||
|
||||
struct cube_state {
|
||||
bool m_first;
|
||||
svector<bool> m_is_decision;
|
||||
|
@ -160,11 +191,18 @@ namespace sat {
|
|||
vector<svector<binary>> m_ternary; // lit |-> vector of ternary clauses
|
||||
unsigned_vector m_ternary_count; // lit |-> current number of active ternary clauses for lit
|
||||
|
||||
#if OLD_NARY
|
||||
vector<unsigned_vector> m_nary; // lit |-> vector of clause_id
|
||||
unsigned_vector m_nary_count; // lit |-> number of valid clause_id in m_clauses2[lit]
|
||||
unsigned_vector m_nary_literals; // the actual literals, clauses start at offset clause_id,
|
||||
// the first entry is the current length, clauses are separated by a null_literal
|
||||
|
||||
#else
|
||||
small_object_allocator m_allocator;
|
||||
vector<ptr_vector<nary>> m_nary; // lit |-> vector of nary clauses
|
||||
ptr_vector<nary> m_nary_clauses; // vector of all nary clauses
|
||||
#endif
|
||||
unsigned_vector m_nary_count; // lit |-> number of valid clause_id in m_nary[lit]
|
||||
|
||||
unsigned m_num_tc1;
|
||||
unsigned_vector m_num_tc1_lim;
|
||||
unsigned m_qhead; // propagation queue head
|
||||
|
@ -410,15 +448,20 @@ namespace sat {
|
|||
void propagate_clauses_searching(literal l);
|
||||
void propagate_clauses_lookahead(literal l);
|
||||
void restore_clauses(literal l);
|
||||
#if OLD_NARY
|
||||
void remove_clause(literal l, unsigned clause_idx);
|
||||
void remove_clause_at(literal l, unsigned clause_idx);
|
||||
|
||||
#else
|
||||
void remove_clause(literal l, nary& n);
|
||||
void remove_clause_at(literal l, nary& n);
|
||||
#endif
|
||||
// ------------------------------------
|
||||
// initialization
|
||||
|
||||
void init_var(bool_var v);
|
||||
void init();
|
||||
void copy_clauses(clause_vector const& clauses, bool learned);
|
||||
nary * copy_clause(clause const& c);
|
||||
|
||||
// ------------------------------------
|
||||
// search
|
||||
|
@ -499,6 +542,12 @@ namespace sat {
|
|||
|
||||
~lookahead() {
|
||||
m_s.rlimit().pop_child();
|
||||
#if OLD_NARY
|
||||
#else
|
||||
for (nary* n : m_nary_clauses) {
|
||||
m_allocator.deallocate(n->obj_size(), n);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue