diff --git a/src/sat/smt/polysat_interval.h b/src/sat/smt/polysat_interval.h deleted file mode 100644 index 9965dbab1..000000000 --- a/src/sat/smt/polysat_interval.h +++ /dev/null @@ -1,224 +0,0 @@ -/*++ -Copyright (c) 2021 Microsoft Corporation - -Module Name: - - polysat intervals - -Author: - - Nikolaj Bjorner (nbjorner) 2021-03-19 - Jakob Rath 2021-04-6 - ---*/ -#pragma once -#include "sat/smt/polysat_types.h" -#include - -namespace polysat { - - struct pdd_bounds { - pdd lo; ///< lower bound, inclusive - pdd hi; ///< upper bound, exclusive - }; - - /** - * An interval is either [lo; hi[ (excl. upper bound) or the full domain Z_{2^w}. - * If lo > hi, the interval wraps around, i.e., represents the union of [lo; 2^w[ and [0; hi[. - * Membership test t \in [lo; hi[ is equivalent to t - lo < hi - lo. - */ - class interval { - std::optional m_bounds = std::nullopt; - - interval() = default; - interval(pdd const& lo, pdd const& hi): m_bounds({lo, hi}) {} - public: - static interval empty(dd::pdd_manager& m) { return proper(m.zero(), m.zero()); } - static interval full() { return {}; } - static interval proper(pdd const& lo, pdd const& hi) { return {lo, hi}; } - - interval(interval const&) = default; - interval(interval&&) = default; - interval& operator=(interval const& other) { - m_bounds = std::nullopt; // clear pdds first to allow changing pdd_manager (probably should change the PDD assignment operator; but for now I want to be able to detect manager confusions) - m_bounds = other.m_bounds; - return *this; - } - interval& operator=(interval&& other) { - m_bounds = std::nullopt; // clear pdds first to allow changing pdd_manager - m_bounds = std::move(other.m_bounds); - return *this; - } - ~interval() = default; - - bool is_full() const { return !m_bounds; } - bool is_proper() const { return !!m_bounds; } - bool is_always_empty() const { return is_proper() && lo() == hi(); } - pdd const& lo() const { SASSERT(is_proper()); return m_bounds->lo; } - pdd const& hi() const { SASSERT(is_proper()); return m_bounds->hi; } - }; - - inline std::ostream& operator<<(std::ostream& os, interval const& i) { - if (i.is_full()) - return os << "full"; - else - return os << "[" << i.lo() << " ; " << i.hi() << "["; - } - - // distance from a to b, wrapping around at mod_value. - // basically mod(b - a, mod_value), but distance(0, mod_value, mod_value) = mod_value. - inline rational distance(rational const& a, rational const& b, rational const& mod_value) { - SASSERT(mod_value.is_power_of_two()); - SASSERT(0 <= a && a < mod_value); - SASSERT(0 <= b && b <= mod_value); - rational x = b - a; - if (x.is_neg()) - x += mod_value; - return x; - } - - class r_interval { - rational m_lo; - rational m_hi; - - r_interval(rational lo, rational hi) - : m_lo(std::move(lo)), m_hi(std::move(hi)) - {} - - public: - - static r_interval empty() { - return {rational::zero(), rational::zero()}; - } - - static r_interval full() { - return {rational(-1), rational::zero()}; - } - - static r_interval proper(rational lo, rational hi) { - SASSERT(0 <= lo); - SASSERT(0 <= hi); - return {std::move(lo), std::move(hi)}; - } - - bool is_full() const { return m_lo.is_neg(); } - bool is_proper() const { return !is_full(); } - bool is_empty() const { return is_proper() && lo() == hi(); } - rational const& lo() const { SASSERT(is_proper()); return m_lo; } - rational const& hi() const { SASSERT(is_proper()); return m_hi; } - - // this one also supports representing full intervals as [lo;mod_value[ - static rational len(rational const& lo, rational const& hi, rational const& mod_value) { - SASSERT(mod_value.is_power_of_two()); - SASSERT(0 <= lo && lo < mod_value); - SASSERT(0 <= hi && hi <= mod_value); - SASSERT(hi != mod_value || lo == 0); // hi == mod_value only allowed when lo == 0 - rational len = hi - lo; - if (len.is_neg()) - len += mod_value; - return len; - } - - rational len(rational const& mod_value) const { - SASSERT(is_proper()); - return len(lo(), hi(), mod_value); - } - - // deals only with proper intervals - // but works with full intervals represented as [0;mod_value[ -- maybe we should just change representation of full intervals to this always - static bool contains(rational const& lo, rational const& hi, rational const& val) { - if (lo <= hi) - return lo <= val && val < hi; - else - return val < hi || val >= lo; - } - - bool contains(rational const& val) const { - if (is_full()) - return true; - else - return contains(lo(), hi(), val); - } - - }; - - class eval_interval { - interval m_symbolic; - rational m_concrete_lo; - rational m_concrete_hi; - - eval_interval(interval&& i, rational const& lo_val, rational const& hi_val): - m_symbolic(std::move(i)), m_concrete_lo(lo_val), m_concrete_hi(hi_val) {} - public: - static eval_interval empty(dd::pdd_manager& m) { - return {interval::empty(m), rational::zero(), rational::zero()}; - } - - static eval_interval full() { - return {interval::full(), rational::zero(), rational::zero()}; - } - - static eval_interval proper(pdd const& lo, rational const& lo_val, pdd const& hi, rational const& hi_val) { - SASSERT(0 <= lo_val && lo_val <= lo.manager().max_value()); - SASSERT(0 <= hi_val && hi_val <= hi.manager().max_value()); - return {interval::proper(lo, hi), lo_val, hi_val}; - } - - bool is_full() const { return m_symbolic.is_full(); } - bool is_proper() const { return m_symbolic.is_proper(); } - bool is_always_empty() const { return m_symbolic.is_always_empty(); } - bool is_currently_empty() const { return is_proper() && lo_val() == hi_val(); } - interval const& symbolic() const { return m_symbolic; } - pdd const& lo() const { return m_symbolic.lo(); } - pdd const& hi() const { return m_symbolic.hi(); } - rational const& lo_val() const { SASSERT(is_proper()); return m_concrete_lo; } - rational const& hi_val() const { SASSERT(is_proper()); return m_concrete_hi; } - - rational current_len() const { - SASSERT(is_proper()); - return mod(hi_val() - lo_val(), lo().manager().two_to_N()); - } - - bool currently_contains(rational const& val) const { - if (is_full()) - return true; - else if (lo_val() <= hi_val()) - return lo_val() <= val && val < hi_val(); - else - return val < hi_val() || val >= lo_val(); - } - - bool currently_contains(eval_interval const& other) const { - if (is_full()) - return true; - if (other.is_full()) - return false; - // lo <= lo' <= hi' <= hi' - if (lo_val() <= other.lo_val() && other.lo_val() <= other.hi_val() && other.hi_val() <= hi_val()) - return true; - if (lo_val() <= hi_val()) - return false; - // hi < lo <= lo' <= hi' - if (lo_val() <= other.lo_val() && other.lo_val() <= other.hi_val()) - return true; - // lo' <= hi' <= hi < lo - if (other.lo_val() <= other.hi_val() && other.hi_val() <= hi_val()) - return true; - // hi' <= hi < lo <= lo' - if (other.hi_val() <= hi_val() && lo_val() <= other.lo_val()) - return true; - return false; - } - - }; // class eval_interval - - inline std::ostream& operator<<(std::ostream& os, eval_interval const& i) { - if (i.is_full()) - return os << "full"; - else { - auto& m = i.hi().manager(); - return os << i.symbolic() << " := [" << m.normalize(i.lo_val()) << ";" << m.normalize(i.hi_val()) << "["; - } - } - -} diff --git a/src/sat/smt/polysat_substitution.h b/src/sat/smt/polysat_substitution.h deleted file mode 100644 index a30c6b710..000000000 --- a/src/sat/smt/polysat_substitution.h +++ /dev/null @@ -1,212 +0,0 @@ -/*++ -Copyright (c) 2021 Microsoft Corporation - -Module Name: - - polysat substitution - -Author: - - Nikolaj Bjorner (nbjorner) 2021-03-19 - Jakob Rath 2021-04-06 - ---*/ -#pragma once -#include "sat/smt/polysat_types.h" - -namespace polysat { - - using assignment_item_t = std::pair; - - class substitution_iterator { - pdd m_current; - substitution_iterator(pdd current) : m_current(std::move(current)) {} - friend class substitution; - - public: - using value_type = assignment_item_t; - using difference_type = std::ptrdiff_t; - using pointer = value_type const*; - using reference = value_type const&; - using iterator_category = std::input_iterator_tag; - - substitution_iterator& operator++() { - SASSERT(!m_current.is_val()); - m_current = m_current.hi(); - return *this; - } - - value_type operator*() const { - SASSERT(!m_current.is_val()); - return { m_current.var(), m_current.lo().val() }; - } - - bool operator==(substitution_iterator const& other) const { return m_current == other.m_current; } - bool operator!=(substitution_iterator const& other) const { return !operator==(other); } - }; - - /** Substitution for a single bit width. */ - class substitution { - pdd m_subst; - - substitution(pdd p); - - public: - substitution(dd::pdd_manager& m); - [[nodiscard]] substitution add(pvar var, rational const& value) const; - [[nodiscard]] pdd apply_to(pdd const& p) const; - - [[nodiscard]] bool contains(pvar var) const; - [[nodiscard]] bool value(pvar var, rational& out_value) const; - - [[nodiscard]] bool empty() const { return m_subst.is_one(); } - - pdd const& to_pdd() const { return m_subst; } - unsigned bit_width() const { return to_pdd().power_of_2(); } - - bool operator==(substitution const& other) const { return &m_subst.manager() == &other.m_subst.manager() && m_subst == other.m_subst; } - bool operator!=(substitution const& other) const { return !operator==(other); } - - std::ostream& display(std::ostream& out) const; - - using const_iterator = substitution_iterator; - const_iterator begin() const { return {m_subst}; } - const_iterator end() const { return {m_subst.manager().one()}; } - }; - - /** Full variable assignment, may include variables of varying bit widths. */ - class assignment { - vector m_pairs; - mutable scoped_ptr_vector m_subst; - vector m_subst_trail; - - substitution& subst(unsigned sz); - solver& s() const { return *m_solver; } - public: - assignment(solver& s); - // prevent implicit copy, use clone() if you do need a copy - assignment(assignment const&) = delete; - assignment& operator=(assignment const&) = delete; - assignment(assignment&&) = default; - assignment& operator=(assignment&&) = default; - assignment clone() const; - - void push(pvar var, rational const& value); - void pop(); - - pdd apply_to(pdd const& p) const; - - bool contains(pvar var) const; - bool value(pvar var, rational& out_value) const; - rational value(pvar var) const { rational val; VERIFY(value(var, val)); return val; } - bool empty() const { return pairs().empty(); } - substitution const& subst(unsigned sz) const; - vector const& pairs() const { return m_pairs; } - using const_iterator = decltype(m_pairs)::const_iterator; - const_iterator begin() const { return pairs().begin(); } - const_iterator end() const { return pairs().end(); } - - std::ostream& display(std::ostream& out) const; - }; - - inline std::ostream& operator<<(std::ostream& out, substitution const& sub) { return sub.display(out); } - - inline std::ostream& operator<<(std::ostream& out, assignment const& a) { return a.display(out); } -} - -namespace polysat { - - enum class search_item_k - { - assignment, - boolean, - }; - - class search_item { - search_item_k m_kind; - union { - pvar m_var; - sat::literal m_lit; - }; - bool m_resolved = false; // when marked as resolved it is no longer valid to reduce the conflict state - - search_item(pvar var): m_kind(search_item_k::assignment), m_var(var) {} - search_item(sat::literal lit): m_kind(search_item_k::boolean), m_lit(lit) {} - public: - static search_item assignment(pvar var) { return search_item(var); } - static search_item boolean(sat::literal lit) { return search_item(lit); } - bool is_assignment() const { return m_kind == search_item_k::assignment; } - bool is_boolean() const { return m_kind == search_item_k::boolean; } - bool is_resolved() const { return m_resolved; } - search_item_k kind() const { return m_kind; } - pvar var() const { SASSERT(is_assignment()); return m_var; } - sat::literal lit() const { SASSERT(is_boolean()); return m_lit; } - void set_resolved() { m_resolved = true; } - }; - - class search_state { - solver& s; - - vector m_items; - assignment m_assignment; - - // store index into m_items - unsigned_vector m_pvar_to_idx; - unsigned_vector m_bool_to_idx; - - bool value(pvar v, rational& r) const; - - public: - search_state(solver& s): s(s), m_assignment(s) {} - unsigned size() const { return m_items.size(); } - search_item const& back() const { return m_items.back(); } - search_item const& operator[](unsigned i) const { return m_items[i]; } - - assignment const& get_assignment() const { return m_assignment; } - substitution const& subst(unsigned sz) const { return m_assignment.subst(sz); } - - // TODO: implement the following method if we actually need the assignments without resolved items already during conflict resolution - // (no separate trail needed, just a second m_subst and an index into the trail, I think) - // (update on set_resolved? might be one iteration too early, looking at the old solver::resolve_conflict loop) - substitution const& unresolved_assignment(unsigned sz) const; - - void push_assignment(pvar v, rational const& r); - void push_boolean(sat::literal lit); - void pop(); - - unsigned get_pvar_index(pvar v) const; - unsigned get_bool_index(sat::bool_var var) const; - unsigned get_bool_index(sat::literal lit) const { return get_bool_index(lit.var()); } - - void set_resolved(unsigned i) { m_items[i].set_resolved(); } - - using const_iterator = decltype(m_items)::const_iterator; - const_iterator begin() const { return m_items.begin(); } - const_iterator end() const { return m_items.end(); } - - std::ostream& display(std::ostream& out) const; - std::ostream& display(search_item const& item, std::ostream& out) const; - std::ostream& display_verbose(std::ostream& out) const; - std::ostream& display_verbose(search_item const& item, std::ostream& out) const; - }; - - struct search_state_pp { - search_state const& s; - bool verbose; - search_state_pp(search_state const& s, bool verbose = false) : s(s), verbose(verbose) {} - }; - - struct search_item_pp { - search_state const& s; - search_item const& i; - bool verbose; - search_item_pp(search_state const& s, search_item const& i, bool verbose = false) : s(s), i(i), verbose(verbose) {} - }; - - inline std::ostream& operator<<(std::ostream& out, search_state const& s) { return s.display(out); } - - inline std::ostream& operator<<(std::ostream& out, search_state_pp const& p) { return p.verbose ? p.s.display_verbose(out) : p.s.display(out); } - - inline std::ostream& operator<<(std::ostream& out, search_item_pp const& p) { return p.verbose ? p.s.display_verbose(p.i, out) : p.s.display(p.i, out); } - -}