mirror of
https://github.com/Z3Prover/z3
synced 2025-04-23 09:05:31 +00:00
Bring back boolean decisions (wip)
The backtracking code doesn't know about boolean decisions yet
This commit is contained in:
parent
811843cf45
commit
3d27ec41d0
7 changed files with 132 additions and 27 deletions
|
@ -60,6 +60,11 @@ namespace polysat {
|
|||
// m_unused.push_back(var);
|
||||
}
|
||||
|
||||
bool bool_var_manager::invariant(sat::bool_var var) const {
|
||||
SASSERT_EQ(value(var) == l_undef, m_kind[var] == kind_t::unassigned);
|
||||
return true;
|
||||
}
|
||||
|
||||
void bool_var_manager::propagate(sat::literal lit, unsigned lvl, clause& reason) {
|
||||
LOG("Propagate literal " << lit << " @ " << lvl << " by " << reason);
|
||||
assign(kind_t::bool_propagation, lit, lvl, &reason);
|
||||
|
@ -78,6 +83,12 @@ namespace polysat {
|
|||
SASSERT(is_assumption(lit));
|
||||
}
|
||||
|
||||
void bool_var_manager::decision(sat::literal lit, unsigned lvl) {
|
||||
LOG("Decided " << lit << " @ " << lvl);
|
||||
assign(kind_t::decision, lit, lvl, nullptr);
|
||||
SASSERT(is_decision(lit));
|
||||
}
|
||||
|
||||
void bool_var_manager::assign(kind_t k, sat::literal lit, unsigned lvl, clause* reason, dependency dep) {
|
||||
SASSERT(!is_assigned(lit));
|
||||
SASSERT(k != kind_t::unassigned);
|
||||
|
|
|
@ -25,6 +25,7 @@ namespace polysat {
|
|||
bool_propagation,
|
||||
value_propagation,
|
||||
assumption,
|
||||
decision,
|
||||
};
|
||||
|
||||
svector<sat::bool_var> m_unused; // previously deleted variables that can be reused by new_var();
|
||||
|
@ -36,6 +37,8 @@ namespace polysat {
|
|||
vector<ptr_vector<clause>> m_watch; // watch list for literals into clauses
|
||||
|
||||
void assign(kind_t k, sat::literal lit, unsigned lvl, clause* reason, dependency dep = null_dependency);
|
||||
bool invariant(sat::bool_var var) const;
|
||||
bool invariant(sat::literal lit) const { return invariant(lit.var()); }
|
||||
|
||||
public:
|
||||
bool_var_manager() {}
|
||||
|
@ -46,13 +49,15 @@ namespace polysat {
|
|||
sat::bool_var new_var();
|
||||
void del_var(sat::bool_var var);
|
||||
|
||||
bool is_assigned(sat::bool_var var) const { return value(var) != l_undef; }
|
||||
bool is_assigned(sat::literal lit) const { return value(lit) != l_undef; }
|
||||
bool is_assumption(sat::bool_var var) const { return is_assigned(var) && m_kind[var] == kind_t::assumption; }
|
||||
bool is_assigned(sat::bool_var var) const { SASSERT(invariant(var)); return value(var) != l_undef; }
|
||||
bool is_assigned(sat::literal lit) const { SASSERT(invariant(lit)); return value(lit) != l_undef; }
|
||||
bool is_assumption(sat::bool_var var) const { SASSERT(invariant(var)); return m_kind[var] == kind_t::assumption; }
|
||||
bool is_assumption(sat::literal lit) const { return is_assumption(lit.var()); }
|
||||
bool is_bool_propagation(sat::bool_var var) const { return is_assigned(var) && m_kind[var] == kind_t::bool_propagation; }
|
||||
bool is_decision(sat::bool_var var) const { SASSERT(invariant(var)); return m_kind[var] == kind_t::decision; }
|
||||
bool is_decision(sat::literal lit) const { return is_decision(lit.var()); }
|
||||
bool is_bool_propagation(sat::bool_var var) const { SASSERT(invariant(var)); return m_kind[var] == kind_t::bool_propagation; }
|
||||
bool is_bool_propagation(sat::literal lit) const { return is_bool_propagation(lit.var()); }
|
||||
bool is_value_propagation(sat::bool_var var) const { return is_assigned(var) && m_kind[var] == kind_t::value_propagation; }
|
||||
bool is_value_propagation(sat::bool_var var) const { SASSERT(invariant(var)); return m_kind[var] == kind_t::value_propagation; }
|
||||
bool is_value_propagation(sat::literal lit) const { return is_value_propagation(lit.var()); }
|
||||
lbool value(sat::bool_var var) const { return value(sat::literal(var)); }
|
||||
lbool value(sat::literal lit) const { return m_value[lit.index()]; }
|
||||
|
@ -70,6 +75,8 @@ namespace polysat {
|
|||
void propagate(sat::literal lit, unsigned lvl, clause& reason);
|
||||
void eval(sat::literal lit, unsigned lvl);
|
||||
void assumption(sat::literal lit, unsigned lvl, dependency dep);
|
||||
void decision(sat::literal lit, unsigned lvl);
|
||||
|
||||
void unassign(sat::literal lit);
|
||||
|
||||
std::ostream& display(std::ostream& out) const;
|
||||
|
@ -81,8 +88,10 @@ namespace polysat {
|
|||
case kind_t::bool_propagation: return out << "bool propagation";
|
||||
case kind_t::value_propagation: return out << "value propagation";
|
||||
case kind_t::assumption: return out << "assumption";
|
||||
default: UNREACHABLE(); return out;
|
||||
case kind_t::decision: return out << "decision";
|
||||
}
|
||||
UNREACHABLE();
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -17,11 +17,10 @@ Author:
|
|||
--*/
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <ostream>
|
||||
#include <sstream>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include "util/ref.h"
|
||||
#include "util/util.h"
|
||||
|
||||
template <typename T>
|
||||
struct show_deref_t {
|
||||
|
@ -29,11 +28,11 @@ struct show_deref_t {
|
|||
};
|
||||
|
||||
template <typename T>
|
||||
std::ostream& operator<<(std::ostream& os, show_deref_t<T> s) {
|
||||
std::ostream& operator<<(std::ostream& out, show_deref_t<T> s) {
|
||||
if (s.ptr)
|
||||
return os << *s.ptr;
|
||||
return out << *s.ptr;
|
||||
else
|
||||
return os << "<null>";
|
||||
return out << "<null>";
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
|
|
@ -50,10 +50,13 @@ namespace polysat {
|
|||
out << "\n\t" << rpad(4, l2) << ": " << rpad(16, s.lit2cnstr(l2)) << " " << bool_justification_pp(s.m_bvars, l2);
|
||||
}
|
||||
}
|
||||
else {
|
||||
SASSERT(s.m_bvars.is_value_propagation(lit));
|
||||
else if (s.m_bvars.is_value_propagation(lit)) {
|
||||
out << " evaluated";
|
||||
}
|
||||
else {
|
||||
SASSERT(s.m_bvars.is_decision(lit));
|
||||
out << " decision";
|
||||
}
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -495,6 +495,10 @@ namespace polysat {
|
|||
pop_qhead();
|
||||
break;
|
||||
}
|
||||
case trail_instr_t::lemma_qhead_i: {
|
||||
m_lemmas_qhead--;
|
||||
break;
|
||||
}
|
||||
case trail_instr_t::pwatch_i: {
|
||||
constraint* c = m_pwatch_trail.back();
|
||||
erase_pwatch(c);
|
||||
|
@ -561,10 +565,70 @@ namespace polysat {
|
|||
}
|
||||
}
|
||||
|
||||
bool solver::can_decide() const {
|
||||
return can_pdecide() || can_bdecide();
|
||||
}
|
||||
|
||||
bool solver::can_pdecide() const {
|
||||
return !m_free_pvars.empty();
|
||||
}
|
||||
|
||||
bool solver::can_bdecide() const {
|
||||
return m_lemmas_qhead < m_lemmas.size();
|
||||
}
|
||||
|
||||
void solver::decide() {
|
||||
LOG_H2("Decide");
|
||||
SASSERT(can_decide());
|
||||
pdecide(m_free_pvars.next_var());
|
||||
SASSERT(can_pdecide()); // if !can_pdecide(), all boolean literals have been propagated...
|
||||
if (can_bdecide())
|
||||
bdecide();
|
||||
else
|
||||
pdecide(m_free_pvars.next_var());
|
||||
}
|
||||
|
||||
/// Basic version of https://en.cppreference.com/w/cpp/experimental/scope_exit
|
||||
template <typename Callable>
|
||||
class on_scope_exit final {
|
||||
Callable m_ef;
|
||||
public:
|
||||
explicit on_scope_exit(Callable&& ef)
|
||||
: m_ef(std::forward<Callable>(ef))
|
||||
{ }
|
||||
~on_scope_exit() {
|
||||
m_ef();
|
||||
}
|
||||
};
|
||||
|
||||
void solver::bdecide() {
|
||||
clause& lemma = *m_lemmas[m_lemmas_qhead++];
|
||||
on_scope_exit update_trail([this]() {
|
||||
// must be done after push_level, but also if we return early.
|
||||
m_trail.push_back(trail_instr_t::lemma_qhead_i);
|
||||
});
|
||||
|
||||
LOG_H2("Decide on non-asserting lemma: " << lemma);
|
||||
sat::literal choice = sat::null_literal;
|
||||
for (sat::literal lit : lemma) {
|
||||
switch (m_bvars.value(lit)) {
|
||||
case l_true:
|
||||
// Clause is satisfied; nothing to do here
|
||||
return;
|
||||
case l_false:
|
||||
break;
|
||||
case l_undef:
|
||||
if (choice == sat::null_literal)
|
||||
choice = lit;
|
||||
break;
|
||||
}
|
||||
}
|
||||
LOG("Choice is " << lit_pp(*this, choice));
|
||||
// SASSERT(2 <= count_if(lemma, [this](sat::literal lit) { return !m_bvars.is_assigned(lit); });
|
||||
SASSERT(choice != sat::null_literal);
|
||||
// TODO: is the case after backtracking correct?
|
||||
// => the backtracking code has to handle this. making sure that the decision literal is set to false.
|
||||
push_level();
|
||||
assign_decision(choice);
|
||||
}
|
||||
|
||||
void solver::pdecide(pvar v) {
|
||||
|
@ -718,7 +782,7 @@ namespace polysat {
|
|||
void solver::backjump_lemma() {
|
||||
clause_ref lemma = m_conflict.build_lemma();
|
||||
LOG_H2("backjump_lemma: " << show_deref(lemma));
|
||||
SASSERT(lemma && lemma_invariant(*lemma));
|
||||
SASSERT(lemma_invariant(lemma.get()));
|
||||
|
||||
// find second-highest level of the literals in the lemma
|
||||
unsigned max_level = 0;
|
||||
|
@ -795,8 +859,15 @@ namespace polysat {
|
|||
LOG("Learning: "<< lemma);
|
||||
SASSERT(!lemma.empty());
|
||||
m_simplify_clause.apply(lemma);
|
||||
// TODO: print warning if the lemma is non-asserting?
|
||||
add_clause(lemma);
|
||||
// At this point, all literals in lemma have been value- or bool-propated, if possible.
|
||||
// So if the lemma is/was asserting, all its literals are now assigned.
|
||||
bool is_asserting = all_of(lemma, [this](sat::literal lit) { return m_bvars.is_assigned(lit); });
|
||||
if (!is_asserting) {
|
||||
LOG("Lemma is not asserting!");
|
||||
m_lemmas.push_back(&lemma);
|
||||
SASSERT(can_bdecide());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -816,7 +887,7 @@ namespace polysat {
|
|||
SASSERT(m_justification[v].is_decision());
|
||||
|
||||
clause_ref lemma = m_conflict.build_lemma();
|
||||
SASSERT(lemma && lemma_invariant(*lemma));
|
||||
SASSERT(lemma_invariant(lemma.get()));
|
||||
|
||||
if (lemma->empty())
|
||||
report_unsat();
|
||||
|
@ -827,9 +898,10 @@ namespace polysat {
|
|||
}
|
||||
}
|
||||
|
||||
bool solver::lemma_invariant(clause const& lemma) {
|
||||
LOG("Lemma: " << lemma);
|
||||
for (sat::literal lit : lemma) {
|
||||
bool solver::lemma_invariant(clause const* lemma) {
|
||||
SASSERT(lemma);
|
||||
LOG("Lemma: " << *lemma);
|
||||
for (sat::literal lit : *lemma) {
|
||||
LOG(" " << lit_pp(*this, lit));
|
||||
SASSERT(m_bvars.value(lit) == l_false || lit2cnstr(lit).is_currently_false(*this));
|
||||
}
|
||||
|
@ -848,6 +920,12 @@ namespace polysat {
|
|||
return lvl;
|
||||
}
|
||||
|
||||
void solver::assign_decision(sat::literal lit) {
|
||||
m_bvars.decision(lit, m_level);
|
||||
m_trail.push_back(trail_instr_t::assign_bool_i);
|
||||
m_search.push_boolean(lit);
|
||||
}
|
||||
|
||||
void solver::assign_propagate(sat::literal lit, clause& reason) {
|
||||
m_bvars.propagate(lit, level(lit, reason), reason);
|
||||
m_trail.push_back(trail_instr_t::assign_bool_i);
|
||||
|
|
|
@ -134,6 +134,9 @@ namespace polysat {
|
|||
unsigned_vector m_qhead_trail;
|
||||
constraints m_pwatch_trail;
|
||||
|
||||
ptr_vector<clause> m_lemmas; ///< the non-asserting lemmas
|
||||
unsigned m_lemmas_qhead = 0;
|
||||
|
||||
unsigned_vector m_base_levels; // External clients can push/pop scope.
|
||||
|
||||
void push_qhead() {
|
||||
|
@ -163,7 +166,7 @@ namespace polysat {
|
|||
void pop_levels(unsigned num_levels);
|
||||
|
||||
void assign_propagate(sat::literal lit, clause& reason);
|
||||
void assign_decision(sat::literal lit, clause& lemma);
|
||||
void assign_decision(sat::literal lit);
|
||||
void assign_eval(sat::literal lit);
|
||||
void activate_constraint(signed_constraint c);
|
||||
void deactivate_constraint(signed_constraint c);
|
||||
|
@ -190,8 +193,11 @@ namespace polysat {
|
|||
void set_conflict(clause& cl) { m_conflict.init(cl); }
|
||||
void set_conflict(pvar v, bool by_viable_fallback) { m_conflict.init(v, by_viable_fallback); }
|
||||
|
||||
bool can_decide() const { return !m_free_pvars.empty(); }
|
||||
bool can_decide() const;
|
||||
bool can_bdecide() const;
|
||||
bool can_pdecide() const;
|
||||
void decide();
|
||||
void bdecide();
|
||||
void pdecide(pvar v);
|
||||
|
||||
void linear_propagate();
|
||||
|
@ -227,7 +233,7 @@ namespace polysat {
|
|||
|
||||
bool invariant();
|
||||
static bool invariant(signed_constraints const& cs);
|
||||
bool lemma_invariant(clause const& lemma);
|
||||
bool lemma_invariant(clause const* lemma);
|
||||
bool wlist_invariant();
|
||||
bool assignment_invariant();
|
||||
bool verify_sat();
|
||||
|
|
|
@ -16,8 +16,9 @@ Author:
|
|||
|
||||
namespace polysat {
|
||||
|
||||
enum class trail_instr_t {
|
||||
enum class trail_instr_t {
|
||||
qhead_i,
|
||||
lemma_qhead_i,
|
||||
pwatch_i,
|
||||
add_var_i,
|
||||
inc_level_i,
|
||||
|
@ -28,6 +29,4 @@ namespace polysat {
|
|||
assign_bool_i
|
||||
};
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue