12#include <initializer_list>
16#include "dlinear/util/Infinity.h"
17#include "dlinear/util/RoundingModeGuard.hpp"
18#include "dlinear/util/exception.h"
19#include "dlinear/util/math.h"
27 : lp_solver_{lp_solver},
30 var_to_idx_{
std::make_shared<
std::unordered_map<
Variable, int>>()},
31 idx_to_var_{
std::make_shared<
std::unordered_map<int,
Variable>>()} {}
41 DLINEAR_RUNTIME_ERROR(
"Integer variables not supported");
47 "Duplicate variables are not allowed");
53 variables_ = std::make_shared<std::vector<Variable>>(*variables_);
54 var_to_idx_ = std::make_shared<std::unordered_map<Variable, int>>(*var_to_idx_);
55 idx_to_var_ = std::make_shared<std::unordered_map<int, Variable>>(*idx_to_var_);
64 switch (v.get_type()) {
70 DLINEAR_RUNTIME_ERROR(
"Integer variables not supported");
71 values_.emplace_back(-std::numeric_limits<int>::max(), std::numeric_limits<int>::max());
81 DLINEAR_ASSERT(lb <= ub,
"Lower bound must be less than or equal to upper bound");
85 "Binary variable must be in [0, 1]");
89 "Integer variable must be in Z");
103 DLINEAR_ASSERT(i <
size(),
"Index out of bound");
108 DLINEAR_ASSERT(i <
size(),
"Index out of bound");
125 mpq_class max_diam{0.0};
127 for (std::size_t i{0}; i <
variables_->size(); ++i) {
128 const mpq_class &diam_i{
values_[i].diam()};
129 if (diam_i > max_diam &&
values_[i].is_bisectable()) {
134 return std::make_pair(max_diam, idx);
138 const Variable &var{(*idx_to_var_)[i]};
139 if (!
values_[i].is_bisectable()) {
140 DLINEAR_RUNTIME_ERROR_FMT(
"Variable {} = {} is not bisectable but Box::Bisect is called.", var,
values_[i]);
142 switch (var.get_type()) {
149 DLINEAR_UNREACHABLE();
151 DLINEAR_UNREACHABLE();
157 return Bisect(it->second);
159 DLINEAR_RUNTIME_ERROR_FMT(
"Variable {} is not found in this box.", var);
167 "Variable must be integer or binary");
169 const mpz_class &lb{ceil(intv_i.lb())};
170 const mpz_class &ub{floor(intv_i.ub())};
171 const mpq_class &mid{intv_i.mid()};
172 const mpz_class &mid_floor{floor(mid)};
173 DLINEAR_ASSERT(intv_i.lb() <= lb,
"intv_i lower bound must be less than or equal to lower bound");
174 DLINEAR_ASSERT(lb <= mid_floor,
"lower bound must be less than or equal to mid_floor");
175 DLINEAR_ASSERT(mid_floor + 1 <= ub,
"mid_floor + 1 must be less than or equal to upper bound");
176 DLINEAR_ASSERT(ub <= intv_i.ub(),
"upper bound must be less than or equal to intv_i upper bound");
181 b2[i] =
Interval(mid_floor + 1, ub);
182 return std::make_pair(b1, b2);
190 constexpr double kHalf{0.5};
191 const std::pair<Interval, Interval> bisected_intervals{intv_i.bisect(kHalf)};
192 b1[i] = bisected_intervals.first;
193 b2[i] = bisected_intervals.second;
194 return std::make_pair(b1, b2);
198Box& Box::InplaceUnion(
const Box& b) {
202 std::equal_to<Variable>{}));
210class IosFmtFlagSaver {
212 explicit IosFmtFlagSaver(std::ostream &os) : os_(os), flags_(os.flags()) {}
213 ~IosFmtFlagSaver() { os_.flags(flags_); }
215 IosFmtFlagSaver(
const IosFmtFlagSaver &rhs) =
delete;
216 IosFmtFlagSaver(IosFmtFlagSaver &&rhs) =
delete;
217 IosFmtFlagSaver &operator=(
const IosFmtFlagSaver &rhs) =
delete;
218 IosFmtFlagSaver &operator=(IosFmtFlagSaver &&rhs) =
delete;
222 std::ios::fmtflags flags_;
226std::ostream &operator<<(std::ostream &os,
const Box &box) {
227 IosFmtFlagSaver saver{os};
229 for (
const Variable &var : *(box.variables_)) {
230 const Interval interval{box.values_[i++]};
232 switch (var.get_type()) {
239 if (interval.ub() == 0.0)
241 else if (interval.lb() == 1.0)
247 if (i != box.size()) os <<
"\n";
252bool operator==(
const Box &b1,
const Box &b2) {
253 return std::equal(b1.variables().begin(), b1.variables().end(), b2.variables().begin(), b2.variables().end(),
254 std::equal_to<Variable>{}) &&
255 (b1.interval_vector() == b2.interval_vector());
258bool operator!=(
const Box &b1,
const Box &b2) {
return !(b1 == b2); }
260std::ostream &DisplayDiff(std::ostream &os,
const std::vector<Variable> &variables,
const std::vector<Interval> &old_iv,
261 const std::vector<Interval> &new_iv) {
262 IosFmtFlagSaver saver{os};
263 for (std::size_t i = 0; i < variables.size(); ++i) {
264 const Interval &old_i{old_iv[i]};
265 const Interval &new_i{new_iv[i]};
266 if (old_i != new_i) os << variables[i] <<
" : " << old_i <<
" -> " << new_i <<
"\n";
Collection of variables with associated intervals.
std::vector< Interval > values_
Interval vector of the box.
std::pair< mpq_class, int > MaxDiam() const
Return the max diameter of the box and the associated index.
std::shared_ptr< std::unordered_map< Variable, int > > var_to_idx_
Variable to index map.
std::vector< Interval > & m_interval_vector()
Return the interval vector of the box.
std::shared_ptr< std::vector< Variable > > variables_
Variables in the box.
void Add(const Variable &v)
Add the variable v to the box.
std::shared_ptr< std::unordered_map< int, Variable > > idx_to_var_
Index to variable map.
Interval & operator[](int i)
Return the interval at index i.
Config::LPSolver lp_solver_
LP solver.
std::pair< Box, Box > Bisect(int i) const
Bisect the box at i -th dimension.
int index(const Variable &var) const
Return the index associated with var.
std::pair< Box, Box > BisectInt(int i) const
Bisects the box at i -th dimension.
const std::vector< Variable > & variables() const
Get read-only access to the variables of the box.
Box(Config::LPSolver lp_solver)
Construct a new Box object associated with the given lp_solver.
const std::vector< Interval > & interval_vector() const
Return the interval vector of the box.
bool empty() const
Check whether the box is empty.
std::pair< Box, Box > BisectContinuous(int i) const
Bisects the box at i -th dimension.
int size() const
Get read-only access to the number of variables of the box.
const Variable & variable(int i) const
Return the i -th variable in the box.
void set_empty()
Clear the box, making it empty.
bool has_variable(const Variable &var) const
Checks if this box contains var.
LPSolver
Underlying LP solver used by the theory solver.
static const mpq_class & ninfinity(const Config &config)
Get the negative infinity value for the given LP solver in the config.
static const mpq_class & infinity(const Config &config)
Get the positive infinity value for the given LP solver in the config.
Represents a symbolic variable.
@ INTEGER
An INTEGER variable takes an int value.
@ BINARY
A BINARY variable takes an integer value from {0, 1}.
@ CONTINUOUS
A CONTINUOUS variable takes a mpq_class value.
@ BOOLEAN
A BOOLEAN variable takes a bool value.
Global namespace for the dlinear library.
bool IsInteger(const double v)
Returns true if v is represented by int.