6#include "BoundVector.h"
12#include "dlinear/util/exception.h"
14#define TRACE_VIOLATED_BOUNDS(it) \
15 DLINEAR_TRACE_FMT("BoundVector::ViolatedBounds: ({} {}) incompatible with ({} {})", value, lp_bound, *(it)->value, \
20#define FindLowerBoundValue(value_ptr) bounds_.lower_bound({value_ptr, LpColBound::L, {}})
21#define FindLowerBound(value_ptr, bound) bounds_.lower_bound({value_ptr, bound, {}})
22#define FindUpperBoundValue(value_ptr) bounds_.upper_bound({value_ptr, LpColBound::U, {}})
23#define FindUpperBound(value_ptr, bound) bounds_.upper_bound({value_ptr, bound, {}})
24#define FindLowerNqBoundValue(value_ptr) nq_bounds_.lower_bound({value_ptr, LpColBound::D, {}})
25#define FindUpperNqBoundValue(value_ptr) nq_bounds_.upper_bound({value_ptr, LpColBound::D, {}})
33 active_lower_bound_{inf_l_},
34 active_upper_bound_{inf_u_} {}
43 "Valid must be L, U, B, SL, SU or D. Received: {}", lp_bound);
45 if (!violation.empty())
return violation;
57 it =
bounds_.
emplace(
false, &value, lp_bound, theory_lit, explanation);
62 return {
bounds_.cend(),
bounds_.cend(), FindLowerNqBoundValue(&value), FindUpperNqBoundValue(&value)};
69 if (
IsActiveEquality(value))
return {FindLowerBoundValue(&value), FindUpperBoundValue(&value)};
76 bool changed_active_bounds =
false;
82 changed_active_bounds =
true;
85 changed_active_bounds =
true;
88 if (changed_active_bounds) {
105 return RemoveBound({&value, lp_bound, theory_literal, explanation});
118 Bound& modified_bound =
const_cast<Bound&
>(bound);
125 return l_res || u_res;
133 DLINEAR_ASSERT(res,
"Bound must be removed");
137 if (!res)
return res;
151 "Valid must be L, U, B, SL or SU. Received: {}", lp_bound);
153 DLINEAR_TRACE_FMT(
"BoundVector::ViolatedBounds: checking ({} {})", value, lp_bound);
161 if (it ==
bounds_.cend() || *it->value != value)
return {};
163 TRACE_VIOLATED_BOUNDS(it);
164 DLINEAR_ASSERT(
LowerBoundEnd() < FindUpperBound(&value, !lp_bound),
"Bounds must not be inverted");
170 if (it ==
bounds_.cbegin() || *(std::prev(it))->value != value)
return {};
172 TRACE_VIOLATED_BOUNDS((std::prev(it)));
173 DLINEAR_ASSERT(FindLowerBound(&value, !lp_bound) <
LowerBoundEnd(),
"Bounds must not be inverted");
180 TRACE_VIOLATED_BOUNDS(it);
185 if ((it !=
bounds_.cbegin() && *(std::prev(it))->value == value && (std::prev(it))->lp_bound ==
LpColBound::SL)) {
186 TRACE_VIOLATED_BOUNDS(std::prev(it));
192 DLINEAR_UNREACHABLE();
201 if (nq_value_it ==
nq_bounds_.end())
return false;
207 if (lb != ub)
return false;
211 if (nq_value_it ==
nq_bounds_.end())
return false;
231 if (it !=
bounds_.cend())
return true;
238 if (it !=
bounds_.cend())
return true;
263 DLINEAR_ASSERT(lb <= ub,
"Lower bound must be less or equal to upper bound");
267 if (lb_it !=
bounds_.cbegin() && lb == *(std::prev(lb_it))->value) lb_it--;
268 if (ub_it !=
bounds_.cend() && ub == *ub_it->value) ub_it++;
271 lb_it == ub_it || lb_it->lp_bound !=
LpColBound::SL ? FindLowerNqBoundValue(&lb) : FindUpperNqBoundValue(&lb),
272 lb_it == ub_it || (std::prev(ub_it))->lp_bound !=
LpColBound::SU ? FindUpperNqBoundValue(&ub)
273 : FindLowerNqBoundValue(&ub)};
282 DLINEAR_ASSERT(lb <= ub,
"Lower bound must be less or equal to upper bound");
283 const auto lb_it = FindLowerBoundValue(&lb);
284 const auto ub_it = FindUpperBoundValue(&ub);
286 if (lb_it == ub_it)
return {lb_it, ub_it, FindLowerNqBoundValue(&lb), FindUpperNqBoundValue(&ub)};
287 const auto& [value_lb, type_lb, lit_lb, exp_lb] = *lb_it;
288 const auto& [value_ub, type_ub, lit_ub, exp_ub] = *(std::prev(ub_it));
291 return {lb_it, ub_it, FindUpperNqBoundValue(&lb), FindLowerNqBoundValue(&ub)};
294 auto [value, type, lit, exp] = *it;
295 for (; type != type_ub; ++it, type = it->lp_bound, lit = it->theory_literal) {
296 if (lit == lit_ub)
return {it, ub_it, FindUpperNqBoundValue(&lb), FindLowerNqBoundValue(&ub)};
298 it = std::prev(ub_it);
300 lit = it->theory_literal;
301 for (; type != type_lb; --it, type = it->lp_bound, lit = it->theory_literal) {
302 if (lit == lit_lb)
return {lb_it, std::next(it), FindUpperNqBoundValue(&lb), FindLowerNqBoundValue(&ub)};
304 return {lb_it, ub_it, FindUpperNqBoundValue(&lb), FindLowerNqBoundValue(&ub)};
314 explanation.insert(it->explanation.cbegin(), it->explanation.cend());
315 explanation.insert(it->theory_literal);
326 explanation.insert(it->explanation.cbegin(), it->explanation.cend());
327 explanation.insert(it->theory_literal);
337 DLINEAR_RUNTIME_ERROR_FMT(
"Upper bound must be greater or equal to lower bound. Lower: {}, Upper: {}",
343 DLINEAR_RUNTIME_ERROR_FMT(
"Upper bound must be greater or equal to lower bound. Lower: {}, Upper: {}",
349 DLINEAR_RUNTIME_ERROR_FMT(
"Upper bound must be greater or equal to lower bound. Lower: {}, Upper: {}",
355std::ostream& operator<<(std::ostream& os,
const BoundVector& bounds_vector) {
356 os <<
"BoundVector[";
367 for (
const auto& [value, type, lit, exp] : bounds_vector.bounds()) {
368 for (
const Literal& e : exp) os << e <<
" ";
369 if (!exp.empty()) os <<
"=> ";
370 os << lit <<
": " << *value <<
"( " << type <<
" ), ";
375std::ostream& operator<<(std::ostream& os,
const BoundVectorMap& bounds_vector_map) {
376 os <<
"ContextBoundVectorMap{ ";
377 for (
const auto& [col, bounds_vector] : bounds_vector_map) {
378 os <<
"id " << col <<
": " << bounds_vector <<
", ";
383std::ostream& operator<<(std::ostream& os,
const BoundVectorVector& bounds_vector_map) {
384 os <<
"ContextBoundVectorVector{ ";
385 for (
const auto& bounds_vector : bounds_vector_map) {
386 os << bounds_vector <<
", ";
Data structure to store the LP solver bounds in a sorted vector to determine the active lower and upp...
const mpq_class * active_upper_bound_
Active upper bound.
void SetUpperBound(const mpq_class &value)
Manually set the active upper bound to value.
BoundIterator GetActiveBounds() const
Return a BoundIterator containing a set of bounds enclosing the interval [active_lower_bound_,...
void SetLowerBound(const mpq_class &value)
Manually set the active lower bound to value.
const mpq_class * active_lower_bound_
Active lower bound.
std::size_t n_lower_bounds_
Number of lower bounds, both strict and non-strict.
Bounds nq_bounds_
Non-equality bounds.
const mpq_class * GetActiveEqualityBound() const
Return the active equality bound.
BoundVector(const mpq_class &inf_l, const mpq_class &inf_u)
Construct a new BoundVector using inf_l as the the lower bound and inf_u as the upper bound.
const mpq_class & active_lower_bound() const
Get read-only access to the active_lower_bound of the BoundVector.
bool RemoveBound(const Bound &bound)
Remove bound from the vector if it is present.
Bounds::const_iterator LowerBoundEnd() const
Return an iterator over bounds_ after the last lower bound and to the first upper bound.
BoundIterator AddBound(const Bound &bound)
Add a new bound to the vector.
const mpq_class & active_upper_bound() const
Get read-only access to the active_upper_bound of the BoundVector.
LiteralSet GetActiveExplanation() const
Produce a LiteralSet containing all the active bounds that can be used as an explanation.
bool IsUpperBound(const mpq_class &value) const
Check if value represents an upper bound.
bool IsActiveEquality(const mpq_class &value) const
Check if value represents an equality bound.
bool IsBounded() const
Check if the vector has an upper bound and lower bound.
void Clear()
Clear the vector and reset the active bounds.
const mpq_class * inf_u_
Starting upper bound.
BoundIterator ViolatedBounds(const mpq_class &value, LpColBound lp_bound) const
Check if the combination of value and lp_bound violates any of the existing bounds.
bool IsLowerBound(const mpq_class &value) const
Check if value represents a lower bound.
std::pair< const mpq_class &, const mpq_class & > GetActiveBoundsValue() const
Return a pair containing the active lower and upper bound.
const mpq_class * inf_l_
Starting lower bound.
bool IsLowerBounded() const
Check if the vector has a lower bound greater than inf_l_.
Bounds bounds_
Equality and inequality bounds.
bool IsUpperBounded() const
Check if the vector has an upper bound lower than inf_u_.
const mpq_class & inf_u() const
Get read-only access to the positive infinity bound of the BoundVector.
bool ViolatedNqBounds() const
Check if the active bounds violate any of the existing non-equality bounds.
BoundIterator GetActiveBound() const
Return a BoundIterator containing a minimal set of bounds enclosing the interval [active_lower_bound_...
LiteralSet GetActiveEqExplanation() const
Produce a LiteralSet containing all the active bounds that can be used as an explanation,...
const mpq_class & inf_l() const
Get read-only access to the negative lower bound of the BoundVector.
void SetBounds(const mpq_class &lb, const mpq_class &ub)
Manually set the active bounds to lb and ub.
const_iterator find(const T &value) const
Find the index of an element with the provided value in the sorted list.
bool erase(const const_iterator &it)
Remove the element at position it from the sorted list.
void clear()
Clear the sorted list, removing all elements.
size_t size() const
Get read-only access to the size of the vector.
const_iterator upper_bound(const T &value) const
Find the last position in which an element with the provided value could be inserted without changing...
bool empty() const
Check whether the vector is emtpy.
iterator emplace(Args &&... args)
Emplace a new element into the sorted list.
typename std::vector< Bound >::const_iterator const_iterator
const_iterator lower_bound(const T &value) const
Find the first position in which an element with the provided value could be inserted without changin...
Global namespace for the dlinear library.
LpColBound
Describe the bound of a linear program variable.
@ B
Both upper and lower bound are equal (fixed)
@ D
Variable must be different from the bound.
std::set< Literal > LiteralSet
A set of literals.
Tuple containing the value, bound type and theory literal associated with the bound.
LiteralSet explanation
Explanation for the existence of the bound (e.g. propagation)
LpColBound lp_bound
Type of the bound (e.g. L, SL, U, SU)
Literal theory_literal
Theory literal associated with the bound.
const mpq_class * value
Value of the bound.
A literal is a variable with an associated truth value, indicating whether it is true or false.