23#include "absl/container/flat_hash_map.h"
24#include "absl/memory/memory.h"
25#include "absl/types/span.h"
45 const std::vector<IntegerVariable>& vars,
46 const std::vector<IntegerValue>& coeffs,
48 : enforcement_literals_(enforcement_literals),
53 rev_integer_value_repository_(
58 CHECK(!vars_.empty());
59 max_variations_.resize(vars_.size());
62 for (
int i = 0; i < vars.size(); ++i) {
65 coeffs_[i] = -coeffs_[i];
71 literal_reason_.push_back(
literal.Negated());
75 rev_num_fixed_vars_ = 0;
76 rev_lb_fixed_vars_ = IntegerValue(0);
79void IntegerSumLE::FillIntegerReason() {
80 integer_reason_.clear();
81 reason_coeffs_.clear();
82 const int num_vars = vars_.size();
83 for (
int i = 0; i < num_vars; ++i) {
84 const IntegerVariable
var = vars_[i];
87 reason_coeffs_.push_back(coeffs_[i]);
93 IntegerLiteral integer_literal, IntegerVariable target_var)
const {
95 bool literal_var_present =
false;
96 bool literal_var_present_positively =
false;
97 IntegerValue var_coeff;
99 bool target_var_present_negatively =
false;
100 IntegerValue target_coeff;
103 IntegerValue implied_lb(-upper_bound_);
104 for (
int i = 0; i < vars_.size(); ++i) {
105 const IntegerVariable
var = vars_[i];
106 const IntegerValue
coeff = coeffs_[i];
108 target_coeff =
coeff;
109 target_var_present_negatively =
true;
114 implied_lb +=
coeff * lb;
117 literal_var_present =
true;
118 literal_var_present_positively = (
var == integer_literal.
var);
121 if (!literal_var_present || !target_var_present_negatively) {
126 if (literal_var_present_positively) {
131 IntegerValue(0), integer_literal.
bound -
133 return {
CeilRatio(implied_lb, target_coeff),
134 CeilRatio(implied_lb + var_coeff * diff, target_coeff)};
140 IntegerValue(0), integer_trail_->
UpperBound(integer_literal.
var) -
141 integer_literal.
bound + 1);
142 return {
CeilRatio(implied_lb + var_coeff * diff, target_coeff),
150 int num_unassigned_enforcement_literal = 0;
155 ++num_unassigned_enforcement_literal;
156 unique_unnasigned_literal =
literal.Index();
162 if (num_unassigned_enforcement_literal > 1)
return true;
165 if (is_registered_) {
166 rev_integer_value_repository_->
SaveState(&rev_lb_fixed_vars_);
168 rev_num_fixed_vars_ = 0;
169 rev_lb_fixed_vars_ = 0;
173 IntegerValue lb_unfixed_vars = IntegerValue(0);
174 const int num_vars = vars_.size();
175 for (
int i = rev_num_fixed_vars_; i < num_vars; ++i) {
176 const IntegerVariable
var = vars_[i];
177 const IntegerValue
coeff = coeffs_[i];
181 max_variations_[i] = (ub - lb) *
coeff;
182 lb_unfixed_vars += lb *
coeff;
185 std::swap(vars_[i], vars_[rev_num_fixed_vars_]);
186 std::swap(coeffs_[i], coeffs_[rev_num_fixed_vars_]);
187 std::swap(max_variations_[i], max_variations_[rev_num_fixed_vars_]);
188 rev_num_fixed_vars_++;
189 rev_lb_fixed_vars_ += lb *
coeff;
193 static_cast<double>(num_vars - rev_num_fixed_vars_) * 1e-9);
196 const IntegerValue slack =
197 upper_bound_ - (rev_lb_fixed_vars_ + lb_unfixed_vars);
203 if (num_unassigned_enforcement_literal == 1) {
206 std::vector<Literal> tmp = literal_reason_;
207 tmp.erase(std::find(tmp.begin(), tmp.end(), to_propagate));
208 integer_trail_->
EnqueueLiteral(to_propagate, tmp, integer_reason_);
211 return integer_trail_->
ReportConflict(literal_reason_, integer_reason_);
215 if (num_unassigned_enforcement_literal > 0)
return true;
219 for (
int i = rev_num_fixed_vars_; i < num_vars; ++i) {
220 if (max_variations_[i] <= slack)
continue;
222 const IntegerVariable
var = vars_[i];
223 const IntegerValue
coeff = coeffs_[i];
224 const IntegerValue div = slack /
coeff;
225 const IntegerValue new_ub = integer_trail_->
LowerBound(
var) + div;
226 const IntegerValue propagation_slack = (div + 1) *
coeff - slack - 1;
229 [
this, propagation_slack](
231 std::vector<Literal>* literal_reason,
232 std::vector<int>* trail_indices_reason) {
233 *literal_reason = literal_reason_;
234 trail_indices_reason->clear();
235 reason_coeffs_.clear();
236 const int size = vars_.size();
237 for (int i = 0; i < size; ++i) {
238 const IntegerVariable var = vars_[i];
239 if (PositiveVariable(var) == PositiveVariable(i_lit.var)) {
243 integer_trail_->FindTrailIndexOfVarBefore(var, trail_index);
245 trail_indices_reason->push_back(index);
246 if (propagation_slack > 0) {
247 reason_coeffs_.push_back(coeffs_[i]);
251 if (propagation_slack > 0) {
253 propagation_slack, reason_coeffs_, trail_indices_reason);
263bool IntegerSumLE::PropagateAtLevelZero() {
266 if (!enforcement_literals_.empty())
return true;
269 IntegerValue min_activity = IntegerValue(0);
270 const int num_vars =
vars_.size();
271 for (
int i = 0; i < num_vars; ++i) {
272 const IntegerVariable
var =
vars_[i];
273 const IntegerValue
coeff = coeffs_[i];
274 const IntegerValue lb = integer_trail_->LevelZeroLowerBound(
var);
275 const IntegerValue ub = integer_trail_->LevelZeroUpperBound(
var);
276 max_variations_[i] = (ub - lb) *
coeff;
277 min_activity += lb *
coeff;
279 time_limit_->AdvanceDeterministicTime(
static_cast<double>(num_vars * 1e-9));
282 const IntegerValue slack = upper_bound_ - min_activity;
284 return integer_trail_->ReportConflict({}, {});
289 for (
int i = 0; i < num_vars; ++i) {
290 if (max_variations_[i] <= slack)
continue;
292 const IntegerVariable
var =
vars_[i];
293 const IntegerValue
coeff = coeffs_[i];
294 const IntegerValue div = slack /
coeff;
295 const IntegerValue new_ub = integer_trail_->LevelZeroLowerBound(
var) + div;
306 is_registered_ =
true;
307 const int id = watcher->
Register(
this);
308 for (
const IntegerVariable&
var :
vars_) {
321LevelZeroEquality::LevelZeroEquality(IntegerVariable target,
322 const std::vector<IntegerVariable>& vars,
323 const std::vector<IntegerValue>& coeffs,
331 const int id = watcher->
Register(
this);
332 watcher->SetPropagatorPriority(
id, 2);
333 watcher->WatchIntegerVariable(target,
id);
334 for (
const IntegerVariable&
var : vars_) {
335 watcher->WatchIntegerVariable(
var,
id);
353 for (
int i = 0; i < vars_.size(); ++i) {
354 if (integer_trail_->
IsFixed(vars_[i])) {
355 sum += coeffs_[i] * integer_trail_->
LowerBound(vars_[i]);
361 if (gcd == 0)
return true;
364 VLOG(1) <<
"Objective gcd: " << gcd;
367 gcd_ = IntegerValue(gcd);
369 const IntegerValue lb = integer_trail_->
LowerBound(target_);
371 if (lb_remainder != 0) {
378 const IntegerValue ub = integer_trail_->
UpperBound(target_);
379 const IntegerValue ub_remainder =
381 if (ub_remainder != 0) {
391 IntegerVariable min_var,
393 :
vars_(vars), min_var_(min_var), integer_trail_(integer_trail) {}
396 if (vars_.empty())
return true;
402 const IntegerValue current_min_ub = integer_trail_->
UpperBound(min_var_);
403 int num_intervals_that_can_be_min = 0;
404 int last_possible_min_interval = 0;
407 for (
int i = 0; i < vars_.size(); ++i) {
408 const IntegerValue lb = integer_trail_->
LowerBound(vars_[i]);
410 if (lb <= current_min_ub) {
411 ++num_intervals_that_can_be_min;
412 last_possible_min_interval = i;
418 integer_reason_.clear();
419 for (
const IntegerVariable
var : vars_) {
423 {}, integer_reason_)) {
429 if (num_intervals_that_can_be_min == 1) {
430 const IntegerValue ub_of_only_candidate =
431 integer_trail_->
UpperBound(vars_[last_possible_min_interval]);
432 if (current_min_ub < ub_of_only_candidate) {
433 integer_reason_.clear();
437 integer_reason_.push_back(min_ub_literal);
438 for (
const IntegerVariable
var : vars_) {
439 if (
var ==
vars_[last_possible_min_interval])
continue;
440 integer_reason_.push_back(
446 {}, integer_reason_)) {
458 if (num_intervals_that_can_be_min == 0) {
459 integer_reason_.clear();
462 integer_reason_.push_back(min_ub_literal);
463 for (
const IntegerVariable
var : vars_) {
464 integer_reason_.push_back(
474 const int id = watcher->
Register(
this);
475 for (
const IntegerVariable&
var : vars_) {
488bool LinMinPropagator::PropagateLinearUpperBound(
489 const std::vector<IntegerVariable>& vars,
490 const std::vector<IntegerValue>& coeffs,
const IntegerValue
upper_bound) {
491 IntegerValue sum_lb = IntegerValue(0);
492 const int num_vars = vars.size();
493 std::vector<IntegerValue> max_variations;
494 for (
int i = 0; i < num_vars; ++i) {
495 const IntegerVariable
var = vars[i];
496 const IntegerValue
coeff = coeffs[i];
501 max_variations.push_back((ub - lb) *
coeff);
502 sum_lb += lb *
coeff;
506 static_cast<double>(num_vars) * 1e-9);
510 std::vector<IntegerLiteral> linear_sum_reason;
511 std::vector<IntegerValue> reason_coeffs;
512 for (
int i = 0; i < num_vars; ++i) {
513 const IntegerVariable
var = vars[i];
516 reason_coeffs.push_back(coeffs[i]);
523 std::vector<IntegerLiteral> local_reason =
524 integer_reason_for_unique_candidate_;
525 local_reason.insert(local_reason.end(), linear_sum_reason.begin(),
526 linear_sum_reason.end());
532 for (
int i = 0; i < num_vars; ++i) {
533 if (max_variations[i] <= slack)
continue;
535 const IntegerVariable
var = vars[i];
536 const IntegerValue
coeff = coeffs[i];
537 const IntegerValue div = slack /
coeff;
538 const IntegerValue new_ub = integer_trail_->
LowerBound(
var) + div;
540 const IntegerValue propagation_slack = (div + 1) *
coeff - slack - 1;
543 [
this, &vars, &coeffs, propagation_slack](
544 IntegerLiteral i_lit,
int trail_index,
545 std::vector<Literal>* literal_reason,
546 std::vector<int>* trail_indices_reason) {
547 literal_reason->clear();
548 trail_indices_reason->clear();
549 std::vector<IntegerValue> reason_coeffs;
550 const int size = vars.size();
551 for (
int i = 0; i < size; ++i) {
552 const IntegerVariable
var = vars[i];
559 trail_indices_reason->push_back(
index);
560 if (propagation_slack > 0) {
561 reason_coeffs.push_back(coeffs[i]);
565 if (propagation_slack > 0) {
567 propagation_slack, reason_coeffs, trail_indices_reason);
570 for (IntegerLiteral reason_lit :
571 integer_reason_for_unique_candidate_) {
573 reason_lit.var, trail_index);
575 trail_indices_reason->push_back(
index);
586 if (exprs_.empty())
return true;
590 const IntegerValue current_min_ub = integer_trail_->
UpperBound(min_var_);
591 int num_intervals_that_can_be_min = 0;
592 int last_possible_min_interval = 0;
596 for (
int i = 0; i < exprs_.size(); ++i) {
598 expr_lbs_.push_back(lb);
599 min_of_linear_expression_lb =
std::min(min_of_linear_expression_lb, lb);
600 if (lb <= current_min_ub) {
601 ++num_intervals_that_can_be_min;
602 last_possible_min_interval = i;
610 if (min_of_linear_expression_lb > current_min_ub) {
611 min_of_linear_expression_lb = current_min_ub + 1;
613 if (min_of_linear_expression_lb > integer_trail_->
LowerBound(min_var_)) {
614 std::vector<IntegerLiteral> local_reason;
615 for (
int i = 0; i < exprs_.size(); ++i) {
616 const IntegerValue slack = expr_lbs_[i] - min_of_linear_expression_lb;
618 exprs_[i].vars, &local_reason);
621 min_var_, min_of_linear_expression_lb),
631 if (num_intervals_that_can_be_min == 1) {
632 const IntegerValue ub_of_only_candidate =
634 if (current_min_ub < ub_of_only_candidate) {
637 if (rev_unique_candidate_ == 0) {
638 integer_reason_for_unique_candidate_.clear();
642 integer_reason_for_unique_candidate_.push_back(
644 for (
int i = 0; i < exprs_.size(); ++i) {
645 if (i == last_possible_min_interval)
continue;
646 const IntegerValue slack = expr_lbs_[i] - (current_min_ub + 1);
648 slack, exprs_[i].coeffs, exprs_[i].vars,
649 &integer_reason_for_unique_candidate_);
651 rev_unique_candidate_ = 1;
654 return PropagateLinearUpperBound(
655 exprs_[last_possible_min_interval].vars,
656 exprs_[last_possible_min_interval].coeffs,
657 current_min_ub - exprs_[last_possible_min_interval].offset);
665 const int id = watcher->
Register(
this);
667 for (
int i = 0; i < expr.vars.size(); ++i) {
668 const IntegerVariable&
var = expr.vars[i];
669 const IntegerValue
coeff = expr.coeffs[i];
684 : a_(
a), b_(
b), p_(p), integer_trail_(integer_trail) {}
687bool ProductPropagator::CanonicalizeCases() {
701 p_.
GreaterOrEqual(0), {a_.GreaterOrEqual(0), b_.GreaterOrEqual(0)});
727bool ProductPropagator::PropagateWhenAllNonNegative() {
728 const IntegerValue max_a = integer_trail_->
UpperBound(a_);
729 const IntegerValue max_b = integer_trail_->
UpperBound(b_);
730 const IntegerValue new_max(
CapProd(max_a.value(), max_b.value()));
731 if (new_max < integer_trail_->
UpperBound(p_)) {
734 {integer_trail_->UpperBoundAsLiteral(a_),
735 integer_trail_->UpperBoundAsLiteral(b_), a_.GreaterOrEqual(0),
736 b_.GreaterOrEqual(0)})) {
741 const IntegerValue min_a = integer_trail_->
LowerBound(a_);
742 const IntegerValue min_b = integer_trail_->
LowerBound(b_);
743 const IntegerValue new_min(
CapProd(min_a.value(), min_b.value()));
744 if (new_min > integer_trail_->
LowerBound(p_)) {
747 {integer_trail_->LowerBoundAsLiteral(a_),
748 integer_trail_->LowerBoundAsLiteral(b_)})) {
753 for (
int i = 0; i < 2; ++i) {
754 const AffineExpression
a = i == 0 ? a_ : b_;
755 const AffineExpression
b = i == 0 ? b_ : a_;
756 const IntegerValue max_a = integer_trail_->
UpperBound(
a);
757 const IntegerValue min_b = integer_trail_->
LowerBound(
b);
758 const IntegerValue min_p = integer_trail_->
LowerBound(p_);
759 const IntegerValue max_p = integer_trail_->
UpperBound(p_);
760 const IntegerValue prod(
CapProd(max_a.value(), min_b.value()));
768 }
else if (prod < min_p) {
785bool ProductPropagator::PropagateMaxOnPositiveProduct(AffineExpression
a,
788 IntegerValue max_p) {
789 const IntegerValue max_a = integer_trail_->
UpperBound(
a);
790 if (max_a <= 0)
return true;
793 if (max_a >= min_p) {
796 a.LowerOrEqual(max_p),
797 {p_.LowerOrEqual(max_p), p_.GreaterOrEqual(1)})) {
804 const IntegerValue min_pos_b =
CeilRatio(min_p, max_a);
807 b.LowerOrEqual(0), {integer_trail_->LowerBoundAsLiteral(p_),
808 integer_trail_->UpperBoundAsLiteral(a),
809 integer_trail_->UpperBoundAsLiteral(b)})) {
815 const IntegerValue new_max_a =
FloorRatio(max_p, min_pos_b);
818 a.LowerOrEqual(new_max_a),
819 {integer_trail_->LowerBoundAsLiteral(p_),
820 integer_trail_->UpperBoundAsLiteral(a),
821 integer_trail_->UpperBoundAsLiteral(p_)})) {
829 if (!CanonicalizeCases())
return false;
833 const int64_t min_a = integer_trail_->
LowerBound(a_).value();
834 const int64_t min_b = integer_trail_->
LowerBound(b_).value();
835 if (min_a >= 0 && min_b >= 0) {
838 return PropagateWhenAllNonNegative();
847 const int64_t max_a = integer_trail_->
UpperBound(a_).value();
848 const int64_t max_b = integer_trail_->
UpperBound(b_).value();
849 const IntegerValue p1(
CapProd(max_a, max_b));
850 const IntegerValue p2(
CapProd(max_a, min_b));
851 const IntegerValue p3(
CapProd(min_a, max_b));
852 const IntegerValue p4(
CapProd(min_a, min_b));
853 const IntegerValue new_max_p =
std::max({p1, p2, p3, p4});
854 if (new_max_p < integer_trail_->
UpperBound(p_)) {
857 {integer_trail_->LowerBoundAsLiteral(a_),
858 integer_trail_->LowerBoundAsLiteral(b_),
859 integer_trail_->UpperBoundAsLiteral(a_),
860 integer_trail_->UpperBoundAsLiteral(b_)})) {
864 const IntegerValue new_min_p =
std::min({p1, p2, p3, p4});
865 if (new_min_p > integer_trail_->
LowerBound(p_)) {
868 {integer_trail_->LowerBoundAsLiteral(a_),
869 integer_trail_->LowerBoundAsLiteral(b_),
870 integer_trail_->UpperBoundAsLiteral(a_),
871 integer_trail_->UpperBoundAsLiteral(b_)})) {
877 const IntegerValue min_p = integer_trail_->
LowerBound(p_);
878 const IntegerValue max_p = integer_trail_->
UpperBound(p_);
881 const bool zero_is_possible = min_p <= 0;
882 if (!zero_is_possible) {
886 {p_.GreaterOrEqual(1), a_.GreaterOrEqual(0)})) {
893 {p_.GreaterOrEqual(1), b_.GreaterOrEqual(0)})) {
900 b_.
GreaterOrEqual(1), {a_.GreaterOrEqual(0), p_.GreaterOrEqual(1)});
905 a_.
GreaterOrEqual(1), {b_.GreaterOrEqual(0), p_.GreaterOrEqual(1)});
909 for (
int i = 0; i < 2; ++i) {
913 const IntegerValue max_b = integer_trail_->
UpperBound(
b);
914 const IntegerValue min_b = integer_trail_->
LowerBound(
b);
918 if (zero_is_possible && min_b <= 0)
continue;
921 if (min_b < 0 && max_b > 0) {
926 if (!PropagateMaxOnPositiveProduct(
a,
b, min_p, max_p)) {
929 if (!PropagateMaxOnPositiveProduct(
a.Negated(),
b.Negated(), min_p,
938 if (min_b <= 0)
continue;
941 a.GreaterOrEqual(0), {p_.GreaterOrEqual(0), b.GreaterOrEqual(1)});
945 a.LowerOrEqual(0), {p_.LowerOrEqual(0), b.GreaterOrEqual(1)});
949 const IntegerValue new_max_a =
FloorRatio(max_p, min_b);
952 a.LowerOrEqual(new_max_a),
953 {integer_trail_->UpperBoundAsLiteral(p_),
954 integer_trail_->LowerBoundAsLiteral(b)})) {
958 const IntegerValue new_min_a =
CeilRatio(min_p, min_b);
961 a.GreaterOrEqual(new_min_a),
962 {integer_trail_->LowerBoundAsLiteral(p_),
963 integer_trail_->LowerBoundAsLiteral(b)})) {
973 const int id = watcher->
Register(
this);
982 : x_(x), s_(s), integer_trail_(integer_trail) {
989 const IntegerValue min_x = integer_trail_->
LowerBound(x_);
990 const IntegerValue min_s = integer_trail_->
LowerBound(s_);
991 const IntegerValue min_x_square(
CapProd(min_x.value(), min_x.value()));
992 if (min_x_square > min_s) {
994 {x_.GreaterOrEqual(min_x)})) {
997 }
else if (min_x_square < min_s) {
1001 {s_.GreaterOrEqual((new_min - 1) * (new_min - 1) + 1)})) {
1006 const IntegerValue max_x = integer_trail_->
UpperBound(x_);
1007 const IntegerValue max_s = integer_trail_->
UpperBound(s_);
1008 const IntegerValue max_x_square(
CapProd(max_x.value(), max_x.value()));
1009 if (max_x_square < max_s) {
1011 {x_.LowerOrEqual(max_x)})) {
1014 }
else if (max_x_square > max_s) {
1018 {s_.LowerOrEqual(IntegerValue(CapProd(new_max.value() + 1,
1019 new_max.value() + 1)) -
1029 const int id = watcher->
Register(
this);
1042 negated_num_(num.Negated()),
1043 negated_div_(div.Negated()),
1044 integer_trail_(integer_trail) {
1050 if (!PropagateSigns())
return false;
1054 !PropagateUpperBounds(num_, denom_, div_)) {
1058 if (integer_trail_->
UpperBound(negated_num_) >= 0 &&
1059 integer_trail_->
UpperBound(negated_div_) >= 0 &&
1060 !PropagateUpperBounds(negated_num_, denom_, negated_div_)) {
1066 return PropagatePositiveDomains(num_, denom_, div_);
1071 return PropagatePositiveDomains(negated_num_, denom_, negated_div_);
1077bool DivisionPropagator::PropagateSigns() {
1078 const IntegerValue min_num = integer_trail_->
LowerBound(num_);
1079 const IntegerValue max_num = integer_trail_->
UpperBound(num_);
1080 const IntegerValue min_div = integer_trail_->
LowerBound(div_);
1081 const IntegerValue max_div = integer_trail_->
UpperBound(div_);
1084 if (min_num >= 0 && min_div < 0) {
1086 {num_.GreaterOrEqual(0)})) {
1092 if (min_num <= 0 && min_div > 0) {
1094 {div_.GreaterOrEqual(1)})) {
1100 if (max_num <= 0 && max_div > 0) {
1102 {num_.LowerOrEqual(0)})) {
1108 if (max_num >= 0 && max_div < 0) {
1110 {div_.LowerOrEqual(-1)})) {
1118bool DivisionPropagator::PropagateUpperBounds(AffineExpression num,
1119 AffineExpression denom,
1120 AffineExpression div) {
1121 const IntegerValue max_num = integer_trail_->
UpperBound(num);
1122 const IntegerValue min_denom = integer_trail_->
LowerBound(denom);
1123 const IntegerValue max_denom = integer_trail_->
UpperBound(denom);
1124 const IntegerValue max_div = integer_trail_->
UpperBound(div);
1126 const IntegerValue new_max_div = max_num / min_denom;
1127 if (max_div > new_max_div) {
1129 div.LowerOrEqual(new_max_div),
1130 {integer_trail_->UpperBoundAsLiteral(num),
1131 integer_trail_->LowerBoundAsLiteral(denom)})) {
1139 const IntegerValue new_max_num =
1140 IntegerValue(
CapAdd(
CapProd(max_div.value() + 1, max_denom.value()), -1));
1141 if (max_num > new_max_num) {
1143 num.LowerOrEqual(new_max_num),
1144 {integer_trail_->UpperBoundAsLiteral(denom),
1145 integer_trail_->UpperBoundAsLiteral(div)})) {
1153bool DivisionPropagator::PropagatePositiveDomains(AffineExpression num,
1154 AffineExpression denom,
1155 AffineExpression div) {
1156 const IntegerValue min_num = integer_trail_->
LowerBound(num);
1157 const IntegerValue max_num = integer_trail_->
UpperBound(num);
1158 const IntegerValue min_denom = integer_trail_->
LowerBound(denom);
1159 const IntegerValue max_denom = integer_trail_->
UpperBound(denom);
1160 const IntegerValue min_div = integer_trail_->
LowerBound(div);
1161 const IntegerValue max_div = integer_trail_->
UpperBound(div);
1163 const IntegerValue new_min_div = min_num / max_denom;
1164 if (min_div < new_min_div) {
1166 div.GreaterOrEqual(new_min_div),
1167 {integer_trail_->LowerBoundAsLiteral(num),
1168 integer_trail_->UpperBoundAsLiteral(denom)})) {
1176 const IntegerValue new_min_num =
1177 IntegerValue(
CapProd(min_denom.value(), min_div.value()));
1178 if (min_num < new_min_num) {
1180 num.GreaterOrEqual(new_min_num),
1181 {integer_trail_->LowerBoundAsLiteral(denom),
1182 integer_trail_->LowerBoundAsLiteral(div)})) {
1192 const IntegerValue new_max_denom = max_num / min_div;
1193 if (max_denom > new_max_denom) {
1195 denom.LowerOrEqual(new_max_denom),
1196 {integer_trail_->UpperBoundAsLiteral(num), num.GreaterOrEqual(0),
1197 integer_trail_->LowerBoundAsLiteral(div)})) {
1205 const IntegerValue new_min_denom =
CeilRatio(min_num + 1, max_div + 1);
1206 if (min_denom < new_min_denom) {
1207 if (!integer_trail_->
SafeEnqueue(denom.GreaterOrEqual(new_min_denom),
1208 {integer_trail_->LowerBoundAsLiteral(num),
1209 integer_trail_->UpperBoundAsLiteral(div),
1210 div.GreaterOrEqual(0)})) {
1219 const int id = watcher->
Register(
this);
1230 : a_(
a), b_(
b), c_(c), integer_trail_(integer_trail) {
1235 const IntegerValue min_a = integer_trail_->
LowerBound(a_);
1236 const IntegerValue max_a = integer_trail_->
UpperBound(a_);
1237 IntegerValue min_c = integer_trail_->
LowerBound(c_);
1238 IntegerValue max_c = integer_trail_->
UpperBound(c_);
1240 if (max_a / b_ < max_c) {
1244 {integer_trail_->UpperBoundAsLiteral(a_)})) {
1247 }
else if (max_a / b_ > max_c) {
1248 const IntegerValue new_max_a =
1249 max_c >= 0 ? max_c * b_ + b_ - 1
1250 : IntegerValue(
CapProd(max_c.value(), b_.value()));
1254 {integer_trail_->UpperBoundAsLiteral(c_)})) {
1259 if (min_a / b_ > min_c) {
1263 {integer_trail_->LowerBoundAsLiteral(a_)})) {
1266 }
else if (min_a / b_ < min_c) {
1267 const IntegerValue new_min_a =
1268 min_c > 0 ? IntegerValue(
CapProd(min_c.value(), b_.value()))
1269 : min_c * b_ - b_ + 1;
1273 {integer_trail_->LowerBoundAsLiteral(c_)})) {
1282 const int id = watcher->
Register(
this);
1291 :
expr_(expr), mod_(mod), target_(target), integer_trail_(integer_trail) {
1296 if (!PropagateSignsAndTargetRange())
return false;
1297 if (!PropagateOuterBounds())
return false;
1299 if (integer_trail_->
LowerBound(expr_) >= 0) {
1300 if (!PropagateBoundsWhenExprIsPositive(expr_, target_))
return false;
1301 }
else if (integer_trail_->
UpperBound(expr_) <= 0) {
1302 if (!PropagateBoundsWhenExprIsPositive(expr_.
Negated(),
1311bool FixedModuloPropagator::PropagateSignsAndTargetRange() {
1313 if (integer_trail_->
UpperBound(target_) >= mod_) {
1319 if (integer_trail_->
LowerBound(target_) <= -mod_) {
1326 if (integer_trail_->
LowerBound(expr_) >= 0 &&
1329 {expr_.GreaterOrEqual(0)})) {
1334 if (integer_trail_->
UpperBound(expr_) <= 0 &&
1337 {expr_.LowerOrEqual(0)})) {
1345bool FixedModuloPropagator::PropagateOuterBounds() {
1346 const IntegerValue min_expr = integer_trail_->
LowerBound(expr_);
1347 const IntegerValue max_expr = integer_trail_->
UpperBound(expr_);
1348 const IntegerValue min_target = integer_trail_->
LowerBound(target_);
1349 const IntegerValue max_target = integer_trail_->
UpperBound(target_);
1351 if (max_expr % mod_ > max_target) {
1353 expr_.
LowerOrEqual((max_expr / mod_) * mod_ + max_target),
1354 {integer_trail_->UpperBoundAsLiteral(target_),
1355 integer_trail_->UpperBoundAsLiteral(expr_)})) {
1360 if (min_expr % mod_ < min_target) {
1363 {integer_trail_->LowerBoundAsLiteral(expr_),
1364 integer_trail_->LowerBoundAsLiteral(target_)})) {
1369 if (min_expr / mod_ == max_expr / mod_) {
1370 if (min_target < min_expr % mod_) {
1373 {integer_trail_->LowerBoundAsLiteral(target_),
1374 integer_trail_->UpperBoundAsLiteral(target_),
1375 integer_trail_->LowerBoundAsLiteral(expr_),
1376 integer_trail_->UpperBoundAsLiteral(expr_)})) {
1381 if (max_target > max_expr % mod_) {
1383 target_.
LowerOrEqual(max_expr - (max_expr / mod_) * mod_),
1384 {integer_trail_->LowerBoundAsLiteral(target_),
1385 integer_trail_->UpperBoundAsLiteral(target_),
1386 integer_trail_->LowerBoundAsLiteral(expr_),
1387 integer_trail_->UpperBoundAsLiteral(expr_)})) {
1391 }
else if (min_expr / mod_ == 0 && min_target < 0) {
1393 if (min_target < min_expr) {
1396 {integer_trail_->LowerBoundAsLiteral(target_),
1397 integer_trail_->LowerBoundAsLiteral(expr_)})) {
1401 }
else if (max_expr / mod_ == 0 && max_target > 0) {
1403 if (max_target > max_expr) {
1406 {integer_trail_->UpperBoundAsLiteral(target_),
1407 integer_trail_->UpperBoundAsLiteral(expr_)})) {
1416bool FixedModuloPropagator::PropagateBoundsWhenExprIsPositive(
1417 AffineExpression expr, AffineExpression target) {
1418 const IntegerValue min_target = integer_trail_->
LowerBound(target);
1420 const IntegerValue max_target = integer_trail_->
UpperBound(target);
1424 if (min_target == 0 && max_target == mod_ - 1)
return true;
1426 const IntegerValue min_expr = integer_trail_->
LowerBound(expr);
1427 const IntegerValue max_expr = integer_trail_->
UpperBound(expr);
1429 if (max_expr % mod_ < min_target) {
1432 expr.LowerOrEqual((max_expr / mod_ - 1) * mod_ + max_target),
1433 {integer_trail_->UpperBoundAsLiteral(expr),
1434 integer_trail_->LowerBoundAsLiteral(target),
1435 integer_trail_->UpperBoundAsLiteral(target)})) {
1440 if (min_expr % mod_ > max_target) {
1443 expr.GreaterOrEqual((min_expr / mod_ + 1) * mod_ + min_target),
1444 {integer_trail_->LowerBoundAsLiteral(target),
1445 integer_trail_->UpperBoundAsLiteral(target),
1446 integer_trail_->LowerBoundAsLiteral(expr)})) {
1455 const int id = watcher->
Register(
this);
1462 const std::vector<Literal>& selectors,
1463 const std::vector<IntegerValue>& values) {
1468 CHECK(!values.empty());
1469 CHECK_EQ(values.size(), selectors.size());
1470 std::vector<int64_t> unique_values;
1471 absl::flat_hash_map<int64_t, std::vector<Literal>> value_to_selector;
1472 for (
int i = 0; i < values.size(); ++i) {
1473 unique_values.push_back(values[i].
value());
1474 value_to_selector[values[i].value()].push_back(selectors[i]);
1479 if (unique_values.size() == 1) {
1486 for (
const int64_t v : unique_values) {
1487 const std::vector<Literal>& selectors = value_to_selector[v];
1488 if (selectors.size() == 1) {
1489 encoder->AssociateToIntegerEqualValue(selectors[0],
var,
1494 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 DCHECK_GT(val1, val2)
#define DCHECK_LT(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.
DivisionPropagator(AffineExpression num, AffineExpression denom, AffineExpression div, IntegerTrail *integer_trail)
void RegisterWith(GenericLiteralWatcher *watcher)
void RegisterWith(GenericLiteralWatcher *watcher)
FixedDivisionPropagator(AffineExpression a, IntegerValue b, AffineExpression c, IntegerTrail *integer_trail)
void RegisterWith(GenericLiteralWatcher *watcher)
FixedModuloPropagator(AffineExpression expr, IntegerValue mod, AffineExpression target, IntegerTrail *integer_trail)
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 WatchAffineExpression(AffineExpression e, int id)
void WatchUpperBound(IntegerVariable var, int id, int watch_index=-1)
int Register(PropagatorInterface *propagator)
void NotifyThatPropagatorMayNotReachFixedPointInOnePass(int id)
std::pair< IntegerValue, IntegerValue > ConditionalLb(IntegerLiteral integer_literal, IntegerVariable target_var) const
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
ABSL_MUST_USE_RESULT bool SafeEnqueue(IntegerLiteral i_lit, absl::Span< const IntegerLiteral > integer_reason)
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)
ProductPropagator(AffineExpression a, AffineExpression b, AffineExpression p, IntegerTrail *integer_trail)
void RegisterWith(GenericLiteralWatcher *watcher)
SquarePropagator(AffineExpression x, AffineExpression 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)
constexpr IntegerValue kMaxIntegerValue(std::numeric_limits< IntegerValue::ValueType >::max() - 1)
IntegerValue LinExprLowerBound(const LinearExpression &expr, const IntegerTrail &integer_trail)
std::function< void(Model *)> ReifiedBoolOr(const std::vector< Literal > &literals, Literal r)
IntegerValue CeilRatio(IntegerValue dividend, IntegerValue positive_divisor)
const LiteralIndex kNoLiteralIndex(-1)
std::function< void(Model *)> ClauseConstraint(absl::Span< const Literal > literals)
std::function< void(Model *)> IsOneOf(IntegerVariable var, const std::vector< Literal > &selectors, const std::vector< IntegerValue > &values)
std::function< BooleanVariable(Model *)> NewBooleanVariable()
std::function< void(Model *)> LowerOrEqual(IntegerVariable v, int64_t ub)
constexpr IntegerValue kMinIntegerValue(-kMaxIntegerValue.value())
int64_t CeilSquareRoot(int64_t a)
IntegerVariable PositiveVariable(IntegerVariable i)
IntegerValue PositiveRemainder(IntegerValue dividend, IntegerValue positive_divisor)
std::function< int64_t(const Model &)> UpperBound(IntegerVariable v)
int64_t FloorSquareRoot(int64_t a)
std::vector< IntegerVariable > NegationOf(const std::vector< IntegerVariable > &vars)
IntegerValue LinExprUpperBound(const LinearExpression &expr, const IntegerTrail &integer_trail)
Collection of objects used to extend the Constraint Solver library.
int64_t CapAdd(int64_t x, int64_t y)
int64_t CapProd(int64_t x, int64_t y)
AffineExpression Negated() const
IntegerLiteral GreaterOrEqual(IntegerValue bound) const
IntegerLiteral LowerOrEqual(IntegerValue bound) const
static IntegerLiteral LowerOrEqual(IntegerVariable i, IntegerValue bound)
static IntegerLiteral GreaterOrEqual(IntegerVariable i, IntegerValue bound)