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);
66void 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]);
80 IntegerLiteral integer_literal, IntegerVariable target_var)
const {
82 bool literal_var_present =
false;
83 bool literal_var_present_positively =
false;
84 IntegerValue var_coeff;
86 bool target_var_present_negatively =
false;
87 IntegerValue target_coeff;
90 IntegerValue implied_lb(-upper_bound_);
91 for (
int i = 0; i < vars_.size(); ++i) {
92 const IntegerVariable
var = vars_[i];
93 const IntegerValue coeff = coeffs_[i];
96 target_var_present_negatively =
true;
101 implied_lb += coeff * lb;
104 literal_var_present =
true;
105 literal_var_present_positively = (
var == integer_literal.
var);
108 if (!literal_var_present || !target_var_present_negatively) {
113 if (literal_var_present_positively) {
118 IntegerValue(0), integer_literal.
bound -
120 return {
CeilRatio(implied_lb, target_coeff),
121 CeilRatio(implied_lb + var_coeff * diff, target_coeff)};
127 IntegerValue(0), integer_trail_->
UpperBound(integer_literal.
var) -
128 integer_literal.
bound + 1);
129 return {
CeilRatio(implied_lb + var_coeff * diff, target_coeff),
137 int num_unassigned_enforcement_literal = 0;
142 ++num_unassigned_enforcement_literal;
143 unique_unnasigned_literal =
literal.Index();
149 if (num_unassigned_enforcement_literal > 1)
return true;
152 if (is_registered_) {
153 rev_integer_value_repository_->
SaveState(&rev_lb_fixed_vars_);
155 rev_num_fixed_vars_ = 0;
156 rev_lb_fixed_vars_ = 0;
160 IntegerValue lb_unfixed_vars = IntegerValue(0);
161 const int num_vars = vars_.size();
162 for (
int i = rev_num_fixed_vars_; i < num_vars; ++i) {
163 const IntegerVariable
var = vars_[i];
164 const IntegerValue coeff = coeffs_[i];
168 max_variations_[i] = (ub - lb) * coeff;
169 lb_unfixed_vars += lb * coeff;
172 std::swap(vars_[i], vars_[rev_num_fixed_vars_]);
173 std::swap(coeffs_[i], coeffs_[rev_num_fixed_vars_]);
174 std::swap(max_variations_[i], max_variations_[rev_num_fixed_vars_]);
175 rev_num_fixed_vars_++;
176 rev_lb_fixed_vars_ += lb * coeff;
180 static_cast<double>(num_vars - rev_num_fixed_vars_) * 1e-9);
183 const IntegerValue slack =
184 upper_bound_ - (rev_lb_fixed_vars_ + lb_unfixed_vars);
190 if (num_unassigned_enforcement_literal == 1) {
193 std::vector<Literal> tmp = literal_reason_;
194 tmp.erase(std::find(tmp.begin(), tmp.end(), to_propagate));
195 integer_trail_->
EnqueueLiteral(to_propagate, tmp, integer_reason_);
198 return integer_trail_->
ReportConflict(literal_reason_, integer_reason_);
202 if (num_unassigned_enforcement_literal > 0)
return true;
206 for (
int i = rev_num_fixed_vars_; i < num_vars; ++i) {
207 if (max_variations_[i] <= slack)
continue;
209 const IntegerVariable
var = vars_[i];
210 const IntegerValue coeff = coeffs_[i];
211 const IntegerValue div = slack / coeff;
212 const IntegerValue new_ub = integer_trail_->
LowerBound(
var) + div;
213 const IntegerValue propagation_slack = (div + 1) * coeff - slack - 1;
216 [
this, propagation_slack](
218 std::vector<Literal>* literal_reason,
219 std::vector<int>* trail_indices_reason) {
220 *literal_reason = literal_reason_;
221 trail_indices_reason->clear();
222 reason_coeffs_.clear();
223 const int size = vars_.size();
224 for (int i = 0; i < size; ++i) {
225 const IntegerVariable var = vars_[i];
226 if (PositiveVariable(var) == PositiveVariable(i_lit.var)) {
230 integer_trail_->FindTrailIndexOfVarBefore(var, trail_index);
232 trail_indices_reason->push_back(index);
233 if (propagation_slack > 0) {
234 reason_coeffs_.push_back(coeffs_[i]);
238 if (propagation_slack > 0) {
240 propagation_slack, reason_coeffs_, trail_indices_reason);
250bool IntegerSumLE::PropagateAtLevelZero() {
253 if (!enforcement_literals_.empty())
return true;
256 IntegerValue min_activity = IntegerValue(0);
257 const int num_vars =
vars_.size();
258 for (
int i = 0; i < num_vars; ++i) {
259 const IntegerVariable
var =
vars_[i];
260 const IntegerValue coeff = coeffs_[i];
261 const IntegerValue lb = integer_trail_->LevelZeroLowerBound(
var);
262 const IntegerValue ub = integer_trail_->LevelZeroUpperBound(
var);
263 max_variations_[i] = (ub - lb) * coeff;
264 min_activity += lb * coeff;
266 time_limit_->AdvanceDeterministicTime(
static_cast<double>(num_vars * 1e-9));
269 const IntegerValue slack = upper_bound_ - min_activity;
271 return integer_trail_->ReportConflict({}, {});
276 for (
int i = 0; i < num_vars; ++i) {
277 if (max_variations_[i] <= slack)
continue;
279 const IntegerVariable
var =
vars_[i];
280 const IntegerValue coeff = coeffs_[i];
281 const IntegerValue div = slack / coeff;
282 const IntegerValue new_ub = integer_trail_->LevelZeroLowerBound(
var) + div;
293 is_registered_ =
true;
294 const int id = watcher->
Register(
this);
295 for (
const IntegerVariable&
var :
vars_) {
308LevelZeroEquality::LevelZeroEquality(IntegerVariable target,
309 const std::vector<IntegerVariable>& vars,
310 const std::vector<IntegerValue>& coeffs,
318 const int id = watcher->
Register(
this);
319 watcher->SetPropagatorPriority(
id, 2);
320 watcher->WatchIntegerVariable(target,
id);
321 for (
const IntegerVariable&
var : vars_) {
322 watcher->WatchIntegerVariable(
var,
id);
340 for (
int i = 0; i < vars_.size(); ++i) {
341 if (integer_trail_->
IsFixed(vars_[i])) {
342 sum += coeffs_[i] * integer_trail_->
LowerBound(vars_[i]);
348 if (gcd == 0)
return true;
351 VLOG(1) <<
"Objective gcd: " << gcd;
354 gcd_ = IntegerValue(gcd);
356 const IntegerValue lb = integer_trail_->
LowerBound(target_);
358 if (lb_remainder != 0) {
365 const IntegerValue ub = integer_trail_->
UpperBound(target_);
366 const IntegerValue ub_remainder =
368 if (ub_remainder != 0) {
378 IntegerVariable min_var,
380 :
vars_(vars), min_var_(min_var), integer_trail_(integer_trail) {}
383 if (vars_.empty())
return true;
389 const IntegerValue current_min_ub = integer_trail_->
UpperBound(min_var_);
390 int num_intervals_that_can_be_min = 0;
391 int last_possible_min_interval = 0;
394 for (
int i = 0; i < vars_.size(); ++i) {
395 const IntegerValue lb = integer_trail_->
LowerBound(vars_[i]);
397 if (lb <= current_min_ub) {
398 ++num_intervals_that_can_be_min;
399 last_possible_min_interval = i;
405 integer_reason_.clear();
406 for (
const IntegerVariable
var : vars_) {
410 {}, integer_reason_)) {
416 if (num_intervals_that_can_be_min == 1) {
417 const IntegerValue ub_of_only_candidate =
418 integer_trail_->
UpperBound(vars_[last_possible_min_interval]);
419 if (current_min_ub < ub_of_only_candidate) {
420 integer_reason_.clear();
424 integer_reason_.push_back(min_ub_literal);
425 for (
const IntegerVariable
var : vars_) {
426 if (
var ==
vars_[last_possible_min_interval])
continue;
427 integer_reason_.push_back(
433 {}, integer_reason_)) {
445 if (num_intervals_that_can_be_min == 0) {
446 integer_reason_.clear();
449 integer_reason_.push_back(min_ub_literal);
450 for (
const IntegerVariable
var : vars_) {
451 integer_reason_.push_back(
461 const int id = watcher->
Register(
this);
462 for (
const IntegerVariable&
var : vars_) {
475bool LinMinPropagator::PropagateLinearUpperBound(
476 const std::vector<IntegerVariable>& vars,
477 const std::vector<IntegerValue>& coeffs,
const IntegerValue
upper_bound) {
478 IntegerValue sum_lb = IntegerValue(0);
479 const int num_vars = vars.size();
480 std::vector<IntegerValue> max_variations;
481 for (
int i = 0; i < num_vars; ++i) {
482 const IntegerVariable
var = vars[i];
483 const IntegerValue coeff = coeffs[i];
488 max_variations.push_back((ub - lb) * coeff);
489 sum_lb += lb * coeff;
493 static_cast<double>(num_vars) * 1e-9);
497 std::vector<IntegerLiteral> linear_sum_reason;
498 std::vector<IntegerValue> reason_coeffs;
499 for (
int i = 0; i < num_vars; ++i) {
500 const IntegerVariable
var = vars[i];
503 reason_coeffs.push_back(coeffs[i]);
510 std::vector<IntegerLiteral> local_reason =
511 integer_reason_for_unique_candidate_;
512 local_reason.insert(local_reason.end(), linear_sum_reason.begin(),
513 linear_sum_reason.end());
519 for (
int i = 0; i < num_vars; ++i) {
520 if (max_variations[i] <= slack)
continue;
522 const IntegerVariable
var = vars[i];
523 const IntegerValue coeff = coeffs[i];
524 const IntegerValue div = slack / coeff;
525 const IntegerValue new_ub = integer_trail_->
LowerBound(
var) + div;
527 const IntegerValue propagation_slack = (div + 1) * coeff - slack - 1;
530 [
this, &vars, &coeffs, propagation_slack](
531 IntegerLiteral i_lit,
int trail_index,
532 std::vector<Literal>* literal_reason,
533 std::vector<int>* trail_indices_reason) {
534 literal_reason->clear();
535 trail_indices_reason->clear();
536 std::vector<IntegerValue> reason_coeffs;
537 const int size = vars.size();
538 for (
int i = 0; i < size; ++i) {
539 const IntegerVariable
var = vars[i];
546 trail_indices_reason->push_back(
index);
547 if (propagation_slack > 0) {
548 reason_coeffs.push_back(coeffs[i]);
552 if (propagation_slack > 0) {
554 propagation_slack, reason_coeffs, trail_indices_reason);
557 for (IntegerLiteral reason_lit :
558 integer_reason_for_unique_candidate_) {
560 reason_lit.var, trail_index);
562 trail_indices_reason->push_back(
index);
573 if (exprs_.empty())
return true;
577 const IntegerValue current_min_ub = integer_trail_->
UpperBound(min_var_);
578 int num_intervals_that_can_be_min = 0;
579 int last_possible_min_interval = 0;
583 for (
int i = 0; i < exprs_.size(); ++i) {
585 expr_lbs_.push_back(lb);
586 min_of_linear_expression_lb =
std::min(min_of_linear_expression_lb, lb);
587 if (lb <= current_min_ub) {
588 ++num_intervals_that_can_be_min;
589 last_possible_min_interval = i;
597 if (min_of_linear_expression_lb > current_min_ub) {
598 min_of_linear_expression_lb = current_min_ub + 1;
600 if (min_of_linear_expression_lb > integer_trail_->
LowerBound(min_var_)) {
601 std::vector<IntegerLiteral> local_reason;
602 for (
int i = 0; i < exprs_.size(); ++i) {
603 const IntegerValue slack = expr_lbs_[i] - min_of_linear_expression_lb;
605 exprs_[i].vars, &local_reason);
608 min_var_, min_of_linear_expression_lb),
618 if (num_intervals_that_can_be_min == 1) {
619 const IntegerValue ub_of_only_candidate =
621 if (current_min_ub < ub_of_only_candidate) {
624 if (rev_unique_candidate_ == 0) {
625 integer_reason_for_unique_candidate_.clear();
629 integer_reason_for_unique_candidate_.push_back(
631 for (
int i = 0; i < exprs_.size(); ++i) {
632 if (i == last_possible_min_interval)
continue;
633 const IntegerValue slack = expr_lbs_[i] - (current_min_ub + 1);
635 slack, exprs_[i].coeffs, exprs_[i].vars,
636 &integer_reason_for_unique_candidate_);
638 rev_unique_candidate_ = 1;
641 return PropagateLinearUpperBound(
642 exprs_[last_possible_min_interval].vars,
643 exprs_[last_possible_min_interval].coeffs,
644 current_min_ub - exprs_[last_possible_min_interval].offset);
652 const int id = watcher->
Register(
this);
654 for (
int i = 0; i < expr.vars.size(); ++i) {
655 const IntegerVariable&
var = expr.vars[i];
656 const IntegerValue coeff = expr.coeffs[i];
671 : a_(
a), b_(
b), p_(p), integer_trail_(integer_trail) {}
674bool ProductPropagator::CanonicalizeCases() {
688 p_.
GreaterOrEqual(0), {a_.GreaterOrEqual(0), b_.GreaterOrEqual(0)});
714bool ProductPropagator::PropagateWhenAllNonNegative() {
715 const IntegerValue max_a = integer_trail_->
UpperBound(a_);
716 const IntegerValue max_b = integer_trail_->
UpperBound(b_);
717 const IntegerValue new_max(
CapProd(max_a.value(), max_b.value()));
718 if (new_max < integer_trail_->
UpperBound(p_)) {
721 {integer_trail_->UpperBoundAsLiteral(a_),
722 integer_trail_->UpperBoundAsLiteral(b_), a_.GreaterOrEqual(0),
723 b_.GreaterOrEqual(0)})) {
728 const IntegerValue min_a = integer_trail_->
LowerBound(a_);
729 const IntegerValue min_b = integer_trail_->
LowerBound(b_);
730 const IntegerValue new_min(
CapProd(min_a.value(), min_b.value()));
731 if (new_min > integer_trail_->
LowerBound(p_)) {
734 {integer_trail_->LowerBoundAsLiteral(a_),
735 integer_trail_->LowerBoundAsLiteral(b_)})) {
740 for (
int i = 0; i < 2; ++i) {
741 const AffineExpression
a = i == 0 ? a_ : b_;
742 const AffineExpression
b = i == 0 ? b_ : a_;
743 const IntegerValue max_a = integer_trail_->
UpperBound(
a);
744 const IntegerValue min_b = integer_trail_->
LowerBound(
b);
745 const IntegerValue min_p = integer_trail_->
LowerBound(p_);
746 const IntegerValue max_p = integer_trail_->
UpperBound(p_);
747 const IntegerValue prod(
CapProd(max_a.value(), min_b.value()));
755 }
else if (prod < min_p) {
772bool ProductPropagator::PropagateMaxOnPositiveProduct(AffineExpression
a,
775 IntegerValue max_p) {
776 const IntegerValue max_a = integer_trail_->
UpperBound(
a);
777 if (max_a <= 0)
return true;
780 if (max_a >= min_p) {
783 a.LowerOrEqual(max_p),
784 {p_.LowerOrEqual(max_p), p_.GreaterOrEqual(1)})) {
791 const IntegerValue min_pos_b =
CeilRatio(min_p, max_a);
794 b.LowerOrEqual(0), {integer_trail_->LowerBoundAsLiteral(p_),
795 integer_trail_->UpperBoundAsLiteral(a),
796 integer_trail_->UpperBoundAsLiteral(b)})) {
802 const IntegerValue new_max_a =
FloorRatio(max_p, min_pos_b);
805 a.LowerOrEqual(new_max_a),
806 {integer_trail_->LowerBoundAsLiteral(p_),
807 integer_trail_->UpperBoundAsLiteral(a),
808 integer_trail_->UpperBoundAsLiteral(p_)})) {
816 if (!CanonicalizeCases())
return false;
820 const int64_t min_a = integer_trail_->
LowerBound(a_).value();
821 const int64_t min_b = integer_trail_->
LowerBound(b_).value();
822 if (min_a >= 0 && min_b >= 0) {
825 return PropagateWhenAllNonNegative();
834 const int64_t max_a = integer_trail_->
UpperBound(a_).value();
835 const int64_t max_b = integer_trail_->
UpperBound(b_).value();
836 const IntegerValue p1(
CapProd(max_a, max_b));
837 const IntegerValue p2(
CapProd(max_a, min_b));
838 const IntegerValue p3(
CapProd(min_a, max_b));
839 const IntegerValue p4(
CapProd(min_a, min_b));
840 const IntegerValue new_max_p =
std::max({p1, p2, p3, p4});
841 if (new_max_p < integer_trail_->
UpperBound(p_)) {
844 {integer_trail_->LowerBoundAsLiteral(a_),
845 integer_trail_->LowerBoundAsLiteral(b_),
846 integer_trail_->UpperBoundAsLiteral(a_),
847 integer_trail_->UpperBoundAsLiteral(b_)})) {
851 const IntegerValue new_min_p =
std::min({p1, p2, p3, p4});
852 if (new_min_p > integer_trail_->
LowerBound(p_)) {
855 {integer_trail_->LowerBoundAsLiteral(a_),
856 integer_trail_->LowerBoundAsLiteral(b_),
857 integer_trail_->UpperBoundAsLiteral(a_),
858 integer_trail_->UpperBoundAsLiteral(b_)})) {
864 const IntegerValue min_p = integer_trail_->
LowerBound(p_);
865 const IntegerValue max_p = integer_trail_->
UpperBound(p_);
868 const bool zero_is_possible = min_p <= 0;
869 if (!zero_is_possible) {
873 {p_.GreaterOrEqual(1), a_.GreaterOrEqual(0)})) {
880 {p_.GreaterOrEqual(1), b_.GreaterOrEqual(0)})) {
887 b_.
GreaterOrEqual(1), {a_.GreaterOrEqual(0), p_.GreaterOrEqual(1)});
892 a_.
GreaterOrEqual(1), {b_.GreaterOrEqual(0), p_.GreaterOrEqual(1)});
896 for (
int i = 0; i < 2; ++i) {
900 const IntegerValue max_b = integer_trail_->
UpperBound(
b);
901 const IntegerValue min_b = integer_trail_->
LowerBound(
b);
905 if (zero_is_possible && min_b <= 0)
continue;
908 if (min_b < 0 && max_b > 0) {
913 if (!PropagateMaxOnPositiveProduct(
a,
b, min_p, max_p)) {
916 if (!PropagateMaxOnPositiveProduct(
a.Negated(),
b.Negated(), min_p,
925 if (min_b <= 0)
continue;
928 a.GreaterOrEqual(0), {p_.GreaterOrEqual(0), b.GreaterOrEqual(1)});
932 a.LowerOrEqual(0), {p_.LowerOrEqual(0), b.GreaterOrEqual(1)});
936 const IntegerValue new_max_a =
FloorRatio(max_p, min_b);
939 a.LowerOrEqual(new_max_a),
940 {integer_trail_->UpperBoundAsLiteral(p_),
941 integer_trail_->LowerBoundAsLiteral(b)})) {
945 const IntegerValue new_min_a =
CeilRatio(min_p, min_b);
948 a.GreaterOrEqual(new_min_a),
949 {integer_trail_->LowerBoundAsLiteral(p_),
950 integer_trail_->LowerBoundAsLiteral(b)})) {
960 const int id = watcher->
Register(
this);
972IntegerValue FloorSquareRoot(IntegerValue
a) {
973 IntegerValue result(
static_cast<int64_t
>(
974 std::floor(std::sqrt(
static_cast<double>(
a.value())))));
975 while (
CapProd(result.value(), result.value()) >
a) --result;
976 while (
CapProd(result.value() + 1, result.value() + 1) <=
a) ++result;
981IntegerValue CeilSquareRoot(IntegerValue
a) {
982 IntegerValue result(
static_cast<int64_t
>(
983 std::ceil(std::sqrt(
static_cast<double>(
a.value())))));
984 while (
CapProd(result.value(), result.value()) <
a) ++result;
985 while ((result.value() - 1) * (result.value() - 1) >=
a) --result;
993 : x_(x), s_(s), integer_trail_(integer_trail) {
1000 const IntegerValue min_x = integer_trail_->
LowerBound(x_);
1001 const IntegerValue min_s = integer_trail_->
LowerBound(s_);
1002 const IntegerValue min_x_square(
CapProd(min_x.value(), min_x.value()));
1003 if (min_x_square > min_s) {
1005 {x_.GreaterOrEqual(min_x)})) {
1008 }
else if (min_x_square < min_s) {
1009 const IntegerValue new_min = CeilSquareRoot(min_s);
1012 {s_.GreaterOrEqual((new_min - 1) * (new_min - 1) + 1)})) {
1017 const IntegerValue max_x = integer_trail_->
UpperBound(x_);
1018 const IntegerValue max_s = integer_trail_->
UpperBound(s_);
1019 const IntegerValue max_x_square(
CapProd(max_x.value(), max_x.value()));
1020 if (max_x_square < max_s) {
1022 {x_.LowerOrEqual(max_x)})) {
1025 }
else if (max_x_square > max_s) {
1026 const IntegerValue new_max = FloorSquareRoot(max_s);
1029 {s_.LowerOrEqual(IntegerValue(CapProd(new_max.value() + 1,
1030 new_max.value() + 1)) -
1040 const int id = watcher->
Register(
this);
1053 negated_num_(num.Negated()),
1054 negated_div_(div.Negated()),
1055 integer_trail_(integer_trail) {
1061 if (!PropagateSigns())
return false;
1065 !PropagateUpperBounds(num_, denom_, div_)) {
1069 if (integer_trail_->
UpperBound(negated_num_) >= 0 &&
1070 integer_trail_->
UpperBound(negated_div_) >= 0 &&
1071 !PropagateUpperBounds(negated_num_, denom_, negated_div_)) {
1077 return PropagatePositiveDomains(num_, denom_, div_);
1082 return PropagatePositiveDomains(negated_num_, denom_, negated_div_);
1088bool DivisionPropagator::PropagateSigns() {
1089 const IntegerValue min_num = integer_trail_->
LowerBound(num_);
1090 const IntegerValue max_num = integer_trail_->
UpperBound(num_);
1091 const IntegerValue min_div = integer_trail_->
LowerBound(div_);
1092 const IntegerValue max_div = integer_trail_->
UpperBound(div_);
1095 if (min_num >= 0 && min_div < 0) {
1097 {num_.GreaterOrEqual(0)})) {
1103 if (min_num <= 0 && min_div > 0) {
1105 {div_.GreaterOrEqual(1)})) {
1111 if (max_num <= 0 && max_div > 0) {
1113 {num_.LowerOrEqual(0)})) {
1119 if (max_num >= 0 && max_div < 0) {
1121 {div_.LowerOrEqual(-1)})) {
1129bool DivisionPropagator::PropagateUpperBounds(AffineExpression num,
1130 AffineExpression denom,
1131 AffineExpression div) {
1132 const IntegerValue max_num = integer_trail_->
UpperBound(num);
1133 const IntegerValue min_denom = integer_trail_->
LowerBound(denom);
1134 const IntegerValue max_denom = integer_trail_->
UpperBound(denom);
1135 const IntegerValue max_div = integer_trail_->
UpperBound(div);
1137 const IntegerValue new_max_div = max_num / min_denom;
1138 if (max_div > new_max_div) {
1140 div.LowerOrEqual(new_max_div),
1141 {integer_trail_->UpperBoundAsLiteral(num),
1142 integer_trail_->LowerBoundAsLiteral(denom)})) {
1150 const IntegerValue new_max_num =
1151 IntegerValue(
CapAdd(
CapProd(max_div.value() + 1, max_denom.value()), -1));
1152 if (max_num > new_max_num) {
1154 num.LowerOrEqual(new_max_num),
1155 {integer_trail_->UpperBoundAsLiteral(denom),
1156 integer_trail_->UpperBoundAsLiteral(div)})) {
1164bool DivisionPropagator::PropagatePositiveDomains(AffineExpression num,
1165 AffineExpression denom,
1166 AffineExpression div) {
1167 const IntegerValue min_num = integer_trail_->
LowerBound(num);
1168 const IntegerValue max_num = integer_trail_->
UpperBound(num);
1169 const IntegerValue min_denom = integer_trail_->
LowerBound(denom);
1170 const IntegerValue max_denom = integer_trail_->
UpperBound(denom);
1171 const IntegerValue min_div = integer_trail_->
LowerBound(div);
1172 const IntegerValue max_div = integer_trail_->
UpperBound(div);
1174 const IntegerValue new_min_div = min_num / max_denom;
1175 if (min_div < new_min_div) {
1177 div.GreaterOrEqual(new_min_div),
1178 {integer_trail_->LowerBoundAsLiteral(num),
1179 integer_trail_->UpperBoundAsLiteral(denom)})) {
1187 const IntegerValue new_min_num =
1188 IntegerValue(
CapProd(min_denom.value(), min_div.value()));
1189 if (min_num < new_min_num) {
1191 num.GreaterOrEqual(new_min_num),
1192 {integer_trail_->LowerBoundAsLiteral(denom),
1193 integer_trail_->LowerBoundAsLiteral(div)})) {
1203 const IntegerValue new_max_denom = max_num / min_div;
1204 if (max_denom > new_max_denom) {
1206 denom.LowerOrEqual(new_max_denom),
1207 {integer_trail_->UpperBoundAsLiteral(num), num.GreaterOrEqual(0),
1208 integer_trail_->LowerBoundAsLiteral(div)})) {
1216 const IntegerValue new_min_denom =
CeilRatio(min_num + 1, max_div + 1);
1217 if (min_denom < new_min_denom) {
1218 if (!integer_trail_->
SafeEnqueue(denom.GreaterOrEqual(new_min_denom),
1219 {integer_trail_->LowerBoundAsLiteral(num),
1220 integer_trail_->UpperBoundAsLiteral(div),
1221 div.GreaterOrEqual(0)})) {
1230 const int id = watcher->
Register(
this);
1241 : a_(
a), b_(
b), c_(c), integer_trail_(integer_trail) {
1246 const IntegerValue min_a = integer_trail_->
LowerBound(a_);
1247 const IntegerValue max_a = integer_trail_->
UpperBound(a_);
1248 IntegerValue min_c = integer_trail_->
LowerBound(c_);
1249 IntegerValue max_c = integer_trail_->
UpperBound(c_);
1251 if (max_a / b_ < max_c) {
1255 {integer_trail_->UpperBoundAsLiteral(a_)})) {
1258 }
else if (max_a / b_ > max_c) {
1259 const IntegerValue new_max_a =
1260 max_c >= 0 ? max_c * b_ + b_ - 1
1261 : IntegerValue(
CapProd(max_c.value(), b_.value()));
1265 {integer_trail_->UpperBoundAsLiteral(c_)})) {
1270 if (min_a / b_ > min_c) {
1274 {integer_trail_->LowerBoundAsLiteral(a_)})) {
1277 }
else if (min_a / b_ < min_c) {
1278 const IntegerValue new_min_a =
1279 min_c > 0 ? IntegerValue(
CapProd(min_c.value(), b_.value()))
1280 : min_c * b_ - b_ + 1;
1284 {integer_trail_->LowerBoundAsLiteral(c_)})) {
1293 const int id = watcher->
Register(
this);
1302 :
expr_(expr), mod_(mod), target_(target), integer_trail_(integer_trail) {
1307 if (!PropagateSignsAndTargetRange())
return false;
1308 if (!PropagateOuterBounds())
return false;
1310 if (integer_trail_->
LowerBound(expr_) >= 0) {
1311 if (!PropagateBoundsWhenExprIsPositive(expr_, target_))
return false;
1312 }
else if (integer_trail_->
UpperBound(expr_) <= 0) {
1313 if (!PropagateBoundsWhenExprIsPositive(expr_.
Negated(),
1322bool FixedModuloPropagator::PropagateSignsAndTargetRange() {
1324 if (integer_trail_->
UpperBound(target_) >= mod_) {
1330 if (integer_trail_->
LowerBound(target_) <= -mod_) {
1337 if (integer_trail_->
LowerBound(expr_) >= 0 &&
1340 {expr_.GreaterOrEqual(0)})) {
1345 if (integer_trail_->
UpperBound(expr_) <= 0 &&
1348 {expr_.LowerOrEqual(0)})) {
1356bool FixedModuloPropagator::PropagateOuterBounds() {
1357 const IntegerValue min_expr = integer_trail_->
LowerBound(expr_);
1358 const IntegerValue max_expr = integer_trail_->
UpperBound(expr_);
1359 const IntegerValue min_target = integer_trail_->
LowerBound(target_);
1360 const IntegerValue max_target = integer_trail_->
UpperBound(target_);
1362 if (max_expr % mod_ > max_target) {
1364 expr_.
LowerOrEqual((max_expr / mod_) * mod_ + max_target),
1365 {integer_trail_->UpperBoundAsLiteral(target_),
1366 integer_trail_->UpperBoundAsLiteral(expr_)})) {
1371 if (min_expr % mod_ < min_target) {
1374 {integer_trail_->LowerBoundAsLiteral(expr_),
1375 integer_trail_->LowerBoundAsLiteral(target_)})) {
1380 if (min_expr / mod_ == max_expr / mod_) {
1381 if (min_target < min_expr % mod_) {
1384 {integer_trail_->LowerBoundAsLiteral(target_),
1385 integer_trail_->UpperBoundAsLiteral(target_),
1386 integer_trail_->LowerBoundAsLiteral(expr_),
1387 integer_trail_->UpperBoundAsLiteral(expr_)})) {
1392 if (max_target > max_expr % mod_) {
1394 target_.
LowerOrEqual(max_expr - (max_expr / mod_) * mod_),
1395 {integer_trail_->LowerBoundAsLiteral(target_),
1396 integer_trail_->UpperBoundAsLiteral(target_),
1397 integer_trail_->LowerBoundAsLiteral(expr_),
1398 integer_trail_->UpperBoundAsLiteral(expr_)})) {
1402 }
else if (min_expr / mod_ == 0 && min_target < 0) {
1404 if (min_target < min_expr) {
1407 {integer_trail_->LowerBoundAsLiteral(target_),
1408 integer_trail_->LowerBoundAsLiteral(expr_)})) {
1412 }
else if (max_expr / mod_ == 0 && max_target > 0) {
1414 if (max_target > max_expr) {
1417 {integer_trail_->UpperBoundAsLiteral(target_),
1418 integer_trail_->UpperBoundAsLiteral(expr_)})) {
1427bool FixedModuloPropagator::PropagateBoundsWhenExprIsPositive(
1428 AffineExpression expr, AffineExpression target) {
1429 const IntegerValue min_target = integer_trail_->
LowerBound(target);
1431 const IntegerValue max_target = integer_trail_->
UpperBound(target);
1435 if (min_target == 0 && max_target == mod_ - 1)
return true;
1437 const IntegerValue min_expr = integer_trail_->
LowerBound(expr);
1438 const IntegerValue max_expr = integer_trail_->
UpperBound(expr);
1440 if (max_expr % mod_ < min_target) {
1443 expr.LowerOrEqual((max_expr / mod_ - 1) * mod_ + max_target),
1444 {integer_trail_->UpperBoundAsLiteral(expr),
1445 integer_trail_->LowerBoundAsLiteral(target),
1446 integer_trail_->UpperBoundAsLiteral(target)})) {
1451 if (min_expr % mod_ > max_target) {
1454 expr.GreaterOrEqual((min_expr / mod_ + 1) * mod_ + min_target),
1455 {integer_trail_->LowerBoundAsLiteral(target),
1456 integer_trail_->UpperBoundAsLiteral(target),
1457 integer_trail_->LowerBoundAsLiteral(expr)})) {
1466 const int id = watcher->
Register(
this);
1473 const std::vector<Literal>& selectors,
1474 const std::vector<IntegerValue>& values) {
1479 CHECK(!values.empty());
1480 CHECK_EQ(values.size(), selectors.size());
1481 std::vector<int64_t> unique_values;
1482 absl::flat_hash_map<int64_t, std::vector<Literal>> value_to_selector;
1483 for (
int i = 0; i < values.size(); ++i) {
1484 unique_values.push_back(values[i].
value());
1485 value_to_selector[values[i].value()].push_back(selectors[i]);
1490 if (unique_values.size() == 1) {
1497 for (
const int64_t v : unique_values) {
1498 const std::vector<Literal>& selectors = value_to_selector[v];
1499 if (selectors.size() == 1) {
1500 encoder->AssociateToIntegerEqualValue(selectors[0],
var,
1505 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)
IntegerVariable PositiveVariable(IntegerVariable i)
IntegerValue PositiveRemainder(IntegerValue dividend, IntegerValue positive_divisor)
std::function< int64_t(const Model &)> UpperBound(IntegerVariable v)
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)