21 #include "absl/container/flat_hash_map.h"
22 #include "absl/memory/memory.h"
32 const std::vector<IntegerVariable>& vars,
33 const std::vector<IntegerValue>& coeffs,
35 : enforcement_literals_(enforcement_literals),
40 rev_integer_value_repository_(
45 CHECK(!vars_.empty());
46 max_variations_.resize(vars_.size());
49 for (
int i = 0; i < vars.size(); ++i) {
52 coeffs_[i] = -coeffs_[i];
58 literal_reason_.push_back(
literal.Negated());
62 rev_num_fixed_vars_ = 0;
63 rev_lb_fixed_vars_ = IntegerValue(0);
66 void IntegerSumLE::FillIntegerReason() {
67 integer_reason_.clear();
68 reason_coeffs_.clear();
69 const int num_vars = vars_.size();
70 for (
int i = 0; i < num_vars; ++i) {
71 const IntegerVariable
var = vars_[i];
74 reason_coeffs_.push_back(coeffs_[i]);
82 int num_unassigned_enforcement_literal = 0;
87 ++num_unassigned_enforcement_literal;
88 unique_unnasigned_literal =
literal.Index();
94 if (num_unassigned_enforcement_literal > 1)
return true;
98 rev_integer_value_repository_->
SaveState(&rev_lb_fixed_vars_);
100 rev_num_fixed_vars_ = 0;
101 rev_lb_fixed_vars_ = 0;
105 IntegerValue lb_unfixed_vars = IntegerValue(0);
106 const int num_vars = vars_.size();
107 for (
int i = rev_num_fixed_vars_; i < num_vars; ++i) {
108 const IntegerVariable
var = vars_[i];
109 const IntegerValue coeff = coeffs_[i];
113 max_variations_[i] = (ub - lb) * coeff;
114 lb_unfixed_vars += lb * coeff;
117 std::swap(vars_[i], vars_[rev_num_fixed_vars_]);
118 std::swap(coeffs_[i], coeffs_[rev_num_fixed_vars_]);
119 std::swap(max_variations_[i], max_variations_[rev_num_fixed_vars_]);
120 rev_num_fixed_vars_++;
121 rev_lb_fixed_vars_ += lb * coeff;
125 static_cast<double>(num_vars - rev_num_fixed_vars_) * 1e-9);
128 const IntegerValue slack =
129 upper_bound_ - (rev_lb_fixed_vars_ + lb_unfixed_vars);
135 if (num_unassigned_enforcement_literal == 1) {
138 std::vector<Literal> tmp = literal_reason_;
139 tmp.erase(std::find(tmp.begin(), tmp.end(), to_propagate));
140 integer_trail_->
EnqueueLiteral(to_propagate, tmp, integer_reason_);
143 return integer_trail_->
ReportConflict(literal_reason_, integer_reason_);
147 if (num_unassigned_enforcement_literal > 0)
return true;
151 for (
int i = rev_num_fixed_vars_; i < num_vars; ++i) {
152 if (max_variations_[i] <= slack)
continue;
154 const IntegerVariable
var = vars_[i];
155 const IntegerValue coeff = coeffs_[i];
156 const IntegerValue div = slack / coeff;
157 const IntegerValue new_ub = integer_trail_->
LowerBound(
var) + div;
158 const IntegerValue propagation_slack = (div + 1) * coeff - slack - 1;
161 [
this, propagation_slack](
163 std::vector<Literal>* literal_reason,
164 std::vector<int>* trail_indices_reason) {
165 *literal_reason = literal_reason_;
166 trail_indices_reason->clear();
167 reason_coeffs_.clear();
168 const int size = vars_.size();
169 for (int i = 0; i < size; ++i) {
170 const IntegerVariable var = vars_[i];
171 if (PositiveVariable(var) == PositiveVariable(i_lit.var)) {
175 integer_trail_->FindTrailIndexOfVarBefore(var, trail_index);
177 trail_indices_reason->push_back(index);
178 if (propagation_slack > 0) {
179 reason_coeffs_.push_back(coeffs_[i]);
183 if (propagation_slack > 0) {
185 propagation_slack, reason_coeffs_, trail_indices_reason);
195 bool IntegerSumLE::PropagateAtLevelZero() {
198 if (!enforcement_literals_.empty())
return true;
201 IntegerValue min_activity = IntegerValue(0);
202 const int num_vars =
vars_.size();
203 for (
int i = 0; i < num_vars; ++i) {
204 const IntegerVariable
var =
vars_[i];
205 const IntegerValue coeff = coeffs_[i];
206 const IntegerValue lb = integer_trail_->LevelZeroLowerBound(
var);
207 const IntegerValue ub = integer_trail_->LevelZeroUpperBound(
var);
208 max_variations_[i] = (ub - lb) * coeff;
209 min_activity += lb * coeff;
211 time_limit_->AdvanceDeterministicTime(
static_cast<double>(num_vars * 1e-9));
214 const IntegerValue slack = upper_bound_ - min_activity;
216 return integer_trail_->ReportConflict({}, {});
221 for (
int i = 0; i < num_vars; ++i) {
222 if (max_variations_[i] <= slack)
continue;
224 const IntegerVariable
var =
vars_[i];
225 const IntegerValue coeff = coeffs_[i];
226 const IntegerValue div = slack / coeff;
227 const IntegerValue new_ub = integer_trail_->LevelZeroLowerBound(
var) + div;
238 is_registered_ =
true;
239 const int id = watcher->
Register(
this);
240 for (
const IntegerVariable&
var :
vars_) {
253 LevelZeroEquality::LevelZeroEquality(IntegerVariable target,
254 const std::vector<IntegerVariable>& vars,
255 const std::vector<IntegerValue>& coeffs,
263 const int id = watcher->
Register(
this);
264 watcher->SetPropagatorPriority(
id, 2);
265 watcher->WatchIntegerVariable(target,
id);
266 for (
const IntegerVariable&
var : vars_) {
267 watcher->WatchIntegerVariable(
var,
id);
285 for (
int i = 0; i < vars_.size(); ++i) {
286 if (integer_trail_->
IsFixed(vars_[i])) {
287 sum += coeffs_[i] * integer_trail_->
LowerBound(vars_[i]);
293 if (gcd == 0)
return true;
296 VLOG(1) <<
"Objective gcd: " << gcd;
299 gcd_ = IntegerValue(gcd);
301 const IntegerValue lb = integer_trail_->
LowerBound(target_);
303 if (lb_remainder != 0) {
310 const IntegerValue ub = integer_trail_->
UpperBound(target_);
311 const IntegerValue ub_remainder =
313 if (ub_remainder != 0) {
323 IntegerVariable min_var,
325 :
vars_(vars), min_var_(min_var), integer_trail_(integer_trail) {}
328 if (vars_.empty())
return true;
334 const IntegerValue current_min_ub = integer_trail_->
UpperBound(min_var_);
335 int num_intervals_that_can_be_min = 0;
336 int last_possible_min_interval = 0;
339 for (
int i = 0; i < vars_.size(); ++i) {
340 const IntegerValue lb = integer_trail_->
LowerBound(vars_[i]);
342 if (lb <= current_min_ub) {
343 ++num_intervals_that_can_be_min;
344 last_possible_min_interval = i;
350 integer_reason_.clear();
351 for (
const IntegerVariable
var : vars_) {
355 {}, integer_reason_)) {
361 if (num_intervals_that_can_be_min == 1) {
362 const IntegerValue ub_of_only_candidate =
363 integer_trail_->
UpperBound(vars_[last_possible_min_interval]);
364 if (current_min_ub < ub_of_only_candidate) {
365 integer_reason_.clear();
369 integer_reason_.push_back(min_ub_literal);
370 for (
const IntegerVariable
var : vars_) {
371 if (
var ==
vars_[last_possible_min_interval])
continue;
372 integer_reason_.push_back(
378 {}, integer_reason_)) {
390 if (num_intervals_that_can_be_min == 0) {
391 integer_reason_.clear();
394 integer_reason_.push_back(min_ub_literal);
395 for (
const IntegerVariable
var : vars_) {
396 integer_reason_.push_back(
406 const int id = watcher->
Register(
this);
407 for (
const IntegerVariable&
var : vars_) {
420 bool LinMinPropagator::PropagateLinearUpperBound(
421 const std::vector<IntegerVariable>& vars,
422 const std::vector<IntegerValue>& coeffs,
const IntegerValue
upper_bound) {
423 IntegerValue sum_lb = IntegerValue(0);
424 const int num_vars = vars.size();
425 std::vector<IntegerValue> max_variations;
426 for (
int i = 0; i < num_vars; ++i) {
427 const IntegerVariable
var = vars[i];
428 const IntegerValue coeff = coeffs[i];
433 max_variations.push_back((ub - lb) * coeff);
434 sum_lb += lb * coeff;
438 static_cast<double>(num_vars) * 1e-9);
442 std::vector<IntegerLiteral> linear_sum_reason;
443 std::vector<IntegerValue> reason_coeffs;
444 for (
int i = 0; i < num_vars; ++i) {
445 const IntegerVariable
var = vars[i];
448 reason_coeffs.push_back(coeffs[i]);
455 std::vector<IntegerLiteral> local_reason =
456 integer_reason_for_unique_candidate_;
457 local_reason.insert(local_reason.end(), linear_sum_reason.begin(),
458 linear_sum_reason.end());
464 for (
int i = 0; i < num_vars; ++i) {
465 if (max_variations[i] <= slack)
continue;
467 const IntegerVariable
var = vars[i];
468 const IntegerValue coeff = coeffs[i];
469 const IntegerValue div = slack / coeff;
470 const IntegerValue new_ub = integer_trail_->
LowerBound(
var) + div;
472 const IntegerValue propagation_slack = (div + 1) * coeff - slack - 1;
475 [
this, &vars, &coeffs, propagation_slack](
476 IntegerLiteral i_lit,
int trail_index,
477 std::vector<Literal>* literal_reason,
478 std::vector<int>* trail_indices_reason) {
479 literal_reason->clear();
480 trail_indices_reason->clear();
481 std::vector<IntegerValue> reason_coeffs;
482 const int size = vars.size();
483 for (
int i = 0; i < size; ++i) {
484 const IntegerVariable
var = vars[i];
491 trail_indices_reason->push_back(
index);
492 if (propagation_slack > 0) {
493 reason_coeffs.push_back(coeffs[i]);
497 if (propagation_slack > 0) {
499 propagation_slack, reason_coeffs, trail_indices_reason);
502 for (IntegerLiteral reason_lit :
503 integer_reason_for_unique_candidate_) {
505 reason_lit.var, trail_index);
507 trail_indices_reason->push_back(
index);
518 if (exprs_.empty())
return true;
526 const IntegerValue current_min_ub = integer_trail_->
UpperBound(min_var_);
527 int num_intervals_that_can_be_min = 0;
528 int last_possible_min_interval = 0;
531 for (
int i = 0; i < exprs_.size(); ++i) {
533 expr_lbs_.push_back(lb);
534 min_of_linear_expression_lb =
std::min(min_of_linear_expression_lb, lb);
535 if (lb <= current_min_ub) {
536 ++num_intervals_that_can_be_min;
537 last_possible_min_interval = i;
545 if (min_of_linear_expression_lb > current_min_ub) {
546 min_of_linear_expression_lb = current_min_ub + 1;
551 const bool use_slack =
false;
552 if (min_of_linear_expression_lb > integer_trail_->
LowerBound(min_var_)) {
553 std::vector<IntegerLiteral> local_reason;
554 for (
int i = 0; i < exprs_.size(); ++i) {
555 const IntegerValue slack = expr_lbs_[i] - min_of_linear_expression_lb;
557 (use_slack ? slack : IntegerValue(0)), exprs_[i].coeffs,
558 exprs_[i].vars, &local_reason);
561 min_var_, min_of_linear_expression_lb),
571 if (num_intervals_that_can_be_min == 1) {
572 const IntegerValue ub_of_only_candidate =
574 if (current_min_ub < ub_of_only_candidate) {
577 if (rev_unique_candidate_ == 0) {
578 integer_reason_for_unique_candidate_.clear();
582 integer_reason_for_unique_candidate_.push_back(min_ub_literal);
583 for (
int i = 0; i < exprs_.size(); ++i) {
584 if (i == last_possible_min_interval)
continue;
585 const IntegerValue slack = expr_lbs_[i] - (current_min_ub + 1);
587 (use_slack ? slack : IntegerValue(0)), exprs_[i].coeffs,
588 exprs_[i].vars, &integer_reason_for_unique_candidate_);
590 rev_unique_candidate_ = 1;
593 return PropagateLinearUpperBound(
594 exprs_[last_possible_min_interval].vars,
595 exprs_[last_possible_min_interval].coeffs,
596 current_min_ub - exprs_[last_possible_min_interval].offset);
604 const int id = watcher->
Register(
this);
606 for (
int i = 0; i < expr.vars.size(); ++i) {
607 const IntegerVariable&
var = expr.vars[i];
608 const IntegerValue coeff = expr.coeffs[i];
621 IntegerVariable
a, IntegerVariable
b, IntegerVariable p,
623 : a_(
a), b_(
b), p_(p), integer_trail_(integer_trail) {
634 const IntegerValue max_a = integer_trail_->
UpperBound(a_);
635 const IntegerValue max_b = integer_trail_->
UpperBound(b_);
636 const IntegerValue new_max(
CapProd(max_a.value(), max_b.value()));
637 if (new_max < integer_trail_->
UpperBound(p_)) {
639 {integer_trail_->UpperBoundAsLiteral(a_),
640 integer_trail_->UpperBoundAsLiteral(b_)})) {
645 const IntegerValue min_a = integer_trail_->
LowerBound(a_);
646 const IntegerValue min_b = integer_trail_->
LowerBound(b_);
647 const IntegerValue new_min(
CapProd(min_a.value(), min_b.value()));
648 if (new_min > integer_trail_->
LowerBound(p_)) {
651 {integer_trail_->LowerBoundAsLiteral(a_),
652 integer_trail_->LowerBoundAsLiteral(b_)})) {
657 for (
int i = 0; i < 2; ++i) {
658 const IntegerVariable
a = i == 0 ? a_ : b_;
659 const IntegerVariable
b = i == 0 ? b_ : a_;
660 const IntegerValue max_a = integer_trail_->
UpperBound(
a);
661 const IntegerValue min_b = integer_trail_->
LowerBound(
b);
662 const IntegerValue min_p = integer_trail_->
LowerBound(p_);
663 const IntegerValue max_p = integer_trail_->
UpperBound(p_);
664 const IntegerValue prod(
CapProd(max_a.value(), min_b.value()));
672 }
else if (prod < min_p) {
686 const int id = watcher->
Register(
this);
696 IntegerValue FloorSquareRoot(IntegerValue
a) {
697 IntegerValue result(
static_cast<int64_t
>(std::floor(std::sqrt(
ToDouble(
a)))));
698 while (result * result >
a) --result;
699 while ((result + 1) * (result + 1) <=
a) ++result;
704 IntegerValue CeilSquareRoot(IntegerValue
a) {
705 IntegerValue result(
static_cast<int64_t
>(std::ceil(std::sqrt(
ToDouble(
a)))));
706 while (result * result <
a) ++result;
707 while ((result - 1) * (result - 1) >=
a) --result;
715 : x_(x), s_(s), integer_trail_(integer_trail) {
722 const IntegerValue min_x = integer_trail_->
LowerBound(x_);
723 const IntegerValue min_s = integer_trail_->
LowerBound(s_);
724 const IntegerValue min_x_square(
CapProd(min_x.value(), min_x.value()));
725 if (min_x_square > min_s) {
728 {IntegerLiteral::GreaterOrEqual(x_, min_x)})) {
731 }
else if (min_x_square < min_s) {
732 const IntegerValue new_min = CeilSquareRoot(min_s);
735 {IntegerLiteral::GreaterOrEqual(
736 s_, (new_min - 1) * (new_min - 1) + 1)})) {
741 const IntegerValue max_x = integer_trail_->
UpperBound(x_);
742 const IntegerValue max_s = integer_trail_->
UpperBound(s_);
743 const IntegerValue max_x_square(
CapProd(max_x.value(), max_x.value()));
744 if (max_x_square < max_s) {
747 {IntegerLiteral::LowerOrEqual(x_, max_x)})) {
750 }
else if (max_x_square > max_s) {
751 const IntegerValue new_max = FloorSquareRoot(max_s);
753 {IntegerLiteral::LowerOrEqual(
754 s_, (new_max + 1) * (new_max + 1) - 1)})) {
763 const int id = watcher->
Register(
this);
772 : a_(
a), b_(
b), c_(c), integer_trail_(integer_trail) {
779 const IntegerValue min_a = integer_trail_->
LowerBound(a_);
780 const IntegerValue max_a = integer_trail_->
UpperBound(a_);
781 const IntegerValue min_b = integer_trail_->
LowerBound(b_);
782 const IntegerValue max_b = integer_trail_->
UpperBound(b_);
783 IntegerValue min_c = integer_trail_->
LowerBound(c_);
784 IntegerValue max_c = integer_trail_->
UpperBound(c_);
786 if (max_a / min_b < max_c) {
787 max_c = max_a / min_b;
789 {integer_trail_->UpperBoundAsLiteral(a_),
790 integer_trail_->LowerBoundAsLiteral(b_)})) {
794 if (min_a / max_b > min_c) {
795 min_c = min_a / max_b;
797 {integer_trail_->LowerBoundAsLiteral(a_),
798 integer_trail_->UpperBoundAsLiteral(b_)})) {
810 const int id = watcher->
Register(
this);
821 : a_(
a), b_(
b), c_(c), integer_trail_(integer_trail) {}
824 const IntegerValue min_a = integer_trail_->
LowerBound(a_);
825 const IntegerValue max_a = integer_trail_->
UpperBound(a_);
826 IntegerValue min_c = integer_trail_->
LowerBound(c_);
827 IntegerValue max_c = integer_trail_->
UpperBound(c_);
831 if (max_a / b_ < max_c) {
834 {integer_trail_->UpperBoundAsLiteral(a_)})) {
837 }
else if (max_a / b_ > max_c) {
838 const IntegerValue new_max_a =
839 max_c >= 0 ? max_c * b_ + b_ - 1
840 : IntegerValue(
CapProd(max_c.value(), b_.value()));
844 {integer_trail_->UpperBoundAsLiteral(c_)})) {
849 if (min_a / b_ > min_c) {
852 {integer_trail_->LowerBoundAsLiteral(a_)})) {
855 }
else if (min_a / b_ < min_c) {
856 const IntegerValue new_min_a =
857 min_c > 0 ? IntegerValue(
CapProd(min_c.value(), b_.value()))
858 : min_c * b_ - b_ + 1;
862 {integer_trail_->LowerBoundAsLiteral(c_)})) {
871 const int id = watcher->
Register(
this);
877 const std::vector<Literal>& selectors,
878 const std::vector<IntegerValue>& values) {
883 CHECK(!values.empty());
884 CHECK_EQ(values.size(), selectors.size());
885 std::vector<int64_t> unique_values;
886 absl::flat_hash_map<int64_t, std::vector<Literal>> value_to_selector;
887 for (
int i = 0; i < values.size(); ++i) {
888 unique_values.push_back(values[i].
value());
889 value_to_selector[values[i].value()].push_back(selectors[i]);
894 if (unique_values.size() == 1) {
901 for (
const int64_t v : unique_values) {
902 const std::vector<Literal>& selectors = value_to_selector[v];
903 if (selectors.size() == 1) {
904 encoder->AssociateToIntegerEqualValue(selectors[0],
var,
909 encoder->AssociateToIntegerEqualValue(l,
var, IntegerValue(v));
const std::vector< IntVar * > vars_
#define CHECK_LT(val1, val2)
#define CHECK_EQ(val1, val2)
#define CHECK_GE(val1, val2)
#define CHECK_GT(val1, val2)
#define DCHECK_GE(val1, val2)
#define VLOG(verboselevel)
static Domain FromValues(std::vector< int64_t > values)
Creates a domain from the union of an unsorted list of integer values.
static int64_t GCD64(int64_t x, int64_t y)
void SaveState(T *object)
A simple class to enforce both an elapsed time limit and a deterministic time limit in the same threa...
void AdvanceDeterministicTime(double deterministic_duration)
Advances the deterministic time.
void RegisterWith(GenericLiteralWatcher *watcher)
DivisionPropagator(IntegerVariable a, IntegerVariable b, IntegerVariable c, IntegerTrail *integer_trail)
FixedDivisionPropagator(IntegerVariable a, IntegerValue b, IntegerVariable c, IntegerTrail *integer_trail)
void RegisterWith(GenericLiteralWatcher *watcher)
void RegisterReversibleInt(int id, int *rev)
void WatchLiteral(Literal l, int id, int watch_index=-1)
void WatchLowerBound(IntegerVariable var, int id, int watch_index=-1)
void WatchIntegerVariable(IntegerVariable i, int id, int watch_index=-1)
void WatchUpperBound(IntegerVariable var, int id, int watch_index=-1)
int Register(PropagatorInterface *propagator)
void NotifyThatPropagatorMayNotReachFixedPointInOnePass(int id)
IntegerSumLE(const std::vector< Literal > &enforcement_literals, const std::vector< IntegerVariable > &vars, const std::vector< IntegerValue > &coeffs, IntegerValue upper_bound, Model *model)
ABSL_MUST_USE_RESULT bool Enqueue(IntegerLiteral i_lit, absl::Span< const Literal > literal_reason, absl::Span< const IntegerLiteral > integer_reason)
int FindTrailIndexOfVarBefore(IntegerVariable var, int threshold) const
bool IsFixed(IntegerVariable i) const
IntegerLiteral LowerBoundAsLiteral(IntegerVariable i) const
bool ReportConflict(absl::Span< const Literal > literal_reason, absl::Span< const IntegerLiteral > integer_reason)
void EnqueueLiteral(Literal literal, absl::Span< const Literal > literal_reason, absl::Span< const IntegerLiteral > integer_reason)
IntegerValue UpperBound(IntegerVariable i) const
bool VariableLowerBoundIsFromLevelZero(IntegerVariable var) const
void AppendRelaxedLinearReason(IntegerValue slack, absl::Span< const IntegerValue > coeffs, absl::Span< const IntegerVariable > vars, std::vector< IntegerLiteral > *reason) const
IntegerValue LevelZeroLowerBound(IntegerVariable var) const
void RelaxLinearReason(IntegerValue slack, absl::Span< const IntegerValue > coeffs, std::vector< IntegerLiteral > *reason) const
IntegerValue LowerBound(IntegerVariable i) const
IntegerLiteral UpperBoundAsLiteral(IntegerVariable i) const
bool UpdateInitialDomain(IntegerVariable var, Domain domain)
LinMinPropagator(const std::vector< LinearExpression > &exprs, IntegerVariable min_var, Model *model)
void RegisterWith(GenericLiteralWatcher *watcher)
void RegisterWith(GenericLiteralWatcher *watcher)
MinPropagator(const std::vector< IntegerVariable > &vars, IntegerVariable min_var, IntegerTrail *integer_trail)
Class that owns everything related to a particular optimization model.
T * GetOrCreate()
Returns an object of type T that is unique to this model (like a "local" singleton).
void RegisterWith(GenericLiteralWatcher *watcher)
PositiveProductPropagator(IntegerVariable a, IntegerVariable b, IntegerVariable p, IntegerTrail *integer_trail)
void RegisterWith(GenericLiteralWatcher *watcher)
SquarePropagator(IntegerVariable x, IntegerVariable s, IntegerTrail *integer_trail)
const VariablesAssignment & Assignment() const
int CurrentDecisionLevel() const
bool LiteralIsTrue(Literal literal) const
bool LiteralIsFalse(Literal literal) const
void STLSortAndRemoveDuplicates(T *v, const LessFunc &less_func)
void swap(IdMap< K, V > &a, IdMap< K, V > &b)
IntegerValue FloorRatio(IntegerValue dividend, IntegerValue positive_divisor)
std::function< int64_t(const Model &)> UpperBound(IntegerVariable v)
constexpr IntegerValue kMaxIntegerValue(std::numeric_limits< IntegerValue::ValueType >::max() - 1)
IntegerValue LinExprLowerBound(const LinearExpression &expr, const IntegerTrail &integer_trail)
std::function< void(Model *)> ClauseConstraint(absl::Span< const Literal > literals)
IntegerValue CeilRatio(IntegerValue dividend, IntegerValue positive_divisor)
const LiteralIndex kNoLiteralIndex(-1)
std::function< BooleanVariable(Model *)> NewBooleanVariable()
std::function< void(Model *)> IsOneOf(IntegerVariable var, const std::vector< Literal > &selectors, const std::vector< IntegerValue > &values)
IntegerVariable PositiveVariable(IntegerVariable i)
IntegerValue PositiveRemainder(IntegerValue dividend, IntegerValue positive_divisor)
std::function< void(Model *)> LowerOrEqual(IntegerVariable v, int64_t ub)
std::vector< IntegerVariable > NegationOf(const std::vector< IntegerVariable > &vars)
IntegerValue LinExprUpperBound(const LinearExpression &expr, const IntegerTrail &integer_trail)
double ToDouble(IntegerValue value)
std::function< void(Model *)> ReifiedBoolOr(const std::vector< Literal > &literals, Literal r)
Collection of objects used to extend the Constraint Solver library.
int64_t CapProd(int64_t x, int64_t y)
static IntegerLiteral LowerOrEqual(IntegerVariable i, IntegerValue bound)
static IntegerLiteral GreaterOrEqual(IntegerVariable i, IntegerValue bound)