20 #include "absl/container/flat_hash_map.h"
21 #include "absl/memory/memory.h"
31 const std::vector<IntegerVariable>& vars,
32 const std::vector<IntegerValue>& coeffs,
34 : enforcement_literals_(enforcement_literals),
39 rev_integer_value_repository_(
44 CHECK(!vars_.empty());
45 max_variations_.resize(vars_.size());
48 for (
int i = 0; i < vars.size(); ++i) {
51 coeffs_[i] = -coeffs_[i];
57 literal_reason_.push_back(
literal.Negated());
61 rev_num_fixed_vars_ = 0;
62 rev_lb_fixed_vars_ = IntegerValue(0);
65 void IntegerSumLE::FillIntegerReason() {
66 integer_reason_.clear();
67 reason_coeffs_.clear();
68 const int num_vars = vars_.size();
69 for (
int i = 0; i < num_vars; ++i) {
70 const IntegerVariable
var = vars_[i];
73 reason_coeffs_.push_back(coeffs_[i]);
81 int num_unassigned_enforcement_literal = 0;
86 ++num_unassigned_enforcement_literal;
87 unique_unnasigned_literal =
literal.Index();
93 if (num_unassigned_enforcement_literal > 1)
return true;
97 rev_integer_value_repository_->
SaveState(&rev_lb_fixed_vars_);
101 IntegerValue lb_unfixed_vars = IntegerValue(0);
102 const int num_vars = vars_.size();
103 for (
int i = rev_num_fixed_vars_; i < num_vars; ++i) {
104 const IntegerVariable
var = vars_[i];
105 const IntegerValue coeff = coeffs_[i];
109 max_variations_[i] = (ub - lb) * coeff;
110 lb_unfixed_vars += lb * coeff;
113 std::swap(vars_[i], vars_[rev_num_fixed_vars_]);
114 std::swap(coeffs_[i], coeffs_[rev_num_fixed_vars_]);
115 std::swap(max_variations_[i], max_variations_[rev_num_fixed_vars_]);
116 rev_num_fixed_vars_++;
117 rev_lb_fixed_vars_ += lb * coeff;
121 static_cast<double>(num_vars - rev_num_fixed_vars_) * 1e-9);
124 const IntegerValue slack =
125 upper_bound_ - (rev_lb_fixed_vars_ + lb_unfixed_vars);
131 if (num_unassigned_enforcement_literal == 1) {
134 std::vector<Literal> tmp = literal_reason_;
135 tmp.erase(std::find(tmp.begin(), tmp.end(), to_propagate));
136 integer_trail_->
EnqueueLiteral(to_propagate, tmp, integer_reason_);
139 return integer_trail_->
ReportConflict(literal_reason_, integer_reason_);
143 if (num_unassigned_enforcement_literal > 0)
return true;
147 for (
int i = rev_num_fixed_vars_; i < num_vars; ++i) {
148 if (max_variations_[i] <= slack)
continue;
150 const IntegerVariable
var = vars_[i];
151 const IntegerValue coeff = coeffs_[i];
152 const IntegerValue div = slack / coeff;
153 const IntegerValue new_ub = integer_trail_->
LowerBound(
var) + div;
154 const IntegerValue propagation_slack = (div + 1) * coeff - slack - 1;
157 [
this, propagation_slack](
159 std::vector<Literal>* literal_reason,
160 std::vector<int>* trail_indices_reason) {
161 *literal_reason = literal_reason_;
162 trail_indices_reason->clear();
163 reason_coeffs_.clear();
164 const int size = vars_.size();
165 for (int i = 0; i < size; ++i) {
166 const IntegerVariable var = vars_[i];
167 if (PositiveVariable(var) == PositiveVariable(i_lit.var)) {
171 integer_trail_->FindTrailIndexOfVarBefore(var, trail_index);
173 trail_indices_reason->push_back(index);
174 if (propagation_slack > 0) {
175 reason_coeffs_.push_back(coeffs_[i]);
179 if (propagation_slack > 0) {
181 propagation_slack, reason_coeffs_, trail_indices_reason);
192 is_registered_ =
true;
193 const int id = watcher->
Register(
this);
194 for (
const IntegerVariable&
var :
vars_) {
207 MinPropagator::MinPropagator(
const std::vector<IntegerVariable>& vars,
208 IntegerVariable min_var,
210 :
vars_(vars), min_var_(min_var), integer_trail_(integer_trail) {}
213 if (vars_.empty())
return true;
219 const IntegerValue current_min_ub = integer_trail_->
UpperBound(min_var_);
220 int num_intervals_that_can_be_min = 0;
221 int last_possible_min_interval = 0;
224 for (
int i = 0; i < vars_.size(); ++i) {
225 const IntegerValue lb = integer_trail_->
LowerBound(vars_[i]);
227 if (lb <= current_min_ub) {
228 ++num_intervals_that_can_be_min;
229 last_possible_min_interval = i;
235 integer_reason_.clear();
236 for (
const IntegerVariable
var : vars_) {
240 {}, integer_reason_)) {
246 if (num_intervals_that_can_be_min == 1) {
247 const IntegerValue ub_of_only_candidate =
248 integer_trail_->
UpperBound(vars_[last_possible_min_interval]);
249 if (current_min_ub < ub_of_only_candidate) {
250 integer_reason_.clear();
254 integer_reason_.push_back(min_ub_literal);
255 for (
const IntegerVariable
var : vars_) {
256 if (
var ==
vars_[last_possible_min_interval])
continue;
257 integer_reason_.push_back(
263 {}, integer_reason_)) {
275 if (num_intervals_that_can_be_min == 0) {
276 integer_reason_.clear();
279 integer_reason_.push_back(min_ub_literal);
280 for (
const IntegerVariable
var : vars_) {
281 integer_reason_.push_back(
291 const int id = watcher->
Register(
this);
292 for (
const IntegerVariable&
var : vars_) {
305 bool LinMinPropagator::PropagateLinearUpperBound(
306 const std::vector<IntegerVariable>& vars,
307 const std::vector<IntegerValue>& coeffs,
const IntegerValue upper_bound) {
308 IntegerValue sum_lb = IntegerValue(0);
309 const int num_vars = vars.size();
310 std::vector<IntegerValue> max_variations;
311 for (
int i = 0; i < num_vars; ++i) {
312 const IntegerVariable
var = vars[i];
313 const IntegerValue coeff = coeffs[i];
318 max_variations.push_back((ub - lb) * coeff);
319 sum_lb += lb * coeff;
323 static_cast<double>(num_vars) * 1e-9);
325 const IntegerValue slack = upper_bound - sum_lb;
327 std::vector<IntegerLiteral> linear_sum_reason;
328 std::vector<IntegerValue> reason_coeffs;
329 for (
int i = 0; i < num_vars; ++i) {
330 const IntegerVariable
var = vars[i];
333 reason_coeffs.push_back(coeffs[i]);
340 std::vector<IntegerLiteral> local_reason =
341 integer_reason_for_unique_candidate_;
342 local_reason.insert(local_reason.end(), linear_sum_reason.begin(),
343 linear_sum_reason.end());
349 for (
int i = 0; i < num_vars; ++i) {
350 if (max_variations[i] <= slack)
continue;
352 const IntegerVariable
var = vars[i];
353 const IntegerValue coeff = coeffs[i];
354 const IntegerValue div = slack / coeff;
355 const IntegerValue new_ub = integer_trail_->
LowerBound(
var) + div;
357 const IntegerValue propagation_slack = (div + 1) * coeff - slack - 1;
360 [
this, &vars, &coeffs, propagation_slack](
361 IntegerLiteral i_lit,
int trail_index,
362 std::vector<Literal>* literal_reason,
363 std::vector<int>* trail_indices_reason) {
364 literal_reason->clear();
365 trail_indices_reason->clear();
366 std::vector<IntegerValue> reason_coeffs;
367 const int size = vars.size();
368 for (
int i = 0; i < size; ++i) {
369 const IntegerVariable
var = vars[i];
376 trail_indices_reason->push_back(
index);
377 if (propagation_slack > 0) {
378 reason_coeffs.push_back(coeffs[i]);
382 if (propagation_slack > 0) {
384 propagation_slack, reason_coeffs, trail_indices_reason);
387 for (IntegerLiteral reason_lit :
388 integer_reason_for_unique_candidate_) {
390 reason_lit.var, trail_index);
392 trail_indices_reason->push_back(
index);
403 if (exprs_.empty())
return true;
411 const IntegerValue current_min_ub = integer_trail_->
UpperBound(min_var_);
412 int num_intervals_that_can_be_min = 0;
413 int last_possible_min_interval = 0;
416 for (
int i = 0; i < exprs_.size(); ++i) {
418 expr_lbs_.push_back(lb);
419 min_of_linear_expression_lb =
std::min(min_of_linear_expression_lb, lb);
420 if (lb <= current_min_ub) {
421 ++num_intervals_that_can_be_min;
422 last_possible_min_interval = i;
430 if (min_of_linear_expression_lb > current_min_ub) {
431 min_of_linear_expression_lb = current_min_ub + 1;
436 const bool use_slack =
false;
437 if (min_of_linear_expression_lb > integer_trail_->
LowerBound(min_var_)) {
438 std::vector<IntegerLiteral> local_reason;
439 for (
int i = 0; i < exprs_.size(); ++i) {
440 const IntegerValue slack = expr_lbs_[i] - min_of_linear_expression_lb;
442 (use_slack ? slack : IntegerValue(0)), exprs_[i].coeffs,
443 exprs_[i].vars, &local_reason);
446 min_var_, min_of_linear_expression_lb),
456 if (num_intervals_that_can_be_min == 1) {
457 const IntegerValue ub_of_only_candidate =
459 if (current_min_ub < ub_of_only_candidate) {
462 if (rev_unique_candidate_ == 0) {
463 integer_reason_for_unique_candidate_.clear();
467 integer_reason_for_unique_candidate_.push_back(min_ub_literal);
468 for (
int i = 0; i < exprs_.size(); ++i) {
469 if (i == last_possible_min_interval)
continue;
470 const IntegerValue slack = expr_lbs_[i] - (current_min_ub + 1);
472 (use_slack ? slack : IntegerValue(0)), exprs_[i].coeffs,
473 exprs_[i].vars, &integer_reason_for_unique_candidate_);
475 rev_unique_candidate_ = 1;
478 return PropagateLinearUpperBound(
479 exprs_[last_possible_min_interval].vars,
480 exprs_[last_possible_min_interval].coeffs,
481 current_min_ub - exprs_[last_possible_min_interval].offset);
489 const int id = watcher->
Register(
this);
491 for (
int i = 0; i < expr.vars.size(); ++i) {
492 const IntegerVariable&
var = expr.vars[i];
493 const IntegerValue coeff = expr.coeffs[i];
506 IntegerVariable
a, IntegerVariable
b, IntegerVariable p,
508 : a_(
a), b_(
b), p_(p), integer_trail_(integer_trail) {}
513 IntegerValue MaxValue(IntegerValue
b, IntegerValue p) {
520 IntegerValue MinValue(IntegerValue
b, IntegerValue p) {
523 return (p +
b - 1) /
b;
530 IntegerVariable
a = a_;
531 IntegerVariable
b = b_;
532 IntegerValue min_a = integer_trail_->
LowerBound(
a);
533 IntegerValue max_a = integer_trail_->
UpperBound(
a);
534 IntegerValue min_b = integer_trail_->
LowerBound(
b);
535 IntegerValue max_b = integer_trail_->
UpperBound(
b);
536 IntegerValue min_p = integer_trail_->
LowerBound(p_);
537 IntegerValue max_p = integer_trail_->
UpperBound(p_);
543 const IntegerValue zero(0);
544 bool may_propagate =
true;
545 while (may_propagate) {
546 may_propagate =
false;
547 if (max_a * max_b < max_p) {
548 may_propagate =
true;
549 max_p = max_a * max_b;
551 {integer_trail_->UpperBoundAsLiteral(a),
552 integer_trail_->UpperBoundAsLiteral(b),
553 IntegerLiteral::GreaterOrEqual(a, zero),
554 IntegerLiteral::GreaterOrEqual(b, zero)})) {
558 if (min_a * min_b > min_p) {
559 may_propagate =
true;
560 min_p = min_a * min_b;
563 {integer_trail_->LowerBoundAsLiteral(a),
564 integer_trail_->LowerBoundAsLiteral(b)})) {
571 CHECK_GE(max_p, min_p);
573 for (
int i = 0; i < 2; ++i) {
574 if (max_a * min_b > max_p) {
575 may_propagate =
true;
576 max_a = MaxValue(min_b, max_p);
579 {integer_trail_->LowerBoundAsLiteral(b),
580 integer_trail_->UpperBoundAsLiteral(p_)})) {
583 }
else if (max_a * min_b < min_p) {
584 may_propagate =
true;
585 min_b = MinValue(max_a, min_p);
588 {integer_trail_->UpperBoundAsLiteral(a),
589 IntegerLiteral::GreaterOrEqual(b, zero),
590 integer_trail_->LowerBoundAsLiteral(p_)})) {
597 std::swap(min_a, min_b);
598 std::swap(max_a, max_b);
605 const int id = watcher->
Register(
this);
613 : x_(x), s_(s), integer_trail_(integer_trail) {}
616 bool may_propagate =
true;
617 while (may_propagate) {
618 may_propagate =
false;
619 IntegerValue min_x = integer_trail_->
LowerBound(x_);
620 IntegerValue max_x = integer_trail_->
UpperBound(x_);
621 IntegerValue min_s = integer_trail_->
LowerBound(s_);
622 IntegerValue max_s = integer_trail_->
UpperBound(s_);
628 if (min_x * min_x > min_s) {
629 may_propagate =
true;
630 min_s = min_x * min_x;
633 {IntegerLiteral::GreaterOrEqual(x_, min_x)})) {
637 if (max_x * max_x < max_s) {
638 may_propagate =
true;
639 max_s = max_x * max_x;
641 {IntegerLiteral::LowerOrEqual(x_, max_x)})) {
647 if (max_x * max_x > max_s) {
648 may_propagate =
true;
650 while (max_x * max_x > max_s) max_x--;
652 {IntegerLiteral::LowerOrEqual(
653 s_, (max_x + 1) * (max_x + 1) - 1)})) {
657 if (min_x * min_x < min_s) {
658 may_propagate =
true;
660 while (min_x * min_x < min_s) min_x++;
663 {IntegerLiteral::GreaterOrEqual(
664 s_, (min_x - 1) * (min_x - 1) + 1)})) {
674 const int id = watcher->
Register(
this);
682 : a_(
a), b_(
b), c_(c), integer_trail_(integer_trail) {}
685 const IntegerValue min_a = integer_trail_->
LowerBound(a_);
686 const IntegerValue max_a = integer_trail_->
UpperBound(a_);
687 const IntegerValue min_b = integer_trail_->
LowerBound(b_);
688 const IntegerValue max_b = integer_trail_->
UpperBound(b_);
689 IntegerValue min_c = integer_trail_->
LowerBound(c_);
690 IntegerValue max_c = integer_trail_->
UpperBound(c_);
696 bool may_propagate =
true;
697 while (may_propagate) {
698 may_propagate =
false;
699 if (max_a / min_b < max_c) {
700 may_propagate =
true;
701 max_c = max_a / min_b;
703 {integer_trail_->UpperBoundAsLiteral(a_),
704 integer_trail_->LowerBoundAsLiteral(b_)})) {
708 if (min_a / max_b > min_c) {
709 may_propagate =
true;
710 min_c = min_a / max_b;
713 {integer_trail_->LowerBoundAsLiteral(a_),
714 integer_trail_->UpperBoundAsLiteral(b_)})) {
727 const int id = watcher->
Register(
this);
737 : a_(
a), b_(
b), c_(c), integer_trail_(integer_trail) {}
740 const IntegerValue min_a = integer_trail_->
LowerBound(a_);
741 const IntegerValue max_a = integer_trail_->
UpperBound(a_);
742 IntegerValue min_c = integer_trail_->
LowerBound(c_);
743 IntegerValue max_c = integer_trail_->
UpperBound(c_);
747 if (max_a / b_ < max_c) {
750 {integer_trail_->UpperBoundAsLiteral(a_)})) {
753 }
else if (max_a / b_ > max_c) {
754 const IntegerValue new_max_a =
755 max_c >= 0 ? max_c * b_ + b_ - 1
756 : IntegerValue(
CapProd(max_c.value(), b_.value()));
757 CHECK_LT(new_max_a, max_a);
760 {integer_trail_->UpperBoundAsLiteral(c_)})) {
765 if (min_a / b_ > min_c) {
768 {integer_trail_->LowerBoundAsLiteral(a_)})) {
771 }
else if (min_a / b_ < min_c) {
772 const IntegerValue new_min_a =
773 min_c > 0 ? IntegerValue(
CapProd(min_c.value(), b_.value()))
774 : min_c * b_ - b_ + 1;
775 CHECK_GT(new_min_a, min_a);
778 {integer_trail_->LowerBoundAsLiteral(c_)})) {
787 const int id = watcher->
Register(
this);
793 const std::vector<Literal>& selectors,
794 const std::vector<IntegerValue>& values) {
799 CHECK(!values.empty());
800 CHECK_EQ(values.size(), selectors.size());
801 std::vector<int64> unique_values;
802 absl::flat_hash_map<int64, std::vector<Literal>> value_to_selector;
803 for (
int i = 0; i < values.size(); ++i) {
804 unique_values.push_back(values[i].
value());
805 value_to_selector[values[i].value()].push_back(selectors[i]);
810 if (unique_values.size() == 1) {
817 for (
const int64 v : unique_values) {
818 const std::vector<Literal>& selectors = value_to_selector[v];
819 if (selectors.size() == 1) {
820 encoder->AssociateToIntegerEqualValue(selectors[0],
var,
825 encoder->AssociateToIntegerEqualValue(l,
var, IntegerValue(v));