/*++ Copyright (c) 2016 Microsoft Corporation Module Name: bv_bounds.h Abstract: A class used to determine bounds on bit-vector variables. The satisfiability procedure is polynomial. Author: Mikolas Janota (MikolasJanota) Revision History: --*/ #pragma once #include "ast/ast.h" #include "ast/bv_decl_plugin.h" #include "ast/rewriter/rewriter_types.h" /* \brief A class to analyze constraints on bit vectors. The objective is to identify inconsistencies in polynomial time. All bounds/intervals are closed. Methods that add new constraints return false if inconsistency has already been reached. Typical usage is to call repeatedly add_constraint(e) and call is_sat() in the end. */ class bv_bounds { public: typedef rational numeral; typedef std::pair interval; typedef obj_map bound_map; bv_bounds(ast_manager& m) : m_m(m), m_bv_util(m), m_okay(true) {}; ~bv_bounds(); public: // bounds addition methods br_status rewrite(unsigned limit, func_decl * f, unsigned num, expr * const * args, expr_ref& result); /** \brief Add a constraint to the system. The added constraints are to be considered by is_sat. Currently, only special types of inequalities are supported, e.g. v <= v+1. Other constraints are ignored. Returns false if the system became trivially unsatisfiable **/ bool add_constraint(expr* e); bool bound_up(app * v, const numeral& u); // v <= u bool bound_lo(app * v, const numeral& l); // l <= v inline bool add_neg_bound(app * v, const numeral& a, const numeral& b); // not (a<=v<=b) bool add_bound_signed(app * v, const numeral& a, const numeral& b, bool negate); bool add_bound_unsigned(app * v, const numeral& a, const numeral& b, bool negate); public: bool is_sat(); ///< Determine if the set of considered constraints is satisfiable. bool is_okay(); const bound_map& singletons() { return m_singletons; } bv_util& bvu() { return m_bv_util; } void reset(); protected: struct ninterval { //ninterval(app * v, numeral lo, numeral hi, bool negated) : v(v), lo(lo), hi(hi), negated(negated) {} app * v; numeral lo, hi; bool negated; }; enum conv_res { CONVERTED, UNSAT, UNDEF }; conv_res convert(expr * e, vector& nis, bool negated); conv_res record(app * v, numeral lo, numeral hi, bool negated, vector& nis); conv_res convert_signed(app * v, const numeral& a, const numeral& b, bool negate, vector& nis); typedef vector intervals; typedef obj_map intervals_map; ast_manager& m_m; bound_map m_unsigned_lowers; bound_map m_unsigned_uppers; intervals_map m_negative_intervals; bound_map m_singletons; bv_util m_bv_util; bool m_okay; bool is_sat(app * v); bool is_sat_core(app * v); inline bool in_range(app *v, const numeral& l); inline bool is_constant_add(unsigned bv_sz, expr * e, app*& v, numeral& val); void record_singleton(app * v, numeral& singleton_value); inline bool to_bound(const expr * e) const; bool is_uleq(expr * e, expr * & v, numeral & c); }; inline bool bv_bounds::is_okay() { return m_okay; } inline bool bv_bounds::to_bound(const expr * e) const { return is_app(e) && m_bv_util.is_bv(e) && !m_bv_util.is_bv_add(e) && !m_bv_util.is_numeral(e); } inline bool bv_bounds::in_range(app *v, const bv_bounds::numeral& n) { const unsigned bv_sz = m_bv_util.get_bv_size(v); const bv_bounds::numeral zero(0); const bv_bounds::numeral mod(rational::power_of_two(bv_sz)); return (zero <= n) && (n < mod); } inline bool bv_bounds::is_constant_add(unsigned bv_sz, expr * e, app*& v, numeral& val) { SASSERT(e && !v); SASSERT(m_bv_util.get_bv_size(e) == bv_sz); expr *lhs(nullptr), *rhs(nullptr); if (!m_bv_util.is_bv_add(e, lhs, rhs)) { v = to_app(e); val = rational(0); return true; } if (to_bound(lhs) && m_bv_util.is_numeral(rhs, val, bv_sz)) { v = to_app(lhs); return true; } if (to_bound(rhs) && m_bv_util.is_numeral(lhs, val, bv_sz)) { v = to_app(rhs); return true; } return false; }