mirror of
https://github.com/Z3Prover/z3
synced 2025-08-02 17:30:23 +00:00
Removing ternary clause optimization from sat_solver simplifies special case handling of ternary clauses throughout the sat solver and dependent solvers (pb_solver). Benchmarking on QF_BV suggests the ternary clause optimization does not have any effect. While removing ternary clause optimization two bugs in unit propagation were also uncovered: it missed propagations when the only a single undef literal remained in the non-watched literals and it did not update blocked literals in cases where it could in the watch list. These performance bugs were for general clauses, ternary clause propagation did not miss propagations (and don't use blocked literals), but fixing these issues for general clauses appear to have made ternary clause optimization irrelevant based on what was measured.
129 lines
4.8 KiB
C++
129 lines
4.8 KiB
C++
/*++
|
|
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:
|
|
|
|
--*/
|
|
#pragma once
|
|
|
|
#include "sat/sat_types.h"
|
|
#include "util/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 are no clause objects for binary clauses.
|
|
*/
|
|
|
|
class extension;
|
|
|
|
class watched {
|
|
public:
|
|
enum kind {
|
|
BINARY = 0, CLAUSE, EXT_CONSTRAINT
|
|
};
|
|
private:
|
|
size_t 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());
|
|
}
|
|
|
|
|
|
unsigned val2() const { return m_val2; }
|
|
|
|
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);
|
|
}
|
|
|
|
explicit 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(static_cast<unsigned>(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) == 1; }
|
|
|
|
bool is_binary_learned_clause() const { return is_binary_clause() && is_learned(); }
|
|
bool is_binary_non_learned_clause() const { return is_binary_clause() && !is_learned(); }
|
|
|
|
void set_learned(bool l) { if (l) m_val2 |= 4u; else m_val2 &= ~4u; SASSERT(is_learned() == l); }
|
|
|
|
|
|
bool is_clause() const { return get_kind() == CLAUSE; }
|
|
clause_offset get_clause_offset() const { SASSERT(is_clause()); return static_cast<clause_offset>(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_val1; }
|
|
|
|
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); }
|
|
};
|
|
|
|
static_assert(0 <= watched::BINARY && watched::BINARY <= 2, "");
|
|
static_assert(0 <= watched::CLAUSE && watched::CLAUSE <= 2, "");
|
|
static_assert(0 <= watched::EXT_CONSTRAINT && watched::EXT_CONSTRAINT <= 2, "");
|
|
|
|
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;
|
|
return false;
|
|
}
|
|
};
|
|
|
|
typedef vector<watched> watch_list;
|
|
|
|
watched* find_binary_watch(watch_list & wlist, literal l);
|
|
watched const* find_binary_watch(watch_list const & wlist, literal l);
|
|
bool erase_clause_watch(watch_list & wlist, clause_offset c);
|
|
|
|
class clause_allocator;
|
|
std::ostream& display_watch_list(std::ostream & out, clause_allocator const & ca, watch_list const & wlist, extension* ext);
|
|
|
|
void conflict_cleanup(watch_list::iterator it, watch_list::iterator it2, watch_list& wlist);
|
|
};
|
|
|