3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-08-15 23:35:26 +00:00

bool watch: order by search index instead of decision level

This commit is contained in:
Jakob Rath 2023-03-16 16:50:09 +01:00
parent 9af86f2d68
commit a6771eb567
4 changed files with 14 additions and 9 deletions

View file

@ -12,6 +12,7 @@ Author:
--*/ --*/
#include "math/polysat/boolean.h" #include "math/polysat/boolean.h"
#include "math/polysat/clause.h" #include "math/polysat/clause.h"
#include "math/polysat/solver.h"
#include "math/polysat/log.h" #include "math/polysat/log.h"
namespace polysat { namespace polysat {
@ -131,14 +132,14 @@ namespace polysat {
} }
/** /**
* A literal may be watched if there is no unwatched literal at higher level, * A literal may be watched if there is no unwatched literal that has been assigned later,
* where true and unassigned literals are considered at infinite level. * where true and unassigned literals are considered at infinite level.
* We prefer true literals to unassigned literals. * We prefer true literals to unassigned literals.
*/ */
uint64_t bool_var_manager::get_watch_level(sat::literal lit) const { uint64_t bool_var_manager::get_watch_level(sat::literal lit) const {
switch (value(lit)) { switch (value(lit)) {
case l_false: case l_false:
return level(lit); return s.m_search.get_bool_index(lit);
case l_true: case l_true:
return std::numeric_limits<uint64_t>::max(); return std::numeric_limits<uint64_t>::max();
case l_undef: case l_undef:

View file

@ -15,6 +15,8 @@ Author:
namespace polysat { namespace polysat {
class solver;
class bool_var_manager { class bool_var_manager {
enum class kind_t { enum class kind_t {
@ -28,6 +30,7 @@ namespace polysat {
evaluation, evaluation,
}; };
solver& s;
svector<sat::bool_var> m_unused; // previously deleted variables that can be reused by new_var(); svector<sat::bool_var> m_unused; // previously deleted variables that can be reused by new_var();
svector<lbool> m_value; // current value (indexed by literal) svector<lbool> m_value; // current value (indexed by literal)
unsigned_vector m_level; // level of assignment (indexed by variable) unsigned_vector m_level; // level of assignment (indexed by variable)
@ -41,7 +44,7 @@ namespace polysat {
bool invariant(sat::literal lit) const { return invariant(lit.var()); } bool invariant(sat::literal lit) const { return invariant(lit.var()); }
public: public:
bool_var_manager() {} bool_var_manager(solver& s): s(s) {}
// allocated size (not the number of active variables) // allocated size (not the number of active variables)
unsigned size() const { return m_level.size(); } unsigned size() const { return m_level.size(); }

View file

@ -42,7 +42,7 @@ namespace polysat {
m_simplify_clause(*this), m_simplify_clause(*this),
m_simplify(*this), m_simplify(*this),
m_restart(*this), m_restart(*this),
m_bvars(), m_bvars(*this),
m_free_pvars(m_activity), m_free_pvars(m_activity),
m_constraints(*this), m_constraints(*this),
m_search(*this) { m_search(*this) {
@ -499,7 +499,7 @@ namespace polysat {
// - false literal, propagated at higher level than lit // - false literal, propagated at higher level than lit
// (may happen if a clause has been generated that propagated lit at a lower than current level) // (may happen if a clause has been generated that propagated lit at a lower than current level)
unsigned i = cl.size(); unsigned i = cl.size();
uint64_t i_lvl = m_bvars.level(lit); uint64_t i_lvl = m_bvars.get_watch_level(~lit);
for (unsigned j = 2; j < cl.size(); ++j) { for (unsigned j = 2; j < cl.size(); ++j) {
uint64_t j_lvl = m_bvars.get_watch_level(cl[j]); uint64_t j_lvl = m_bvars.get_watch_level(cl[j]);
if (i_lvl < j_lvl) { if (i_lvl < j_lvl) {
@ -1794,10 +1794,10 @@ namespace polysat {
} }
// Check watch literal invariant for long clauses: // Check watch literal invariant for long clauses:
// - true literals may always be watched // - true literals may always be watched
// - if at least one true literal is watched, the clause is fine // - if at least one true literal is watched, the clause is fine ... (or at least, we cannot detect violations because we do not update watches after a true literal is watched)
// - otherwise, a literal may only be watched if there is no unwatched literal at higher level. // - otherwise, a literal may only be watched if there is no unwatched literal at higher search-queue-index.
auto const get_watch_level = [&](sat::literal lit) -> unsigned { auto const get_watch_level = [&](sat::literal lit) -> unsigned {
return m_bvars.is_false(lit) ? m_bvars.level(lit) : UINT_MAX; return m_bvars.is_false(lit) ? m_search.get_bool_index(lit) : UINT_MAX;
}; };
for (clause const& cl : m_constraints.clauses()) { for (clause const& cl : m_constraints.clauses()) {
if (cl.size() <= 2) if (cl.size() <= 2)
@ -1813,7 +1813,7 @@ namespace polysat {
for (unsigned i = 2; i < cl.size(); ++i) for (unsigned i = 2; i < cl.size(); ++i)
lvl_tail = std::max(lvl_tail, get_watch_level(cl[i])); lvl_tail = std::max(lvl_tail, get_watch_level(cl[i]));
if (lvl_cl0 < lvl_tail || lvl_cl1 < lvl_tail) { if (lvl_cl0 < lvl_tail || lvl_cl1 < lvl_tail) {
verbose_stream() << "Broken constraint on levels of watched literals of clause: " << cl << "\n"; verbose_stream() << "Broken constraint on index of watched literals of clause: " << cl << "\n";
for (sat::literal lit : cl) { for (sat::literal lit : cl) {
verbose_stream() << " " << lit_pp(*this, lit); verbose_stream() << " " << lit_pp(*this, lit);
if (count(m_bvars.watch(lit), &cl) != 0) if (count(m_bvars.watch(lit), &cl) != 0)

View file

@ -106,6 +106,7 @@ namespace polysat {
// TODO: Why so many friends? Can't we just make the relevant functions public? // TODO: Why so many friends? Can't we just make the relevant functions public?
friend class assignment; friend class assignment;
friend class bool_var_manager;
friend class constraint; friend class constraint;
friend class ule_constraint; friend class ule_constraint;
friend class umul_ovfl_constraint; friend class umul_ovfl_constraint;