21#include "absl/container/flat_hash_map.h"
22#include "absl/memory/memory.h"
33 const std::vector<IntegerVariable>& vars,
34 const std::vector<IntegerValue>& coeffs,
36 : enforcement_literals_(enforcement_literals),
41 rev_integer_value_repository_(
46 CHECK(!vars_.empty());
47 max_variations_.resize(vars_.size());
50 for (
int i = 0; i < vars.size(); ++i) {
53 coeffs_[i] = -coeffs_[i];
59 literal_reason_.push_back(
literal.Negated());
63 rev_num_fixed_vars_ = 0;
64 rev_lb_fixed_vars_ = IntegerValue(0);
67void IntegerSumLE::FillIntegerReason() {
68 integer_reason_.clear();
69 reason_coeffs_.clear();
70 const int num_vars = vars_.size();
71 for (
int i = 0; i < num_vars; ++i) {
72 const IntegerVariable
var = vars_[i];
75 reason_coeffs_.push_back(coeffs_[i]);
81 IntegerLiteral integer_literal, IntegerVariable target_var)
const {
83 bool literal_var_present =
false;
84 bool literal_var_present_positively =
false;
85 IntegerValue var_coeff;
87 bool target_var_present_negatively =
false;
88 IntegerValue target_coeff;
91 IntegerValue implied_lb(-upper_bound_);
92 for (
int i = 0; i < vars_.size(); ++i) {
93 const IntegerVariable
var = vars_[i];
94 const IntegerValue
coeff = coeffs_[i];
97 target_var_present_negatively =
true;
102 implied_lb +=
coeff * lb;
105 literal_var_present =
true;
106 literal_var_present_positively = (
var == integer_literal.
var);
109 if (!literal_var_present || !target_var_present_negatively) {
114 if (literal_var_present_positively) {
119 IntegerValue(0), integer_literal.
bound -
121 return {
CeilRatio(implied_lb, target_coeff),
122 CeilRatio(implied_lb + var_coeff * diff, target_coeff)};
128 IntegerValue(0), integer_trail_->
UpperBound(integer_literal.
var) -
129 integer_literal.
bound + 1);
130 return {
CeilRatio(implied_lb + var_coeff * diff, target_coeff),
138 int num_unassigned_enforcement_literal = 0;
143 ++num_unassigned_enforcement_literal;
144 unique_unnasigned_literal =
literal.Index();
150 if (num_unassigned_enforcement_literal > 1)
return true;
153 if (is_registered_) {
154 rev_integer_value_repository_->
SaveState(&rev_lb_fixed_vars_);
156 rev_num_fixed_vars_ = 0;
157 rev_lb_fixed_vars_ = 0;
161 IntegerValue lb_unfixed_vars = IntegerValue(0);
162 const int num_vars = vars_.size();
163 for (
int i = rev_num_fixed_vars_; i < num_vars; ++i) {
164 const IntegerVariable
var = vars_[i];
165 const IntegerValue
coeff = coeffs_[i];
169 max_variations_[i] = (ub - lb) *
coeff;
170 lb_unfixed_vars += lb *
coeff;
173 std::swap(vars_[i], vars_[rev_num_fixed_vars_]);
174 std::swap(coeffs_[i], coeffs_[rev_num_fixed_vars_]);
175 std::swap(max_variations_[i], max_variations_[rev_num_fixed_vars_]);
176 rev_num_fixed_vars_++;
177 rev_lb_fixed_vars_ += lb *
coeff;
181 static_cast<double>(num_vars - rev_num_fixed_vars_) * 1e-9);
184 const IntegerValue slack =
185 upper_bound_ - (rev_lb_fixed_vars_ + lb_unfixed_vars);
191 if (num_unassigned_enforcement_literal == 1) {
194 std::vector<Literal> tmp = literal_reason_;
195 tmp.erase(std::find(tmp.begin(), tmp.end(), to_propagate));
196 integer_trail_->
EnqueueLiteral(to_propagate, tmp, integer_reason_);
199 return integer_trail_->
ReportConflict(literal_reason_, integer_reason_);
203 if (num_unassigned_enforcement_literal > 0)
return true;
207 for (
int i = rev_num_fixed_vars_; i < num_vars; ++i) {
208 if (max_variations_[i] <= slack)
continue;
210 const IntegerVariable
var = vars_[i];
211 const IntegerValue
coeff = coeffs_[i];
212 const IntegerValue div = slack /
coeff;
213 const IntegerValue new_ub = integer_trail_->
LowerBound(
var) + div;
214 const IntegerValue propagation_slack = (div + 1) *
coeff - slack - 1;
217 [
this, propagation_slack](
219 std::vector<Literal>* literal_reason,
220 std::vector<int>* trail_indices_reason) {
221 *literal_reason = literal_reason_;
222 trail_indices_reason->clear();
223 reason_coeffs_.clear();
224 const int size = vars_.size();
225 for (int i = 0; i < size; ++i) {
226 const IntegerVariable var = vars_[i];
227 if (PositiveVariable(var) == PositiveVariable(i_lit.var)) {
231 integer_trail_->FindTrailIndexOfVarBefore(var, trail_index);
233 trail_indices_reason->push_back(index);
234 if (propagation_slack > 0) {
235 reason_coeffs_.push_back(coeffs_[i]);
239 if (propagation_slack > 0) {
241 propagation_slack, reason_coeffs_, trail_indices_reason);
251bool IntegerSumLE::PropagateAtLevelZero() {
254 if (!enforcement_literals_.empty())
return true;
257 IntegerValue min_activity = IntegerValue(0);
258 const int num_vars =
vars_.size();
259 for (
int i = 0; i < num_vars; ++i) {
260 const IntegerVariable
var =
vars_[i];
261 const IntegerValue
coeff = coeffs_[i];
262 const IntegerValue lb = integer_trail_->LevelZeroLowerBound(
var);
263 const IntegerValue ub = integer_trail_->LevelZeroUpperBound(
var);
264 max_variations_[i] = (ub - lb) *
coeff;
265 min_activity += lb *
coeff;
267 time_limit_->AdvanceDeterministicTime(
static_cast<double>(num_vars * 1e-9));
270 const IntegerValue slack = upper_bound_ - min_activity;
272 return integer_trail_->ReportConflict({}, {});
277 for (
int i = 0; i < num_vars; ++i) {
278 if (max_variations_[i] <= slack)
continue;
280 const IntegerVariable
var =
vars_[i];
281 const IntegerValue
coeff = coeffs_[i];
282 const IntegerValue div = slack /
coeff;
283 const IntegerValue new_ub = integer_trail_->LevelZeroLowerBound(
var) + div;
294 is_registered_ =
true;
295 const int id = watcher->
Register(
this);
296 for (
const IntegerVariable&
var :
vars_) {
309LevelZeroEquality::LevelZeroEquality(IntegerVariable target,
310 const std::vector<IntegerVariable>& vars,
311 const std::vector<IntegerValue>& coeffs,
319 const int id = watcher->
Register(
this);
320 watcher->SetPropagatorPriority(
id, 2);
321 watcher->WatchIntegerVariable(target,
id);
322 for (
const IntegerVariable&
var : vars_) {
323 watcher->WatchIntegerVariable(
var,
id);
341 for (
int i = 0; i < vars_.size(); ++i) {
342 if (integer_trail_->
IsFixed(vars_[i])) {
343 sum += coeffs_[i] * integer_trail_->
LowerBound(vars_[i]);
349 if (gcd == 0)
return true;
352 VLOG(1) <<
"Objective gcd: " << gcd;
355 gcd_ = IntegerValue(gcd);
357 const IntegerValue lb = integer_trail_->
LowerBound(target_);
359 if (lb_remainder != 0) {
366 const IntegerValue ub = integer_trail_->
UpperBound(target_);
367 const IntegerValue ub_remainder =
369 if (ub_remainder != 0) {
379 IntegerVariable min_var,
381 :
vars_(vars), min_var_(min_var), integer_trail_(integer_trail) {}
384 if (vars_.empty())
return true;
390 const IntegerValue current_min_ub = integer_trail_->
UpperBound(min_var_);
391 int num_intervals_that_can_be_min = 0;
392 int last_possible_min_interval = 0;
395 for (
int i = 0; i < vars_.size(); ++i) {
396 const IntegerValue lb = integer_trail_->
LowerBound(vars_[i]);
398 if (lb <= current_min_ub) {
399 ++num_intervals_that_can_be_min;
400 last_possible_min_interval = i;
406 integer_reason_.clear();
407 for (
const IntegerVariable
var : vars_) {
411 {}, integer_reason_)) {
417 if (num_intervals_that_can_be_min == 1) {
418 const IntegerValue ub_of_only_candidate =
419 integer_trail_->
UpperBound(vars_[last_possible_min_interval]);
420 if (current_min_ub < ub_of_only_candidate) {
421 integer_reason_.clear();
425 integer_reason_.push_back(min_ub_literal);
426 for (
const IntegerVariable
var : vars_) {
427 if (
var ==
vars_[last_possible_min_interval])
continue;
428 integer_reason_.push_back(
434 {}, integer_reason_)) {
446 if (num_intervals_that_can_be_min == 0) {
447 integer_reason_.clear();
450 integer_reason_.push_back(min_ub_literal);
451 for (
const IntegerVariable
var : vars_) {
452 integer_reason_.push_back(
462 const int id = watcher->
Register(
this);
463 for (
const IntegerVariable&
var : vars_) {
476bool LinMinPropagator::PropagateLinearUpperBound(
477 const std::vector<IntegerVariable>& vars,
478 const std::vector<IntegerValue>& coeffs,
const IntegerValue
upper_bound) {
479 IntegerValue sum_lb = IntegerValue(0);
480 const int num_vars = vars.size();
481 std::vector<IntegerValue> max_variations;
482 for (
int i = 0; i < num_vars; ++i) {
483 const IntegerVariable
var = vars[i];
484 const IntegerValue
coeff = coeffs[i];
489 max_variations.push_back((ub - lb) *
coeff);
490 sum_lb += lb *
coeff;
494 static_cast<double>(num_vars) * 1e-9);
498 std::vector<IntegerLiteral> linear_sum_reason;
499 std::vector<IntegerValue> reason_coeffs;
500 for (
int i = 0; i < num_vars; ++i) {
501 const IntegerVariable
var = vars[i];
504 reason_coeffs.push_back(coeffs[i]);
511 std::vector<IntegerLiteral> local_reason =
512 integer_reason_for_unique_candidate_;
513 local_reason.insert(local_reason.end(), linear_sum_reason.begin(),
514 linear_sum_reason.end());
520 for (
int i = 0; i < num_vars; ++i) {
521 if (max_variations[i] <= slack)
continue;
523 const IntegerVariable
var = vars[i];
524 const IntegerValue
coeff = coeffs[i];
525 const IntegerValue div = slack /
coeff;
526 const IntegerValue new_ub = integer_trail_->
LowerBound(
var) + div;
528 const IntegerValue propagation_slack = (div + 1) *
coeff - slack - 1;
531 [
this, &vars, &coeffs, propagation_slack](
532 IntegerLiteral i_lit,
int trail_index,
533 std::vector<Literal>* literal_reason,
534 std::vector<int>* trail_indices_reason) {
535 literal_reason->clear();
536 trail_indices_reason->clear();
537 std::vector<IntegerValue> reason_coeffs;
538 const int size = vars.size();
539 for (
int i = 0; i < size; ++i) {
540 const IntegerVariable
var = vars[i];
547 trail_indices_reason->push_back(
index);
548 if (propagation_slack > 0) {
549 reason_coeffs.push_back(coeffs[i]);
553 if (propagation_slack > 0) {
555 propagation_slack, reason_coeffs, trail_indices_reason);
558 for (IntegerLiteral reason_lit :
559 integer_reason_for_unique_candidate_) {
561 reason_lit.var, trail_index);
563 trail_indices_reason->push_back(
index);
574 if (exprs_.empty())
return true;
578 const IntegerValue current_min_ub = integer_trail_->
UpperBound(min_var_);
579 int num_intervals_that_can_be_min = 0;
580 int last_possible_min_interval = 0;
584 for (
int i = 0; i < exprs_.size(); ++i) {
586 expr_lbs_.push_back(lb);
587 min_of_linear_expression_lb =
std::min(min_of_linear_expression_lb, lb);
588 if (lb <= current_min_ub) {
589 ++num_intervals_that_can_be_min;
590 last_possible_min_interval = i;
598 if (min_of_linear_expression_lb > current_min_ub) {
599 min_of_linear_expression_lb = current_min_ub + 1;
601 if (min_of_linear_expression_lb > integer_trail_->
LowerBound(min_var_)) {
602 std::vector<IntegerLiteral> local_reason;
603 for (
int i = 0; i < exprs_.size(); ++i) {
604 const IntegerValue slack = expr_lbs_[i] - min_of_linear_expression_lb;
606 exprs_[i].vars, &local_reason);
609 min_var_, min_of_linear_expression_lb),
619 if (num_intervals_that_can_be_min == 1) {
620 const IntegerValue ub_of_only_candidate =
622 if (current_min_ub < ub_of_only_candidate) {
625 if (rev_unique_candidate_ == 0) {
626 integer_reason_for_unique_candidate_.clear();
630 integer_reason_for_unique_candidate_.push_back(
632 for (
int i = 0; i < exprs_.size(); ++i) {
633 if (i == last_possible_min_interval)
continue;
634 const IntegerValue slack = expr_lbs_[i] - (current_min_ub + 1);
636 slack, exprs_[i].coeffs, exprs_[i].vars,
637 &integer_reason_for_unique_candidate_);
639 rev_unique_candidate_ = 1;
642 return PropagateLinearUpperBound(
643 exprs_[last_possible_min_interval].vars,
644 exprs_[last_possible_min_interval].coeffs,
645 current_min_ub - exprs_[last_possible_min_interval].offset);
653 const int id = watcher->
Register(
this);
655 for (
int i = 0; i < expr.vars.size(); ++i) {
656 const IntegerVariable&
var = expr.vars[i];
657 const IntegerValue
coeff = expr.coeffs[i];
672 : a_(
a), b_(
b), p_(p), integer_trail_(integer_trail) {}
675bool ProductPropagator::CanonicalizeCases() {
689 p_.
GreaterOrEqual(0), {a_.GreaterOrEqual(0), b_.GreaterOrEqual(0)});
715bool ProductPropagator::PropagateWhenAllNonNegative() {
716 const IntegerValue max_a = integer_trail_->
UpperBound(a_);
717 const IntegerValue max_b = integer_trail_->
UpperBound(b_);
718 const IntegerValue new_max(
CapProd(max_a.value(), max_b.value()));
719 if (new_max < integer_trail_->
UpperBound(p_)) {
722 {integer_trail_->UpperBoundAsLiteral(a_),
723 integer_trail_->UpperBoundAsLiteral(b_), a_.GreaterOrEqual(0),
724 b_.GreaterOrEqual(0)})) {
729 const IntegerValue min_a = integer_trail_->
LowerBound(a_);
730 const IntegerValue min_b = integer_trail_->
LowerBound(b_);
731 const IntegerValue new_min(
CapProd(min_a.value(), min_b.value()));
732 if (new_min > integer_trail_->
LowerBound(p_)) {
735 {integer_trail_->LowerBoundAsLiteral(a_),
736 integer_trail_->LowerBoundAsLiteral(b_)})) {
741 for (
int i = 0; i < 2; ++i) {
742 const AffineExpression
a = i == 0 ? a_ : b_;
743 const AffineExpression
b = i == 0 ? b_ : a_;
744 const IntegerValue max_a = integer_trail_->
UpperBound(
a);
745 const IntegerValue min_b = integer_trail_->
LowerBound(
b);
746 const IntegerValue min_p = integer_trail_->
LowerBound(p_);
747 const IntegerValue max_p = integer_trail_->
UpperBound(p_);
748 const IntegerValue prod(
CapProd(max_a.value(), min_b.value()));
756 }
else if (prod < min_p) {
773bool ProductPropagator::PropagateMaxOnPositiveProduct(AffineExpression
a,
776 IntegerValue max_p) {
777 const IntegerValue max_a = integer_trail_->
UpperBound(
a);
778 if (max_a <= 0)
return true;
781 if (max_a >= min_p) {
784 a.LowerOrEqual(max_p),
785 {p_.LowerOrEqual(max_p), p_.GreaterOrEqual(1)})) {
792 const IntegerValue min_pos_b =
CeilRatio(min_p, max_a);
795 b.LowerOrEqual(0), {integer_trail_->LowerBoundAsLiteral(p_),
796 integer_trail_->UpperBoundAsLiteral(a),
797 integer_trail_->UpperBoundAsLiteral(b)})) {
803 const IntegerValue new_max_a =
FloorRatio(max_p, min_pos_b);
806 a.LowerOrEqual(new_max_a),
807 {integer_trail_->LowerBoundAsLiteral(p_),
808 integer_trail_->UpperBoundAsLiteral(a),
809 integer_trail_->UpperBoundAsLiteral(p_)})) {
817 if (!CanonicalizeCases())
return false;
821 const int64_t min_a = integer_trail_->
LowerBound(a_).value();
822 const int64_t min_b = integer_trail_->
LowerBound(b_).value();
823 if (min_a >= 0 && min_b >= 0) {
826 return PropagateWhenAllNonNegative();
835 const int64_t max_a = integer_trail_->
UpperBound(a_).value();
836 const int64_t max_b = integer_trail_->
UpperBound(b_).value();
837 const IntegerValue p1(
CapProd(max_a, max_b));
838 const IntegerValue p2(
CapProd(max_a, min_b));
839 const IntegerValue p3(
CapProd(min_a, max_b));
840 const IntegerValue p4(
CapProd(min_a, min_b));
841 const IntegerValue new_max_p =
std::max({p1, p2, p3, p4});
842 if (new_max_p < integer_trail_->
UpperBound(p_)) {
845 {integer_trail_->LowerBoundAsLiteral(a_),
846 integer_trail_->LowerBoundAsLiteral(b_),
847 integer_trail_->UpperBoundAsLiteral(a_),
848 integer_trail_->UpperBoundAsLiteral(b_)})) {
852 const IntegerValue new_min_p =
std::min({p1, p2, p3, p4});
853 if (new_min_p > integer_trail_->
LowerBound(p_)) {
856 {integer_trail_->LowerBoundAsLiteral(a_),
857 integer_trail_->LowerBoundAsLiteral(b_),
858 integer_trail_->UpperBoundAsLiteral(a_),
859 integer_trail_->UpperBoundAsLiteral(b_)})) {
865 const IntegerValue min_p = integer_trail_->
LowerBound(p_);
866 const IntegerValue max_p = integer_trail_->
UpperBound(p_);
869 const bool zero_is_possible = min_p <= 0;
870 if (!zero_is_possible) {
874 {p_.GreaterOrEqual(1), a_.GreaterOrEqual(0)})) {
881 {p_.GreaterOrEqual(1), b_.GreaterOrEqual(0)})) {
888 b_.
GreaterOrEqual(1), {a_.GreaterOrEqual(0), p_.GreaterOrEqual(1)});
893 a_.
GreaterOrEqual(1), {b_.GreaterOrEqual(0), p_.GreaterOrEqual(1)});
897 for (
int i = 0; i < 2; ++i) {
901 const IntegerValue max_b = integer_trail_->
UpperBound(
b);
902 const IntegerValue min_b = integer_trail_->
LowerBound(
b);
906 if (zero_is_possible && min_b <= 0)
continue;
909 if (min_b < 0 && max_b > 0) {
914 if (!PropagateMaxOnPositiveProduct(
a,
b, min_p, max_p)) {
917 if (!PropagateMaxOnPositiveProduct(
a.Negated(),
b.Negated(), min_p,
926 if (min_b <= 0)
continue;
929 a.GreaterOrEqual(0), {p_.GreaterOrEqual(0), b.GreaterOrEqual(1)});
933 a.LowerOrEqual(0), {p_.LowerOrEqual(0), b.GreaterOrEqual(1)});
937 const IntegerValue new_max_a =
FloorRatio(max_p, min_b);
940 a.LowerOrEqual(new_max_a),
941 {integer_trail_->UpperBoundAsLiteral(p_),
942 integer_trail_->LowerBoundAsLiteral(b)})) {
946 const IntegerValue new_min_a =
CeilRatio(min_p, min_b);
949 a.GreaterOrEqual(new_min_a),
950 {integer_trail_->LowerBoundAsLiteral(p_),
951 integer_trail_->LowerBoundAsLiteral(b)})) {
961 const int id = watcher->
Register(
this);
970 : x_(x), s_(s), integer_trail_(integer_trail) {
977 const IntegerValue min_x = integer_trail_->
LowerBound(x_);
978 const IntegerValue min_s = integer_trail_->
LowerBound(s_);
979 const IntegerValue min_x_square(
CapProd(min_x.value(), min_x.value()));
980 if (min_x_square > min_s) {
982 {x_.GreaterOrEqual(min_x)})) {
985 }
else if (min_x_square < min_s) {
989 {s_.GreaterOrEqual((new_min - 1) * (new_min - 1) + 1)})) {
994 const IntegerValue max_x = integer_trail_->
UpperBound(x_);
995 const IntegerValue max_s = integer_trail_->
UpperBound(s_);
996 const IntegerValue max_x_square(
CapProd(max_x.value(), max_x.value()));
997 if (max_x_square < max_s) {
999 {x_.LowerOrEqual(max_x)})) {
1002 }
else if (max_x_square > max_s) {
1006 {s_.LowerOrEqual(IntegerValue(CapProd(new_max.value() + 1,
1007 new_max.value() + 1)) -
1017 const int id = watcher->
Register(
this);
1030 negated_num_(num.Negated()),
1031 negated_div_(div.Negated()),
1032 integer_trail_(integer_trail) {
1038 if (!PropagateSigns())
return false;
1042 !PropagateUpperBounds(num_, denom_, div_)) {
1046 if (integer_trail_->
UpperBound(negated_num_) >= 0 &&
1047 integer_trail_->
UpperBound(negated_div_) >= 0 &&
1048 !PropagateUpperBounds(negated_num_, denom_, negated_div_)) {
1054 return PropagatePositiveDomains(num_, denom_, div_);
1059 return PropagatePositiveDomains(negated_num_, denom_, negated_div_);
1065bool DivisionPropagator::PropagateSigns() {
1066 const IntegerValue min_num = integer_trail_->
LowerBound(num_);
1067 const IntegerValue max_num = integer_trail_->
UpperBound(num_);
1068 const IntegerValue min_div = integer_trail_->
LowerBound(div_);
1069 const IntegerValue max_div = integer_trail_->
UpperBound(div_);
1072 if (min_num >= 0 && min_div < 0) {
1074 {num_.GreaterOrEqual(0)})) {
1080 if (min_num <= 0 && min_div > 0) {
1082 {div_.GreaterOrEqual(1)})) {
1088 if (max_num <= 0 && max_div > 0) {
1090 {num_.LowerOrEqual(0)})) {
1096 if (max_num >= 0 && max_div < 0) {
1098 {div_.LowerOrEqual(-1)})) {
1106bool DivisionPropagator::PropagateUpperBounds(AffineExpression num,
1107 AffineExpression denom,
1108 AffineExpression div) {
1109 const IntegerValue max_num = integer_trail_->
UpperBound(num);
1110 const IntegerValue min_denom = integer_trail_->
LowerBound(denom);
1111 const IntegerValue max_denom = integer_trail_->
UpperBound(denom);
1112 const IntegerValue max_div = integer_trail_->
UpperBound(div);
1114 const IntegerValue new_max_div = max_num / min_denom;
1115 if (max_div > new_max_div) {
1117 div.LowerOrEqual(new_max_div),
1118 {integer_trail_->UpperBoundAsLiteral(num),
1119 integer_trail_->LowerBoundAsLiteral(denom)})) {
1127 const IntegerValue new_max_num =
1128 IntegerValue(
CapAdd(
CapProd(max_div.value() + 1, max_denom.value()), -1));
1129 if (max_num > new_max_num) {
1131 num.LowerOrEqual(new_max_num),
1132 {integer_trail_->UpperBoundAsLiteral(denom),
1133 integer_trail_->UpperBoundAsLiteral(div)})) {
1141bool DivisionPropagator::PropagatePositiveDomains(AffineExpression num,
1142 AffineExpression denom,
1143 AffineExpression div) {
1144 const IntegerValue min_num = integer_trail_->
LowerBound(num);
1145 const IntegerValue max_num = integer_trail_->
UpperBound(num);
1146 const IntegerValue min_denom = integer_trail_->
LowerBound(denom);
1147 const IntegerValue max_denom = integer_trail_->
UpperBound(denom);
1148 const IntegerValue min_div = integer_trail_->
LowerBound(div);
1149 const IntegerValue max_div = integer_trail_->
UpperBound(div);
1151 const IntegerValue new_min_div = min_num / max_denom;
1152 if (min_div < new_min_div) {
1154 div.GreaterOrEqual(new_min_div),
1155 {integer_trail_->LowerBoundAsLiteral(num),
1156 integer_trail_->UpperBoundAsLiteral(denom)})) {
1164 const IntegerValue new_min_num =
1165 IntegerValue(
CapProd(min_denom.value(), min_div.value()));
1166 if (min_num < new_min_num) {
1168 num.GreaterOrEqual(new_min_num),
1169 {integer_trail_->LowerBoundAsLiteral(denom),
1170 integer_trail_->LowerBoundAsLiteral(div)})) {
1180 const IntegerValue new_max_denom = max_num / min_div;
1181 if (max_denom > new_max_denom) {
1183 denom.LowerOrEqual(new_max_denom),
1184 {integer_trail_->UpperBoundAsLiteral(num), num.GreaterOrEqual(0),
1185 integer_trail_->LowerBoundAsLiteral(div)})) {
1193 const IntegerValue new_min_denom =
CeilRatio(min_num + 1, max_div + 1);
1194 if (min_denom < new_min_denom) {
1195 if (!integer_trail_->
SafeEnqueue(denom.GreaterOrEqual(new_min_denom),
1196 {integer_trail_->LowerBoundAsLiteral(num),
1197 integer_trail_->UpperBoundAsLiteral(div),
1198 div.GreaterOrEqual(0)})) {
1207 const int id = watcher->
Register(
this);
1218 : a_(
a), b_(
b), c_(c), integer_trail_(integer_trail) {
1223 const IntegerValue min_a = integer_trail_->
LowerBound(a_);
1224 const IntegerValue max_a = integer_trail_->
UpperBound(a_);
1225 IntegerValue min_c = integer_trail_->
LowerBound(c_);
1226 IntegerValue max_c = integer_trail_->
UpperBound(c_);
1228 if (max_a / b_ < max_c) {
1232 {integer_trail_->UpperBoundAsLiteral(a_)})) {
1235 }
else if (max_a / b_ > max_c) {
1236 const IntegerValue new_max_a =
1237 max_c >= 0 ? max_c * b_ + b_ - 1
1238 : IntegerValue(
CapProd(max_c.value(), b_.value()));
1242 {integer_trail_->UpperBoundAsLiteral(c_)})) {
1247 if (min_a / b_ > min_c) {
1251 {integer_trail_->LowerBoundAsLiteral(a_)})) {
1254 }
else if (min_a / b_ < min_c) {
1255 const IntegerValue new_min_a =
1256 min_c > 0 ? IntegerValue(
CapProd(min_c.value(), b_.value()))
1257 : min_c * b_ - b_ + 1;
1261 {integer_trail_->LowerBoundAsLiteral(c_)})) {
1270 const int id = watcher->
Register(
this);
1279 :
expr_(expr), mod_(mod), target_(target), integer_trail_(integer_trail) {
1284 if (!PropagateSignsAndTargetRange())
return false;
1285 if (!PropagateOuterBounds())
return false;
1287 if (integer_trail_->
LowerBound(expr_) >= 0) {
1288 if (!PropagateBoundsWhenExprIsPositive(expr_, target_))
return false;
1289 }
else if (integer_trail_->
UpperBound(expr_) <= 0) {
1290 if (!PropagateBoundsWhenExprIsPositive(expr_.
Negated(),
1299bool FixedModuloPropagator::PropagateSignsAndTargetRange() {
1301 if (integer_trail_->
UpperBound(target_) >= mod_) {
1307 if (integer_trail_->
LowerBound(target_) <= -mod_) {
1314 if (integer_trail_->
LowerBound(expr_) >= 0 &&
1317 {expr_.GreaterOrEqual(0)})) {
1322 if (integer_trail_->
UpperBound(expr_) <= 0 &&
1325 {expr_.LowerOrEqual(0)})) {
1333bool FixedModuloPropagator::PropagateOuterBounds() {
1334 const IntegerValue min_expr = integer_trail_->
LowerBound(expr_);
1335 const IntegerValue max_expr = integer_trail_->
UpperBound(expr_);
1336 const IntegerValue min_target = integer_trail_->
LowerBound(target_);
1337 const IntegerValue max_target = integer_trail_->
UpperBound(target_);
1339 if (max_expr % mod_ > max_target) {
1341 expr_.
LowerOrEqual((max_expr / mod_) * mod_ + max_target),
1342 {integer_trail_->UpperBoundAsLiteral(target_),
1343 integer_trail_->UpperBoundAsLiteral(expr_)})) {
1348 if (min_expr % mod_ < min_target) {
1351 {integer_trail_->LowerBoundAsLiteral(expr_),
1352 integer_trail_->LowerBoundAsLiteral(target_)})) {
1357 if (min_expr / mod_ == max_expr / mod_) {
1358 if (min_target < min_expr % mod_) {
1361 {integer_trail_->LowerBoundAsLiteral(target_),
1362 integer_trail_->UpperBoundAsLiteral(target_),
1363 integer_trail_->LowerBoundAsLiteral(expr_),
1364 integer_trail_->UpperBoundAsLiteral(expr_)})) {
1369 if (max_target > max_expr % mod_) {
1371 target_.
LowerOrEqual(max_expr - (max_expr / mod_) * mod_),
1372 {integer_trail_->LowerBoundAsLiteral(target_),
1373 integer_trail_->UpperBoundAsLiteral(target_),
1374 integer_trail_->LowerBoundAsLiteral(expr_),
1375 integer_trail_->UpperBoundAsLiteral(expr_)})) {
1379 }
else if (min_expr / mod_ == 0 && min_target < 0) {
1381 if (min_target < min_expr) {
1384 {integer_trail_->LowerBoundAsLiteral(target_),
1385 integer_trail_->LowerBoundAsLiteral(expr_)})) {
1389 }
else if (max_expr / mod_ == 0 && max_target > 0) {
1391 if (max_target > max_expr) {
1394 {integer_trail_->UpperBoundAsLiteral(target_),
1395 integer_trail_->UpperBoundAsLiteral(expr_)})) {
1404bool FixedModuloPropagator::PropagateBoundsWhenExprIsPositive(
1405 AffineExpression expr, AffineExpression target) {
1406 const IntegerValue min_target = integer_trail_->
LowerBound(target);
1408 const IntegerValue max_target = integer_trail_->
UpperBound(target);
1412 if (min_target == 0 && max_target == mod_ - 1)
return true;
1414 const IntegerValue min_expr = integer_trail_->
LowerBound(expr);
1415 const IntegerValue max_expr = integer_trail_->
UpperBound(expr);
1417 if (max_expr % mod_ < min_target) {
1420 expr.LowerOrEqual((max_expr / mod_ - 1) * mod_ + max_target),
1421 {integer_trail_->UpperBoundAsLiteral(expr),
1422 integer_trail_->LowerBoundAsLiteral(target),
1423 integer_trail_->UpperBoundAsLiteral(target)})) {
1428 if (min_expr % mod_ > max_target) {
1431 expr.GreaterOrEqual((min_expr / mod_ + 1) * mod_ + min_target),
1432 {integer_trail_->LowerBoundAsLiteral(target),
1433 integer_trail_->UpperBoundAsLiteral(target),
1434 integer_trail_->LowerBoundAsLiteral(expr)})) {
1443 const int id = watcher->
Register(
this);
1450 const std::vector<Literal>& selectors,
1451 const std::vector<IntegerValue>& values) {
1456 CHECK(!values.empty());
1457 CHECK_EQ(values.size(), selectors.size());
1458 std::vector<int64_t> unique_values;
1459 absl::flat_hash_map<int64_t, std::vector<Literal>> value_to_selector;
1460 for (
int i = 0; i < values.size(); ++i) {
1461 unique_values.push_back(values[i].
value());
1462 value_to_selector[values[i].value()].push_back(selectors[i]);
1467 if (unique_values.size() == 1) {
1474 for (
const int64_t v : unique_values) {
1475 const std::vector<Literal>& selectors = value_to_selector[v];
1476 if (selectors.size() == 1) {
1477 encoder->AssociateToIntegerEqualValue(selectors[0],
var,
1482 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)
constexpr IntegerValue kMinIntegerValue(-kMaxIntegerValue)
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)
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)