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) {
519 const IntegerValue max_a = integer_trail_->
UpperBound(a_);
520 const IntegerValue max_b = integer_trail_->
UpperBound(b_);
521 const IntegerValue new_max(
CapProd(max_a.value(), max_b.value()));
522 if (new_max < integer_trail_->
UpperBound(p_)) {
524 {integer_trail_->UpperBoundAsLiteral(a_),
525 integer_trail_->UpperBoundAsLiteral(b_)})) {
530 const IntegerValue min_a = integer_trail_->
LowerBound(a_);
531 const IntegerValue min_b = integer_trail_->
LowerBound(b_);
532 const IntegerValue new_min(
CapProd(min_a.value(), min_b.value()));
533 if (new_min > integer_trail_->
LowerBound(p_)) {
536 {integer_trail_->LowerBoundAsLiteral(a_),
537 integer_trail_->LowerBoundAsLiteral(b_)})) {
542 for (
int i = 0; i < 2; ++i) {
543 const IntegerVariable
a = i == 0 ? a_ : b_;
544 const IntegerVariable
b = i == 0 ? b_ : a_;
545 const IntegerValue max_a = integer_trail_->
UpperBound(
a);
546 const IntegerValue min_b = integer_trail_->
LowerBound(
b);
547 const IntegerValue min_p = integer_trail_->
LowerBound(p_);
548 const IntegerValue max_p = integer_trail_->
UpperBound(p_);
549 const IntegerValue prod(
CapProd(max_a.value(), min_b.value()));
557 }
else if (prod < min_p) {
571 const int id = watcher->
Register(
this);
581 IntegerValue FloorSquareRoot(IntegerValue
a) {
582 IntegerValue result(
static_cast<int64>(std::floor(std::sqrt(
ToDouble(
a)))));
583 while (result * result >
a) --result;
584 while ((result + 1) * (result + 1) <=
a) ++result;
589 IntegerValue CeilSquareRoot(IntegerValue
a) {
590 IntegerValue result(
static_cast<int64>(std::ceil(std::sqrt(
ToDouble(
a)))));
591 while (result * result <
a) ++result;
592 while ((result - 1) * (result - 1) >=
a) --result;
600 : x_(x), s_(s), integer_trail_(integer_trail) {
607 const IntegerValue min_x = integer_trail_->
LowerBound(x_);
608 const IntegerValue min_s = integer_trail_->
LowerBound(s_);
609 const IntegerValue min_x_square(
CapProd(min_x.value(), min_x.value()));
610 if (min_x_square > min_s) {
613 {IntegerLiteral::GreaterOrEqual(x_, min_x)})) {
616 }
else if (min_x_square < min_s) {
617 const IntegerValue new_min = CeilSquareRoot(min_s);
620 {IntegerLiteral::GreaterOrEqual(
621 s_, (new_min - 1) * (new_min - 1) + 1)})) {
626 const IntegerValue max_x = integer_trail_->
UpperBound(x_);
627 const IntegerValue max_s = integer_trail_->
UpperBound(s_);
628 const IntegerValue max_x_square(
CapProd(max_x.value(), max_x.value()));
629 if (max_x_square < max_s) {
632 {IntegerLiteral::LowerOrEqual(x_, max_x)})) {
635 }
else if (max_x_square > max_s) {
636 const IntegerValue new_max = FloorSquareRoot(max_s);
638 {IntegerLiteral::LowerOrEqual(
639 s_, (new_max + 1) * (new_max + 1) - 1)})) {
648 const int id = watcher->
Register(
this);
657 : a_(
a), b_(
b), c_(c), integer_trail_(integer_trail) {
664 const IntegerValue min_a = integer_trail_->
LowerBound(a_);
665 const IntegerValue max_a = integer_trail_->
UpperBound(a_);
666 const IntegerValue min_b = integer_trail_->
LowerBound(b_);
667 const IntegerValue max_b = integer_trail_->
UpperBound(b_);
668 IntegerValue min_c = integer_trail_->
LowerBound(c_);
669 IntegerValue max_c = integer_trail_->
UpperBound(c_);
671 if (max_a / min_b < max_c) {
672 max_c = max_a / min_b;
674 {integer_trail_->UpperBoundAsLiteral(a_),
675 integer_trail_->LowerBoundAsLiteral(b_)})) {
679 if (min_a / max_b > min_c) {
680 min_c = min_a / max_b;
682 {integer_trail_->LowerBoundAsLiteral(a_),
683 integer_trail_->UpperBoundAsLiteral(b_)})) {
695 const int id = watcher->
Register(
this);
706 : a_(
a), b_(
b), c_(c), integer_trail_(integer_trail) {}
709 const IntegerValue min_a = integer_trail_->
LowerBound(a_);
710 const IntegerValue max_a = integer_trail_->
UpperBound(a_);
711 IntegerValue min_c = integer_trail_->
LowerBound(c_);
712 IntegerValue max_c = integer_trail_->
UpperBound(c_);
716 if (max_a / b_ < max_c) {
719 {integer_trail_->UpperBoundAsLiteral(a_)})) {
722 }
else if (max_a / b_ > max_c) {
723 const IntegerValue new_max_a =
724 max_c >= 0 ? max_c * b_ + b_ - 1
725 : IntegerValue(
CapProd(max_c.value(), b_.value()));
726 CHECK_LT(new_max_a, max_a);
729 {integer_trail_->UpperBoundAsLiteral(c_)})) {
734 if (min_a / b_ > min_c) {
737 {integer_trail_->LowerBoundAsLiteral(a_)})) {
740 }
else if (min_a / b_ < min_c) {
741 const IntegerValue new_min_a =
742 min_c > 0 ? IntegerValue(
CapProd(min_c.value(), b_.value()))
743 : min_c * b_ - b_ + 1;
744 CHECK_GT(new_min_a, min_a);
747 {integer_trail_->LowerBoundAsLiteral(c_)})) {
756 const int id = watcher->
Register(
this);
762 const std::vector<Literal>& selectors,
763 const std::vector<IntegerValue>& values) {
768 CHECK(!values.empty());
769 CHECK_EQ(values.size(), selectors.size());
770 std::vector<int64> unique_values;
771 absl::flat_hash_map<int64, std::vector<Literal>> value_to_selector;
772 for (
int i = 0; i < values.size(); ++i) {
773 unique_values.push_back(values[i].
value());
774 value_to_selector[values[i].value()].push_back(selectors[i]);
779 if (unique_values.size() == 1) {
786 for (
const int64 v : unique_values) {
787 const std::vector<Literal>& selectors = value_to_selector[v];
788 if (selectors.size() == 1) {
789 encoder->AssociateToIntegerEqualValue(selectors[0],
var,
794 encoder->AssociateToIntegerEqualValue(l,
var, IntegerValue(v));