OR-Tools  9.3
integer_expr.cc
Go to the documentation of this file.
1// Copyright 2010-2021 Google LLC
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
15
16#include <algorithm>
17#include <cstdint>
18#include <cstdlib>
19#include <functional>
20#include <utility>
21#include <vector>
22
23#include "absl/container/flat_hash_map.h"
24#include "absl/memory/memory.h"
25#include "absl/types/span.h"
30#include "ortools/sat/integer.h"
32#include "ortools/sat/model.h"
35#include "ortools/sat/util.h"
40
41namespace operations_research {
42namespace sat {
43
44IntegerSumLE::IntegerSumLE(const std::vector<Literal>& enforcement_literals,
45 const std::vector<IntegerVariable>& vars,
46 const std::vector<IntegerValue>& coeffs,
47 IntegerValue upper, Model* model)
48 : enforcement_literals_(enforcement_literals),
49 upper_bound_(upper),
50 trail_(model->GetOrCreate<Trail>()),
51 integer_trail_(model->GetOrCreate<IntegerTrail>()),
52 time_limit_(model->GetOrCreate<TimeLimit>()),
53 rev_integer_value_repository_(
54 model->GetOrCreate<RevIntegerValueRepository>()),
55 vars_(vars),
56 coeffs_(coeffs) {
57 // TODO(user): deal with this corner case.
58 CHECK(!vars_.empty());
59 max_variations_.resize(vars_.size());
60
61 // Handle negative coefficients.
62 for (int i = 0; i < vars.size(); ++i) {
63 if (coeffs_[i] < 0) {
64 vars_[i] = NegationOf(vars_[i]);
65 coeffs_[i] = -coeffs_[i];
66 }
67 }
68
69 // Literal reason will only be used with the negation of enforcement_literals.
70 for (const Literal literal : enforcement_literals) {
71 literal_reason_.push_back(literal.Negated());
72 }
73
74 // Initialize the reversible numbers.
75 rev_num_fixed_vars_ = 0;
76 rev_lb_fixed_vars_ = IntegerValue(0);
77}
78
79void IntegerSumLE::FillIntegerReason() {
80 integer_reason_.clear();
81 reason_coeffs_.clear();
82 const int num_vars = vars_.size();
83 for (int i = 0; i < num_vars; ++i) {
84 const IntegerVariable var = vars_[i];
85 if (!integer_trail_->VariableLowerBoundIsFromLevelZero(var)) {
86 integer_reason_.push_back(integer_trail_->LowerBoundAsLiteral(var));
87 reason_coeffs_.push_back(coeffs_[i]);
88 }
89 }
90}
91
92std::pair<IntegerValue, IntegerValue> IntegerSumLE::ConditionalLb(
93 IntegerLiteral integer_literal, IntegerVariable target_var) const {
94 // Recall that all our coefficient are positive.
95 bool literal_var_present = false;
96 bool literal_var_present_positively = false;
97 IntegerValue var_coeff;
98
99 bool target_var_present_negatively = false;
100 IntegerValue target_coeff;
101
102 // Compute the implied_lb excluding "- target_coeff * target".
103 IntegerValue implied_lb(-upper_bound_);
104 for (int i = 0; i < vars_.size(); ++i) {
105 const IntegerVariable var = vars_[i];
106 const IntegerValue coeff = coeffs_[i];
107 if (var == NegationOf(target_var)) {
108 target_coeff = coeff;
109 target_var_present_negatively = true;
110 continue;
111 }
112
113 const IntegerValue lb = integer_trail_->LowerBound(var);
114 implied_lb += coeff * lb;
115 if (PositiveVariable(var) == PositiveVariable(integer_literal.var)) {
116 var_coeff = coeff;
117 literal_var_present = true;
118 literal_var_present_positively = (var == integer_literal.var);
119 }
120 }
121 if (!literal_var_present || !target_var_present_negatively) {
123 }
124
125 // A literal means var >= bound.
126 if (literal_var_present_positively) {
127 // We have var_coeff * var in the expression, the literal is var >= bound.
128 // When it is false, it is not relevant as implied_lb used var >= lb.
129 // When it is true, the diff is bound - lb.
130 const IntegerValue diff = std::max(
131 IntegerValue(0), integer_literal.bound -
132 integer_trail_->LowerBound(integer_literal.var));
133 return {CeilRatio(implied_lb, target_coeff),
134 CeilRatio(implied_lb + var_coeff * diff, target_coeff)};
135 } else {
136 // We have var_coeff * -var in the expression, the literal is var >= bound.
137 // When it is true, it is not relevant as implied_lb used -var >= -ub.
138 // And when it is false it means var < bound, so -var >= -bound + 1
139 const IntegerValue diff = std::max(
140 IntegerValue(0), integer_trail_->UpperBound(integer_literal.var) -
141 integer_literal.bound + 1);
142 return {CeilRatio(implied_lb + var_coeff * diff, target_coeff),
143 CeilRatio(implied_lb, target_coeff)};
144 }
145}
146
148 // Reified case: If any of the enforcement_literals are false, we ignore the
149 // constraint.
150 int num_unassigned_enforcement_literal = 0;
151 LiteralIndex unique_unnasigned_literal = kNoLiteralIndex;
152 for (const Literal literal : enforcement_literals_) {
153 if (trail_->Assignment().LiteralIsFalse(literal)) return true;
154 if (!trail_->Assignment().LiteralIsTrue(literal)) {
155 ++num_unassigned_enforcement_literal;
156 unique_unnasigned_literal = literal.Index();
157 }
158 }
159
160 // Unfortunately, we can't propagate anything if we have more than one
161 // unassigned enforcement literal.
162 if (num_unassigned_enforcement_literal > 1) return true;
163
164 // Save the current sum of fixed variables.
165 if (is_registered_) {
166 rev_integer_value_repository_->SaveState(&rev_lb_fixed_vars_);
167 } else {
168 rev_num_fixed_vars_ = 0;
169 rev_lb_fixed_vars_ = 0;
170 }
171
172 // Compute the new lower bound and update the reversible structures.
173 IntegerValue lb_unfixed_vars = IntegerValue(0);
174 const int num_vars = vars_.size();
175 for (int i = rev_num_fixed_vars_; i < num_vars; ++i) {
176 const IntegerVariable var = vars_[i];
177 const IntegerValue coeff = coeffs_[i];
178 const IntegerValue lb = integer_trail_->LowerBound(var);
179 const IntegerValue ub = integer_trail_->UpperBound(var);
180 if (lb != ub) {
181 max_variations_[i] = (ub - lb) * coeff;
182 lb_unfixed_vars += lb * coeff;
183 } else {
184 // Update the set of fixed variables.
185 std::swap(vars_[i], vars_[rev_num_fixed_vars_]);
186 std::swap(coeffs_[i], coeffs_[rev_num_fixed_vars_]);
187 std::swap(max_variations_[i], max_variations_[rev_num_fixed_vars_]);
188 rev_num_fixed_vars_++;
189 rev_lb_fixed_vars_ += lb * coeff;
190 }
191 }
192 time_limit_->AdvanceDeterministicTime(
193 static_cast<double>(num_vars - rev_num_fixed_vars_) * 1e-9);
194
195 // Conflict?
196 const IntegerValue slack =
197 upper_bound_ - (rev_lb_fixed_vars_ + lb_unfixed_vars);
198 if (slack < 0) {
199 FillIntegerReason();
200 integer_trail_->RelaxLinearReason(-slack - 1, reason_coeffs_,
201 &integer_reason_);
202
203 if (num_unassigned_enforcement_literal == 1) {
204 // Propagate the only non-true literal to false.
205 const Literal to_propagate = Literal(unique_unnasigned_literal).Negated();
206 std::vector<Literal> tmp = literal_reason_;
207 tmp.erase(std::find(tmp.begin(), tmp.end(), to_propagate));
208 integer_trail_->EnqueueLiteral(to_propagate, tmp, integer_reason_);
209 return true;
210 }
211 return integer_trail_->ReportConflict(literal_reason_, integer_reason_);
212 }
213
214 // We can only propagate more if all the enforcement literals are true.
215 if (num_unassigned_enforcement_literal > 0) return true;
216
217 // The lower bound of all the variables except one can be used to update the
218 // upper bound of the last one.
219 for (int i = rev_num_fixed_vars_; i < num_vars; ++i) {
220 if (max_variations_[i] <= slack) continue;
221
222 const IntegerVariable var = vars_[i];
223 const IntegerValue coeff = coeffs_[i];
224 const IntegerValue div = slack / coeff;
225 const IntegerValue new_ub = integer_trail_->LowerBound(var) + div;
226 const IntegerValue propagation_slack = (div + 1) * coeff - slack - 1;
227 if (!integer_trail_->Enqueue(
229 /*lazy_reason=*/[this, propagation_slack](
230 IntegerLiteral i_lit, int trail_index,
231 std::vector<Literal>* literal_reason,
232 std::vector<int>* trail_indices_reason) {
233 *literal_reason = literal_reason_;
234 trail_indices_reason->clear();
235 reason_coeffs_.clear();
236 const int size = vars_.size();
237 for (int i = 0; i < size; ++i) {
238 const IntegerVariable var = vars_[i];
239 if (PositiveVariable(var) == PositiveVariable(i_lit.var)) {
240 continue;
241 }
242 const int index =
243 integer_trail_->FindTrailIndexOfVarBefore(var, trail_index);
244 if (index >= 0) {
245 trail_indices_reason->push_back(index);
246 if (propagation_slack > 0) {
247 reason_coeffs_.push_back(coeffs_[i]);
248 }
249 }
250 }
251 if (propagation_slack > 0) {
252 integer_trail_->RelaxLinearReason(
253 propagation_slack, reason_coeffs_, trail_indices_reason);
254 }
255 })) {
256 return false;
257 }
258 }
259
260 return true;
261}
262
263bool IntegerSumLE::PropagateAtLevelZero() {
264 // TODO(user): Deal with enforcements. It is just a bit of code to read the
265 // value of the literals at level zero.
266 if (!enforcement_literals_.empty()) return true;
267
268 // Compute the new lower bound and update the reversible structures.
269 IntegerValue min_activity = IntegerValue(0);
270 const int num_vars = vars_.size();
271 for (int i = 0; i < num_vars; ++i) {
272 const IntegerVariable var = vars_[i];
273 const IntegerValue coeff = coeffs_[i];
274 const IntegerValue lb = integer_trail_->LevelZeroLowerBound(var);
275 const IntegerValue ub = integer_trail_->LevelZeroUpperBound(var);
276 max_variations_[i] = (ub - lb) * coeff;
277 min_activity += lb * coeff;
278 }
279 time_limit_->AdvanceDeterministicTime(static_cast<double>(num_vars * 1e-9));
280
281 // Conflict?
282 const IntegerValue slack = upper_bound_ - min_activity;
283 if (slack < 0) {
284 return integer_trail_->ReportConflict({}, {});
285 }
286
287 // The lower bound of all the variables except one can be used to update the
288 // upper bound of the last one.
289 for (int i = 0; i < num_vars; ++i) {
290 if (max_variations_[i] <= slack) continue;
291
292 const IntegerVariable var = vars_[i];
293 const IntegerValue coeff = coeffs_[i];
294 const IntegerValue div = slack / coeff;
295 const IntegerValue new_ub = integer_trail_->LevelZeroLowerBound(var) + div;
296 if (!integer_trail_->Enqueue(IntegerLiteral::LowerOrEqual(var, new_ub), {},
297 {})) {
298 return false;
299 }
300 }
301
302 return true;
303}
304
305void IntegerSumLE::RegisterWith(GenericLiteralWatcher* watcher) {
306 is_registered_ = true;
307 const int id = watcher->Register(this);
308 for (const IntegerVariable& var : vars_) {
309 watcher->WatchLowerBound(var, id);
310 }
311 for (const Literal literal : enforcement_literals_) {
312 // We only watch the true direction.
313 //
314 // TODO(user): if there is more than one, maybe we should watch more to
315 // propagate a "conflict" as soon as only one is unassigned?
316 watcher->WatchLiteral(Literal(literal), id);
317 }
318 watcher->RegisterReversibleInt(id, &rev_num_fixed_vars_);
319}
320
321LevelZeroEquality::LevelZeroEquality(IntegerVariable target,
322 const std::vector<IntegerVariable>& vars,
323 const std::vector<IntegerValue>& coeffs,
324 Model* model)
325 : target_(target),
326 vars_(vars),
327 coeffs_(coeffs),
328 trail_(model->GetOrCreate<Trail>()),
329 integer_trail_(model->GetOrCreate<IntegerTrail>()) {
330 auto* watcher = model->GetOrCreate<GenericLiteralWatcher>();
331 const int id = watcher->Register(this);
332 watcher->SetPropagatorPriority(id, 2);
333 watcher->WatchIntegerVariable(target, id);
334 for (const IntegerVariable& var : vars_) {
335 watcher->WatchIntegerVariable(var, id);
336 }
337}
338
339// TODO(user): We could go even further than just the GCD, and do more
340// arithmetic to tighten the target bounds. See for instance a problem like
341// ej.mps.gz that we don't solve easily, but has just 3 variables! the goal is
342// to minimize X, given 31013 X - 41014 Y - 51015 Z = -31013 (all >=0, Y and Z
343// bounded with high values). I know some MIP solvers have a basic linear
344// diophantine equation support.
346 // TODO(user): Once the GCD is not 1, we could at any level make sure the
347 // objective is of the correct form. For now, this only happen in a few
348 // miplib problem that we close quickly, so I didn't add the extra code yet.
349 if (trail_->CurrentDecisionLevel() != 0) return true;
350
351 int64_t gcd = 0;
352 IntegerValue sum(0);
353 for (int i = 0; i < vars_.size(); ++i) {
354 if (integer_trail_->IsFixed(vars_[i])) {
355 sum += coeffs_[i] * integer_trail_->LowerBound(vars_[i]);
356 continue;
357 }
358 gcd = MathUtil::GCD64(gcd, std::abs(coeffs_[i].value()));
359 if (gcd == 1) break;
360 }
361 if (gcd == 0) return true; // All fixed.
362
363 if (gcd > gcd_) {
364 VLOG(1) << "Objective gcd: " << gcd;
365 }
366 CHECK_GE(gcd, gcd_);
367 gcd_ = IntegerValue(gcd);
368
369 const IntegerValue lb = integer_trail_->LowerBound(target_);
370 const IntegerValue lb_remainder = PositiveRemainder(lb - sum, gcd_);
371 if (lb_remainder != 0) {
372 if (!integer_trail_->Enqueue(
373 IntegerLiteral::GreaterOrEqual(target_, lb + gcd_ - lb_remainder),
374 {}, {}))
375 return false;
376 }
377
378 const IntegerValue ub = integer_trail_->UpperBound(target_);
379 const IntegerValue ub_remainder =
380 PositiveRemainder(ub - sum, IntegerValue(gcd));
381 if (ub_remainder != 0) {
382 if (!integer_trail_->Enqueue(
383 IntegerLiteral::LowerOrEqual(target_, ub - ub_remainder), {}, {}))
384 return false;
385 }
386
387 return true;
388}
389
390MinPropagator::MinPropagator(const std::vector<IntegerVariable>& vars,
391 IntegerVariable min_var,
392 IntegerTrail* integer_trail)
393 : vars_(vars), min_var_(min_var), integer_trail_(integer_trail) {}
394
396 if (vars_.empty()) return true;
397
398 // Count the number of interval that are possible candidate for the min.
399 // Only the intervals for which lb > current_min_ub cannot.
400 const IntegerLiteral min_ub_literal =
401 integer_trail_->UpperBoundAsLiteral(min_var_);
402 const IntegerValue current_min_ub = integer_trail_->UpperBound(min_var_);
403 int num_intervals_that_can_be_min = 0;
404 int last_possible_min_interval = 0;
405
406 IntegerValue min = kMaxIntegerValue;
407 for (int i = 0; i < vars_.size(); ++i) {
408 const IntegerValue lb = integer_trail_->LowerBound(vars_[i]);
409 min = std::min(min, lb);
410 if (lb <= current_min_ub) {
411 ++num_intervals_that_can_be_min;
412 last_possible_min_interval = i;
413 }
414 }
415
416 // Propagation a)
417 if (min > integer_trail_->LowerBound(min_var_)) {
418 integer_reason_.clear();
419 for (const IntegerVariable var : vars_) {
420 integer_reason_.push_back(IntegerLiteral::GreaterOrEqual(var, min));
421 }
422 if (!integer_trail_->Enqueue(IntegerLiteral::GreaterOrEqual(min_var_, min),
423 {}, integer_reason_)) {
424 return false;
425 }
426 }
427
428 // Propagation b)
429 if (num_intervals_that_can_be_min == 1) {
430 const IntegerValue ub_of_only_candidate =
431 integer_trail_->UpperBound(vars_[last_possible_min_interval]);
432 if (current_min_ub < ub_of_only_candidate) {
433 integer_reason_.clear();
434
435 // The reason is that all the other interval start after current_min_ub.
436 // And that min_ub has its current value.
437 integer_reason_.push_back(min_ub_literal);
438 for (const IntegerVariable var : vars_) {
439 if (var == vars_[last_possible_min_interval]) continue;
440 integer_reason_.push_back(
441 IntegerLiteral::GreaterOrEqual(var, current_min_ub + 1));
442 }
443 if (!integer_trail_->Enqueue(
444 IntegerLiteral::LowerOrEqual(vars_[last_possible_min_interval],
445 current_min_ub),
446 {}, integer_reason_)) {
447 return false;
448 }
449 }
450 }
451
452 // Conflict.
453 //
454 // TODO(user): Not sure this code is useful since this will be detected
455 // by the fact that the [lb, ub] of the min is empty. It depends on the
456 // propagation order though, but probably the precedences propagator would
457 // propagate before this one. So change this to a CHECK?
458 if (num_intervals_that_can_be_min == 0) {
459 integer_reason_.clear();
460
461 // Almost the same as propagation b).
462 integer_reason_.push_back(min_ub_literal);
463 for (const IntegerVariable var : vars_) {
464 integer_reason_.push_back(
465 IntegerLiteral::GreaterOrEqual(var, current_min_ub + 1));
466 }
467 return integer_trail_->ReportConflict(integer_reason_);
468 }
469
470 return true;
471}
472
474 const int id = watcher->Register(this);
475 for (const IntegerVariable& var : vars_) {
476 watcher->WatchLowerBound(var, id);
477 }
478 watcher->WatchUpperBound(min_var_, id);
479}
480
481LinMinPropagator::LinMinPropagator(const std::vector<LinearExpression>& exprs,
482 IntegerVariable min_var, Model* model)
483 : exprs_(exprs),
484 min_var_(min_var),
485 model_(model),
486 integer_trail_(model_->GetOrCreate<IntegerTrail>()) {}
487
488bool LinMinPropagator::PropagateLinearUpperBound(
489 const std::vector<IntegerVariable>& vars,
490 const std::vector<IntegerValue>& coeffs, const IntegerValue upper_bound) {
491 IntegerValue sum_lb = IntegerValue(0);
492 const int num_vars = vars.size();
493 std::vector<IntegerValue> max_variations;
494 for (int i = 0; i < num_vars; ++i) {
495 const IntegerVariable var = vars[i];
496 const IntegerValue coeff = coeffs[i];
497 // The coefficients are assumed to be positive for this to work properly.
498 DCHECK_GE(coeff, 0);
499 const IntegerValue lb = integer_trail_->LowerBound(var);
500 const IntegerValue ub = integer_trail_->UpperBound(var);
501 max_variations.push_back((ub - lb) * coeff);
502 sum_lb += lb * coeff;
503 }
504
505 model_->GetOrCreate<TimeLimit>()->AdvanceDeterministicTime(
506 static_cast<double>(num_vars) * 1e-9);
507
508 const IntegerValue slack = upper_bound - sum_lb;
509
510 std::vector<IntegerLiteral> linear_sum_reason;
511 std::vector<IntegerValue> reason_coeffs;
512 for (int i = 0; i < num_vars; ++i) {
513 const IntegerVariable var = vars[i];
514 if (!integer_trail_->VariableLowerBoundIsFromLevelZero(var)) {
515 linear_sum_reason.push_back(integer_trail_->LowerBoundAsLiteral(var));
516 reason_coeffs.push_back(coeffs[i]);
517 }
518 }
519 if (slack < 0) {
520 // Conflict.
521 integer_trail_->RelaxLinearReason(-slack - 1, reason_coeffs,
522 &linear_sum_reason);
523 std::vector<IntegerLiteral> local_reason =
524 integer_reason_for_unique_candidate_;
525 local_reason.insert(local_reason.end(), linear_sum_reason.begin(),
526 linear_sum_reason.end());
527 return integer_trail_->ReportConflict({}, local_reason);
528 }
529
530 // The lower bound of all the variables except one can be used to update the
531 // upper bound of the last one.
532 for (int i = 0; i < num_vars; ++i) {
533 if (max_variations[i] <= slack) continue;
534
535 const IntegerVariable var = vars[i];
536 const IntegerValue coeff = coeffs[i];
537 const IntegerValue div = slack / coeff;
538 const IntegerValue new_ub = integer_trail_->LowerBound(var) + div;
539
540 const IntegerValue propagation_slack = (div + 1) * coeff - slack - 1;
541 if (!integer_trail_->Enqueue(
543 /*lazy_reason=*/[this, &vars, &coeffs, propagation_slack](
544 IntegerLiteral i_lit, int trail_index,
545 std::vector<Literal>* literal_reason,
546 std::vector<int>* trail_indices_reason) {
547 literal_reason->clear();
548 trail_indices_reason->clear();
549 std::vector<IntegerValue> reason_coeffs;
550 const int size = vars.size();
551 for (int i = 0; i < size; ++i) {
552 const IntegerVariable var = vars[i];
553 if (PositiveVariable(var) == PositiveVariable(i_lit.var)) {
554 continue;
555 }
556 const int index =
557 integer_trail_->FindTrailIndexOfVarBefore(var, trail_index);
558 if (index >= 0) {
559 trail_indices_reason->push_back(index);
560 if (propagation_slack > 0) {
561 reason_coeffs.push_back(coeffs[i]);
562 }
563 }
564 }
565 if (propagation_slack > 0) {
566 integer_trail_->RelaxLinearReason(
567 propagation_slack, reason_coeffs, trail_indices_reason);
568 }
569 // Now add the old integer_reason that triggered this propatation.
570 for (IntegerLiteral reason_lit :
571 integer_reason_for_unique_candidate_) {
572 const int index = integer_trail_->FindTrailIndexOfVarBefore(
573 reason_lit.var, trail_index);
574 if (index >= 0) {
575 trail_indices_reason->push_back(index);
576 }
577 }
578 })) {
579 return false;
580 }
581 }
582 return true;
583}
584
586 if (exprs_.empty()) return true;
587
588 // Count the number of interval that are possible candidate for the min.
589 // Only the intervals for which lb > current_min_ub cannot.
590 const IntegerValue current_min_ub = integer_trail_->UpperBound(min_var_);
591 int num_intervals_that_can_be_min = 0;
592 int last_possible_min_interval = 0;
593
594 expr_lbs_.clear();
595 IntegerValue min_of_linear_expression_lb = kMaxIntegerValue;
596 for (int i = 0; i < exprs_.size(); ++i) {
597 const IntegerValue lb = LinExprLowerBound(exprs_[i], *integer_trail_);
598 expr_lbs_.push_back(lb);
599 min_of_linear_expression_lb = std::min(min_of_linear_expression_lb, lb);
600 if (lb <= current_min_ub) {
601 ++num_intervals_that_can_be_min;
602 last_possible_min_interval = i;
603 }
604 }
605
606 // Propagation a) lb(min) >= lb(MIN(exprs)) = MIN(lb(exprs));
607
608 // Conflict will be detected by the fact that the [lb, ub] of the min is
609 // empty. In case of conflict, we just need the reason for pushing UB + 1.
610 if (min_of_linear_expression_lb > current_min_ub) {
611 min_of_linear_expression_lb = current_min_ub + 1;
612 }
613 if (min_of_linear_expression_lb > integer_trail_->LowerBound(min_var_)) {
614 std::vector<IntegerLiteral> local_reason;
615 for (int i = 0; i < exprs_.size(); ++i) {
616 const IntegerValue slack = expr_lbs_[i] - min_of_linear_expression_lb;
617 integer_trail_->AppendRelaxedLinearReason(slack, exprs_[i].coeffs,
618 exprs_[i].vars, &local_reason);
619 }
620 if (!integer_trail_->Enqueue(IntegerLiteral::GreaterOrEqual(
621 min_var_, min_of_linear_expression_lb),
622 {}, local_reason)) {
623 return false;
624 }
625 }
626
627 // Propagation b) ub(min) >= ub(MIN(exprs)) and we can't propagate anything
628 // here unless there is just one possible expression 'e' that can be the min:
629 // for all u != e, lb(u) > ub(min);
630 // In this case, ub(min) >= ub(e).
631 if (num_intervals_that_can_be_min == 1) {
632 const IntegerValue ub_of_only_candidate =
633 LinExprUpperBound(exprs_[last_possible_min_interval], *integer_trail_);
634 if (current_min_ub < ub_of_only_candidate) {
635 // For this propagation, we only need to fill the integer reason once at
636 // the lowest level. At higher levels this reason still remains valid.
637 if (rev_unique_candidate_ == 0) {
638 integer_reason_for_unique_candidate_.clear();
639
640 // The reason is that all the other interval start after current_min_ub.
641 // And that min_ub has its current value.
642 integer_reason_for_unique_candidate_.push_back(
643 integer_trail_->UpperBoundAsLiteral(min_var_));
644 for (int i = 0; i < exprs_.size(); ++i) {
645 if (i == last_possible_min_interval) continue;
646 const IntegerValue slack = expr_lbs_[i] - (current_min_ub + 1);
647 integer_trail_->AppendRelaxedLinearReason(
648 slack, exprs_[i].coeffs, exprs_[i].vars,
649 &integer_reason_for_unique_candidate_);
650 }
651 rev_unique_candidate_ = 1;
652 }
653
654 return PropagateLinearUpperBound(
655 exprs_[last_possible_min_interval].vars,
656 exprs_[last_possible_min_interval].coeffs,
657 current_min_ub - exprs_[last_possible_min_interval].offset);
658 }
659 }
660
661 return true;
662}
663
665 const int id = watcher->Register(this);
666 for (const LinearExpression& expr : exprs_) {
667 for (int i = 0; i < expr.vars.size(); ++i) {
668 const IntegerVariable& var = expr.vars[i];
669 const IntegerValue coeff = expr.coeffs[i];
670 if (coeff > 0) {
671 watcher->WatchLowerBound(var, id);
672 } else {
673 watcher->WatchUpperBound(var, id);
674 }
675 }
676 }
677 watcher->WatchUpperBound(min_var_, id);
678 watcher->RegisterReversibleInt(id, &rev_unique_candidate_);
679}
680
683 IntegerTrail* integer_trail)
684 : a_(a), b_(b), p_(p), integer_trail_(integer_trail) {}
685
686// We want all affine expression to be either non-negative or across zero.
687bool ProductPropagator::CanonicalizeCases() {
688 if (integer_trail_->UpperBound(a_) <= 0) {
689 a_ = a_.Negated();
690 p_ = p_.Negated();
691 }
692 if (integer_trail_->UpperBound(b_) <= 0) {
693 b_ = b_.Negated();
694 p_ = p_.Negated();
695 }
696
697 // If both a and b positive, p must be too.
698 if (integer_trail_->LowerBound(a_) >= 0 &&
699 integer_trail_->LowerBound(b_) >= 0) {
700 return integer_trail_->SafeEnqueue(
701 p_.GreaterOrEqual(0), {a_.GreaterOrEqual(0), b_.GreaterOrEqual(0)});
702 }
703
704 // Otherwise, make sure p is non-negative or accros zero.
705 if (integer_trail_->UpperBound(p_) <= 0) {
706 if (integer_trail_->LowerBound(a_) < 0) {
707 DCHECK_GT(integer_trail_->UpperBound(a_), 0);
708 a_ = a_.Negated();
709 p_ = p_.Negated();
710 } else {
711 DCHECK_LT(integer_trail_->LowerBound(b_), 0);
712 DCHECK_GT(integer_trail_->UpperBound(b_), 0);
713 b_ = b_.Negated();
714 p_ = p_.Negated();
715 }
716 }
717
718 return true;
719}
720
721// Note that this propagation is exact, except on the domain of p as this
722// involves more complex arithmetic.
723//
724// TODO(user): We could tighten the bounds on p by removing extreme value that
725// do not contains divisor in the domains of a or b. There is an algo in O(
726// smallest domain size between a or b).
727bool ProductPropagator::PropagateWhenAllNonNegative() {
728 const IntegerValue max_a = integer_trail_->UpperBound(a_);
729 const IntegerValue max_b = integer_trail_->UpperBound(b_);
730 const IntegerValue new_max(CapProd(max_a.value(), max_b.value()));
731 if (new_max < integer_trail_->UpperBound(p_)) {
732 if (!integer_trail_->SafeEnqueue(
733 p_.LowerOrEqual(new_max),
734 {integer_trail_->UpperBoundAsLiteral(a_),
735 integer_trail_->UpperBoundAsLiteral(b_), a_.GreaterOrEqual(0),
736 b_.GreaterOrEqual(0)})) {
737 return false;
738 }
739 }
740
741 const IntegerValue min_a = integer_trail_->LowerBound(a_);
742 const IntegerValue min_b = integer_trail_->LowerBound(b_);
743 const IntegerValue new_min(CapProd(min_a.value(), min_b.value()));
744 if (new_min > integer_trail_->LowerBound(p_)) {
745 if (!integer_trail_->SafeEnqueue(
746 p_.GreaterOrEqual(new_min),
747 {integer_trail_->LowerBoundAsLiteral(a_),
748 integer_trail_->LowerBoundAsLiteral(b_)})) {
749 return false;
750 }
751 }
752
753 for (int i = 0; i < 2; ++i) {
754 const AffineExpression a = i == 0 ? a_ : b_;
755 const AffineExpression b = i == 0 ? b_ : a_;
756 const IntegerValue max_a = integer_trail_->UpperBound(a);
757 const IntegerValue min_b = integer_trail_->LowerBound(b);
758 const IntegerValue min_p = integer_trail_->LowerBound(p_);
759 const IntegerValue max_p = integer_trail_->UpperBound(p_);
760 const IntegerValue prod(CapProd(max_a.value(), min_b.value()));
761 if (prod > max_p) {
762 if (!integer_trail_->SafeEnqueue(a.LowerOrEqual(FloorRatio(max_p, min_b)),
763 {integer_trail_->LowerBoundAsLiteral(b),
764 integer_trail_->UpperBoundAsLiteral(p_),
765 p_.GreaterOrEqual(0)})) {
766 return false;
767 }
768 } else if (prod < min_p) {
769 if (!integer_trail_->SafeEnqueue(
770 b.GreaterOrEqual(CeilRatio(min_p, max_a)),
771 {integer_trail_->UpperBoundAsLiteral(a),
772 integer_trail_->LowerBoundAsLiteral(p_), a.GreaterOrEqual(0)})) {
773 return false;
774 }
775 }
776 }
777
778 return true;
779}
780
781// This assumes p > 0, p = a * X, and X can take any value.
782// We can propagate max of a by computing a bound on the min b when positive.
783// The expression b is just used to detect when there is no solution given the
784// upper bound of b.
785bool ProductPropagator::PropagateMaxOnPositiveProduct(AffineExpression a,
786 AffineExpression b,
787 IntegerValue min_p,
788 IntegerValue max_p) {
789 const IntegerValue max_a = integer_trail_->UpperBound(a);
790 if (max_a <= 0) return true;
791 DCHECK_GT(min_p, 0);
792
793 if (max_a >= min_p) {
794 if (max_p < max_a) {
795 if (!integer_trail_->SafeEnqueue(
796 a.LowerOrEqual(max_p),
797 {p_.LowerOrEqual(max_p), p_.GreaterOrEqual(1)})) {
798 return false;
799 }
800 }
801 return true;
802 }
803
804 const IntegerValue min_pos_b = CeilRatio(min_p, max_a);
805 if (min_pos_b > integer_trail_->UpperBound(b)) {
806 if (!integer_trail_->SafeEnqueue(
807 b.LowerOrEqual(0), {integer_trail_->LowerBoundAsLiteral(p_),
808 integer_trail_->UpperBoundAsLiteral(a),
809 integer_trail_->UpperBoundAsLiteral(b)})) {
810 return false;
811 }
812 return true;
813 }
814
815 const IntegerValue new_max_a = FloorRatio(max_p, min_pos_b);
816 if (new_max_a < integer_trail_->UpperBound(a)) {
817 if (!integer_trail_->SafeEnqueue(
818 a.LowerOrEqual(new_max_a),
819 {integer_trail_->LowerBoundAsLiteral(p_),
820 integer_trail_->UpperBoundAsLiteral(a),
821 integer_trail_->UpperBoundAsLiteral(p_)})) {
822 return false;
823 }
824 }
825 return true;
826}
827
829 if (!CanonicalizeCases()) return false;
830
831 // In the most common case, we use better reasons even though the code
832 // below would propagate the same.
833 const int64_t min_a = integer_trail_->LowerBound(a_).value();
834 const int64_t min_b = integer_trail_->LowerBound(b_).value();
835 if (min_a >= 0 && min_b >= 0) {
836 // This was done by CanonicalizeCases().
837 DCHECK_GE(integer_trail_->LowerBound(p_), 0);
838 return PropagateWhenAllNonNegative();
839 }
840
841 // Lets propagate on p_ first, the max/min is given by one of: max_a * max_b,
842 // max_a * min_b, min_a * max_b, min_a * min_b. This is true, because any
843 // product x * y, depending on the sign, is dominated by one of these.
844 //
845 // TODO(user): In the reasons, including all 4 bounds is always correct, but
846 // we might be able to relax some of them.
847 const int64_t max_a = integer_trail_->UpperBound(a_).value();
848 const int64_t max_b = integer_trail_->UpperBound(b_).value();
849 const IntegerValue p1(CapProd(max_a, max_b));
850 const IntegerValue p2(CapProd(max_a, min_b));
851 const IntegerValue p3(CapProd(min_a, max_b));
852 const IntegerValue p4(CapProd(min_a, min_b));
853 const IntegerValue new_max_p = std::max({p1, p2, p3, p4});
854 if (new_max_p < integer_trail_->UpperBound(p_)) {
855 if (!integer_trail_->SafeEnqueue(
856 p_.LowerOrEqual(new_max_p),
857 {integer_trail_->LowerBoundAsLiteral(a_),
858 integer_trail_->LowerBoundAsLiteral(b_),
859 integer_trail_->UpperBoundAsLiteral(a_),
860 integer_trail_->UpperBoundAsLiteral(b_)})) {
861 return false;
862 }
863 }
864 const IntegerValue new_min_p = std::min({p1, p2, p3, p4});
865 if (new_min_p > integer_trail_->LowerBound(p_)) {
866 if (!integer_trail_->SafeEnqueue(
867 p_.GreaterOrEqual(new_min_p),
868 {integer_trail_->LowerBoundAsLiteral(a_),
869 integer_trail_->LowerBoundAsLiteral(b_),
870 integer_trail_->UpperBoundAsLiteral(a_),
871 integer_trail_->UpperBoundAsLiteral(b_)})) {
872 return false;
873 }
874 }
875
876 // Lets propagate on a and b.
877 const IntegerValue min_p = integer_trail_->LowerBound(p_);
878 const IntegerValue max_p = integer_trail_->UpperBound(p_);
879
880 // We need a bit more propagation to avoid bad cases below.
881 const bool zero_is_possible = min_p <= 0;
882 if (!zero_is_possible) {
883 if (integer_trail_->LowerBound(a_) == 0) {
884 if (!integer_trail_->SafeEnqueue(
885 a_.GreaterOrEqual(1),
886 {p_.GreaterOrEqual(1), a_.GreaterOrEqual(0)})) {
887 return false;
888 }
889 }
890 if (integer_trail_->LowerBound(b_) == 0) {
891 if (!integer_trail_->SafeEnqueue(
892 b_.GreaterOrEqual(1),
893 {p_.GreaterOrEqual(1), b_.GreaterOrEqual(0)})) {
894 return false;
895 }
896 }
897 if (integer_trail_->LowerBound(a_) >= 0 &&
898 integer_trail_->LowerBound(b_) <= 0) {
899 return integer_trail_->SafeEnqueue(
900 b_.GreaterOrEqual(1), {a_.GreaterOrEqual(0), p_.GreaterOrEqual(1)});
901 }
902 if (integer_trail_->LowerBound(b_) >= 0 &&
903 integer_trail_->LowerBound(a_) <= 0) {
904 return integer_trail_->SafeEnqueue(
905 a_.GreaterOrEqual(1), {b_.GreaterOrEqual(0), p_.GreaterOrEqual(1)});
906 }
907 }
908
909 for (int i = 0; i < 2; ++i) {
910 // p = a * b, what is the min/max of a?
911 const AffineExpression a = i == 0 ? a_ : b_;
912 const AffineExpression b = i == 0 ? b_ : a_;
913 const IntegerValue max_b = integer_trail_->UpperBound(b);
914 const IntegerValue min_b = integer_trail_->LowerBound(b);
915
916 // If the domain of b contain zero, we can't propagate anything on a.
917 // Because of CanonicalizeCases(), we just deal with min_b > 0 here.
918 if (zero_is_possible && min_b <= 0) continue;
919
920 // Here both a and b are across zero, but zero is not possible.
921 if (min_b < 0 && max_b > 0) {
922 CHECK_GT(min_p, 0); // Because zero is not possible.
923
924 // If a is not across zero, we will deal with this on the next
925 // Propagate() call.
926 if (!PropagateMaxOnPositiveProduct(a, b, min_p, max_p)) {
927 return false;
928 }
929 if (!PropagateMaxOnPositiveProduct(a.Negated(), b.Negated(), min_p,
930 max_p)) {
931 return false;
932 }
933 continue;
934 }
935
936 // This shouldn't happen here.
937 // If it does, we should reach the fixed point on the next iteration.
938 if (min_b <= 0) continue;
939 if (min_p >= 0) {
940 return integer_trail_->SafeEnqueue(
941 a.GreaterOrEqual(0), {p_.GreaterOrEqual(0), b.GreaterOrEqual(1)});
942 }
943 if (max_p <= 0) {
944 return integer_trail_->SafeEnqueue(
945 a.LowerOrEqual(0), {p_.LowerOrEqual(0), b.GreaterOrEqual(1)});
946 }
947
948 // So min_b > 0 and p is across zero: min_p < 0 and max_p > 0.
949 const IntegerValue new_max_a = FloorRatio(max_p, min_b);
950 if (new_max_a < integer_trail_->UpperBound(a)) {
951 if (!integer_trail_->SafeEnqueue(
952 a.LowerOrEqual(new_max_a),
953 {integer_trail_->UpperBoundAsLiteral(p_),
954 integer_trail_->LowerBoundAsLiteral(b)})) {
955 return false;
956 }
957 }
958 const IntegerValue new_min_a = CeilRatio(min_p, min_b);
959 if (new_min_a > integer_trail_->LowerBound(a)) {
960 if (!integer_trail_->SafeEnqueue(
961 a.GreaterOrEqual(new_min_a),
962 {integer_trail_->LowerBoundAsLiteral(p_),
963 integer_trail_->LowerBoundAsLiteral(b)})) {
964 return false;
965 }
966 }
967 }
968
969 return true;
970}
971
973 const int id = watcher->Register(this);
974 watcher->WatchAffineExpression(a_, id);
975 watcher->WatchAffineExpression(b_, id);
976 watcher->WatchAffineExpression(p_, id);
978}
979
981 IntegerTrail* integer_trail)
982 : x_(x), s_(s), integer_trail_(integer_trail) {
983 CHECK_GE(integer_trail->LevelZeroLowerBound(x), 0);
984}
985
986// Propagation from x to s: s in [min_x * min_x, max_x * max_x].
987// Propagation from s to x: x in [ceil(sqrt(min_s)), floor(sqrt(max_s))].
989 const IntegerValue min_x = integer_trail_->LowerBound(x_);
990 const IntegerValue min_s = integer_trail_->LowerBound(s_);
991 const IntegerValue min_x_square(CapProd(min_x.value(), min_x.value()));
992 if (min_x_square > min_s) {
993 if (!integer_trail_->SafeEnqueue(s_.GreaterOrEqual(min_x_square),
994 {x_.GreaterOrEqual(min_x)})) {
995 return false;
996 }
997 } else if (min_x_square < min_s) {
998 const IntegerValue new_min(CeilSquareRoot(min_s.value()));
999 if (!integer_trail_->SafeEnqueue(
1000 x_.GreaterOrEqual(new_min),
1001 {s_.GreaterOrEqual((new_min - 1) * (new_min - 1) + 1)})) {
1002 return false;
1003 }
1004 }
1005
1006 const IntegerValue max_x = integer_trail_->UpperBound(x_);
1007 const IntegerValue max_s = integer_trail_->UpperBound(s_);
1008 const IntegerValue max_x_square(CapProd(max_x.value(), max_x.value()));
1009 if (max_x_square < max_s) {
1010 if (!integer_trail_->SafeEnqueue(s_.LowerOrEqual(max_x_square),
1011 {x_.LowerOrEqual(max_x)})) {
1012 return false;
1013 }
1014 } else if (max_x_square > max_s) {
1015 const IntegerValue new_max(FloorSquareRoot(max_s.value()));
1016 if (!integer_trail_->SafeEnqueue(
1017 x_.LowerOrEqual(new_max),
1018 {s_.LowerOrEqual(IntegerValue(CapProd(new_max.value() + 1,
1019 new_max.value() + 1)) -
1020 1)})) {
1021 return false;
1022 }
1023 }
1024
1025 return true;
1026}
1027
1029 const int id = watcher->Register(this);
1030 watcher->WatchAffineExpression(x_, id);
1031 watcher->WatchAffineExpression(s_, id);
1033}
1034
1036 AffineExpression denom,
1037 AffineExpression div,
1038 IntegerTrail* integer_trail)
1039 : num_(num),
1040 denom_(denom),
1041 div_(div),
1042 negated_num_(num.Negated()),
1043 negated_div_(div.Negated()),
1044 integer_trail_(integer_trail) {
1045 // The denominator can never be zero.
1046 CHECK_GT(integer_trail->LevelZeroLowerBound(denom), 0);
1047}
1048
1050 if (!PropagateSigns()) return false;
1051
1052 if (integer_trail_->UpperBound(num_) >= 0 &&
1053 integer_trail_->UpperBound(div_) >= 0 &&
1054 !PropagateUpperBounds(num_, denom_, div_)) {
1055 return false;
1056 }
1057
1058 if (integer_trail_->UpperBound(negated_num_) >= 0 &&
1059 integer_trail_->UpperBound(negated_div_) >= 0 &&
1060 !PropagateUpperBounds(negated_num_, denom_, negated_div_)) {
1061 return false;
1062 }
1063
1064 if (integer_trail_->LowerBound(num_) >= 0 &&
1065 integer_trail_->LowerBound(div_) >= 0) {
1066 return PropagatePositiveDomains(num_, denom_, div_);
1067 }
1068
1069 if (integer_trail_->UpperBound(num_) <= 0 &&
1070 integer_trail_->UpperBound(div_) <= 0) {
1071 return PropagatePositiveDomains(negated_num_, denom_, negated_div_);
1072 }
1073
1074 return true;
1075}
1076
1077bool DivisionPropagator::PropagateSigns() {
1078 const IntegerValue min_num = integer_trail_->LowerBound(num_);
1079 const IntegerValue max_num = integer_trail_->UpperBound(num_);
1080 const IntegerValue min_div = integer_trail_->LowerBound(div_);
1081 const IntegerValue max_div = integer_trail_->UpperBound(div_);
1082
1083 // If num >= 0, as denom > 0, then div must be >= 0.
1084 if (min_num >= 0 && min_div < 0) {
1085 if (!integer_trail_->SafeEnqueue(div_.GreaterOrEqual(0),
1086 {num_.GreaterOrEqual(0)})) {
1087 return false;
1088 }
1089 }
1090
1091 // If div > 0, as denom > 0, then num must be > 0.
1092 if (min_num <= 0 && min_div > 0) {
1093 if (!integer_trail_->SafeEnqueue(num_.GreaterOrEqual(1),
1094 {div_.GreaterOrEqual(1)})) {
1095 return false;
1096 }
1097 }
1098
1099 // If num <= 0, as denom > 0, then div must be <= 0.
1100 if (max_num <= 0 && max_div > 0) {
1101 if (!integer_trail_->SafeEnqueue(div_.LowerOrEqual(0),
1102 {num_.LowerOrEqual(0)})) {
1103 return false;
1104 }
1105 }
1106
1107 // If div < 0, as denom > 0, then num must be < 0.
1108 if (max_num >= 0 && max_div < 0) {
1109 if (!integer_trail_->SafeEnqueue(num_.LowerOrEqual(-1),
1110 {div_.LowerOrEqual(-1)})) {
1111 return false;
1112 }
1113 }
1114
1115 return true;
1116}
1117
1118bool DivisionPropagator::PropagateUpperBounds(AffineExpression num,
1119 AffineExpression denom,
1120 AffineExpression div) {
1121 const IntegerValue max_num = integer_trail_->UpperBound(num);
1122 const IntegerValue min_denom = integer_trail_->LowerBound(denom);
1123 const IntegerValue max_denom = integer_trail_->UpperBound(denom);
1124 const IntegerValue max_div = integer_trail_->UpperBound(div);
1125
1126 const IntegerValue new_max_div = max_num / min_denom;
1127 if (max_div > new_max_div) {
1128 if (!integer_trail_->SafeEnqueue(
1129 div.LowerOrEqual(new_max_div),
1130 {integer_trail_->UpperBoundAsLiteral(num),
1131 integer_trail_->LowerBoundAsLiteral(denom)})) {
1132 return false;
1133 }
1134 }
1135
1136 // We start from num / denom <= max_div.
1137 // num < (max_div + 1) * denom
1138 // num + 1 <= (max_div + 1) * max_denom.
1139 const IntegerValue new_max_num =
1140 IntegerValue(CapAdd(CapProd(max_div.value() + 1, max_denom.value()), -1));
1141 if (max_num > new_max_num) {
1142 if (!integer_trail_->SafeEnqueue(
1143 num.LowerOrEqual(new_max_num),
1144 {integer_trail_->UpperBoundAsLiteral(denom),
1145 integer_trail_->UpperBoundAsLiteral(div)})) {
1146 return false;
1147 }
1148 }
1149
1150 return true;
1151}
1152
1153bool DivisionPropagator::PropagatePositiveDomains(AffineExpression num,
1154 AffineExpression denom,
1155 AffineExpression div) {
1156 const IntegerValue min_num = integer_trail_->LowerBound(num);
1157 const IntegerValue max_num = integer_trail_->UpperBound(num);
1158 const IntegerValue min_denom = integer_trail_->LowerBound(denom);
1159 const IntegerValue max_denom = integer_trail_->UpperBound(denom);
1160 const IntegerValue min_div = integer_trail_->LowerBound(div);
1161 const IntegerValue max_div = integer_trail_->UpperBound(div);
1162
1163 const IntegerValue new_min_div = min_num / max_denom;
1164 if (min_div < new_min_div) {
1165 if (!integer_trail_->SafeEnqueue(
1166 div.GreaterOrEqual(new_min_div),
1167 {integer_trail_->LowerBoundAsLiteral(num),
1168 integer_trail_->UpperBoundAsLiteral(denom)})) {
1169 return false;
1170 }
1171 }
1172
1173 // We start from num / denom >= min_div.
1174 // num >= min_div * denom.
1175 // num >= min_div * min_denom.
1176 const IntegerValue new_min_num =
1177 IntegerValue(CapProd(min_denom.value(), min_div.value()));
1178 if (min_num < new_min_num) {
1179 if (!integer_trail_->SafeEnqueue(
1180 num.GreaterOrEqual(new_min_num),
1181 {integer_trail_->LowerBoundAsLiteral(denom),
1182 integer_trail_->LowerBoundAsLiteral(div)})) {
1183 return false;
1184 }
1185 }
1186
1187 // We start with num / denom >= min_div.
1188 // So num >= min_div * denom
1189 // If min_div == 0 we can't deduce anything.
1190 // Otherwise, denom <= num / min_div and denom <= max_num / min_div.
1191 if (min_div > 0) {
1192 const IntegerValue new_max_denom = max_num / min_div;
1193 if (max_denom > new_max_denom) {
1194 if (!integer_trail_->SafeEnqueue(
1195 denom.LowerOrEqual(new_max_denom),
1196 {integer_trail_->UpperBoundAsLiteral(num), num.GreaterOrEqual(0),
1197 integer_trail_->LowerBoundAsLiteral(div)})) {
1198 return false;
1199 }
1200 }
1201 }
1202
1203 // denom >= CeilRatio(num + 1, max_div+1)
1204 // >= CeilRatio(min_num + 1, max_div +).
1205 const IntegerValue new_min_denom = CeilRatio(min_num + 1, max_div + 1);
1206 if (min_denom < new_min_denom) {
1207 if (!integer_trail_->SafeEnqueue(denom.GreaterOrEqual(new_min_denom),
1208 {integer_trail_->LowerBoundAsLiteral(num),
1209 integer_trail_->UpperBoundAsLiteral(div),
1210 div.GreaterOrEqual(0)})) {
1211 return false;
1212 }
1213 }
1214
1215 return true;
1216}
1217
1219 const int id = watcher->Register(this);
1220 watcher->WatchAffineExpression(num_, id);
1221 watcher->WatchAffineExpression(denom_, id);
1222 watcher->WatchAffineExpression(div_, id);
1224}
1225
1227 IntegerValue b,
1229 IntegerTrail* integer_trail)
1230 : a_(a), b_(b), c_(c), integer_trail_(integer_trail) {
1231 CHECK_GT(b_, 0);
1232}
1233
1235 const IntegerValue min_a = integer_trail_->LowerBound(a_);
1236 const IntegerValue max_a = integer_trail_->UpperBound(a_);
1237 IntegerValue min_c = integer_trail_->LowerBound(c_);
1238 IntegerValue max_c = integer_trail_->UpperBound(c_);
1239
1240 if (max_a / b_ < max_c) {
1241 max_c = max_a / b_;
1242 if (!integer_trail_->SafeEnqueue(
1243 c_.LowerOrEqual(max_c),
1244 {integer_trail_->UpperBoundAsLiteral(a_)})) {
1245 return false;
1246 }
1247 } else if (max_a / b_ > max_c) {
1248 const IntegerValue new_max_a =
1249 max_c >= 0 ? max_c * b_ + b_ - 1
1250 : IntegerValue(CapProd(max_c.value(), b_.value()));
1251 CHECK_LT(new_max_a, max_a);
1252 if (!integer_trail_->SafeEnqueue(
1253 a_.LowerOrEqual(new_max_a),
1254 {integer_trail_->UpperBoundAsLiteral(c_)})) {
1255 return false;
1256 }
1257 }
1258
1259 if (min_a / b_ > min_c) {
1260 min_c = min_a / b_;
1261 if (!integer_trail_->SafeEnqueue(
1262 c_.GreaterOrEqual(min_c),
1263 {integer_trail_->LowerBoundAsLiteral(a_)})) {
1264 return false;
1265 }
1266 } else if (min_a / b_ < min_c) {
1267 const IntegerValue new_min_a =
1268 min_c > 0 ? IntegerValue(CapProd(min_c.value(), b_.value()))
1269 : min_c * b_ - b_ + 1;
1270 CHECK_GT(new_min_a, min_a);
1271 if (!integer_trail_->SafeEnqueue(
1272 a_.GreaterOrEqual(new_min_a),
1273 {integer_trail_->LowerBoundAsLiteral(c_)})) {
1274 return false;
1275 }
1276 }
1277
1278 return true;
1279}
1280
1282 const int id = watcher->Register(this);
1283 watcher->WatchAffineExpression(a_, id);
1284 watcher->WatchAffineExpression(c_, id);
1285}
1286
1288 IntegerValue mod,
1289 AffineExpression target,
1290 IntegerTrail* integer_trail)
1291 : expr_(expr), mod_(mod), target_(target), integer_trail_(integer_trail) {
1292 CHECK_GT(mod_, 0);
1293}
1294
1296 if (!PropagateSignsAndTargetRange()) return false;
1297 if (!PropagateOuterBounds()) return false;
1298
1299 if (integer_trail_->LowerBound(expr_) >= 0) {
1300 if (!PropagateBoundsWhenExprIsPositive(expr_, target_)) return false;
1301 } else if (integer_trail_->UpperBound(expr_) <= 0) {
1302 if (!PropagateBoundsWhenExprIsPositive(expr_.Negated(),
1303 target_.Negated())) {
1304 return false;
1305 }
1306 }
1307
1308 return true;
1309}
1310
1311bool FixedModuloPropagator::PropagateSignsAndTargetRange() {
1312 // Initial domain reduction on the target.
1313 if (integer_trail_->UpperBound(target_) >= mod_) {
1314 if (!integer_trail_->SafeEnqueue(target_.LowerOrEqual(mod_ - 1), {})) {
1315 return false;
1316 }
1317 }
1318
1319 if (integer_trail_->LowerBound(target_) <= -mod_) {
1320 if (!integer_trail_->SafeEnqueue(target_.GreaterOrEqual(1 - mod_), {})) {
1321 return false;
1322 }
1323 }
1324
1325 // The sign of target_ is fixed by the sign of expr_.
1326 if (integer_trail_->LowerBound(expr_) >= 0 &&
1327 integer_trail_->LowerBound(target_) < 0) {
1328 if (!integer_trail_->SafeEnqueue(target_.GreaterOrEqual(0),
1329 {expr_.GreaterOrEqual(0)})) {
1330 return false;
1331 }
1332 }
1333
1334 if (integer_trail_->UpperBound(expr_) <= 0 &&
1335 integer_trail_->UpperBound(target_) > 0) {
1336 if (!integer_trail_->SafeEnqueue(target_.LowerOrEqual(0),
1337 {expr_.LowerOrEqual(0)})) {
1338 return false;
1339 }
1340 }
1341
1342 return true;
1343}
1344
1345bool FixedModuloPropagator::PropagateOuterBounds() {
1346 const IntegerValue min_expr = integer_trail_->LowerBound(expr_);
1347 const IntegerValue max_expr = integer_trail_->UpperBound(expr_);
1348 const IntegerValue min_target = integer_trail_->LowerBound(target_);
1349 const IntegerValue max_target = integer_trail_->UpperBound(target_);
1350
1351 if (max_expr % mod_ > max_target) {
1352 if (!integer_trail_->SafeEnqueue(
1353 expr_.LowerOrEqual((max_expr / mod_) * mod_ + max_target),
1354 {integer_trail_->UpperBoundAsLiteral(target_),
1355 integer_trail_->UpperBoundAsLiteral(expr_)})) {
1356 return false;
1357 }
1358 }
1359
1360 if (min_expr % mod_ < min_target) {
1361 if (!integer_trail_->SafeEnqueue(
1362 expr_.GreaterOrEqual((min_expr / mod_) * mod_ + min_target),
1363 {integer_trail_->LowerBoundAsLiteral(expr_),
1364 integer_trail_->LowerBoundAsLiteral(target_)})) {
1365 return false;
1366 }
1367 }
1368
1369 if (min_expr / mod_ == max_expr / mod_) {
1370 if (min_target < min_expr % mod_) {
1371 if (!integer_trail_->SafeEnqueue(
1372 target_.GreaterOrEqual(min_expr - (min_expr / mod_) * mod_),
1373 {integer_trail_->LowerBoundAsLiteral(target_),
1374 integer_trail_->UpperBoundAsLiteral(target_),
1375 integer_trail_->LowerBoundAsLiteral(expr_),
1376 integer_trail_->UpperBoundAsLiteral(expr_)})) {
1377 return false;
1378 }
1379 }
1380
1381 if (max_target > max_expr % mod_) {
1382 if (!integer_trail_->SafeEnqueue(
1383 target_.LowerOrEqual(max_expr - (max_expr / mod_) * mod_),
1384 {integer_trail_->LowerBoundAsLiteral(target_),
1385 integer_trail_->UpperBoundAsLiteral(target_),
1386 integer_trail_->LowerBoundAsLiteral(expr_),
1387 integer_trail_->UpperBoundAsLiteral(expr_)})) {
1388 return false;
1389 }
1390 }
1391 } else if (min_expr / mod_ == 0 && min_target < 0) {
1392 // expr == target when expr <= 0.
1393 if (min_target < min_expr) {
1394 if (!integer_trail_->SafeEnqueue(
1395 target_.GreaterOrEqual(min_expr),
1396 {integer_trail_->LowerBoundAsLiteral(target_),
1397 integer_trail_->LowerBoundAsLiteral(expr_)})) {
1398 return false;
1399 }
1400 }
1401 } else if (max_expr / mod_ == 0 && max_target > 0) {
1402 // expr == target when expr >= 0.
1403 if (max_target > max_expr) {
1404 if (!integer_trail_->SafeEnqueue(
1405 target_.LowerOrEqual(max_expr),
1406 {integer_trail_->UpperBoundAsLiteral(target_),
1407 integer_trail_->UpperBoundAsLiteral(expr_)})) {
1408 return false;
1409 }
1410 }
1411 }
1412
1413 return true;
1414}
1415
1416bool FixedModuloPropagator::PropagateBoundsWhenExprIsPositive(
1417 AffineExpression expr, AffineExpression target) {
1418 const IntegerValue min_target = integer_trail_->LowerBound(target);
1419 DCHECK_GE(min_target, 0);
1420 const IntegerValue max_target = integer_trail_->UpperBound(target);
1421
1422 // The propagation rules below will not be triggered if the domain of target
1423 // covers [0..mod_ - 1].
1424 if (min_target == 0 && max_target == mod_ - 1) return true;
1425
1426 const IntegerValue min_expr = integer_trail_->LowerBound(expr);
1427 const IntegerValue max_expr = integer_trail_->UpperBound(expr);
1428
1429 if (max_expr % mod_ < min_target) {
1430 DCHECK_GE(max_expr, 0);
1431 if (!integer_trail_->SafeEnqueue(
1432 expr.LowerOrEqual((max_expr / mod_ - 1) * mod_ + max_target),
1433 {integer_trail_->UpperBoundAsLiteral(expr),
1434 integer_trail_->LowerBoundAsLiteral(target),
1435 integer_trail_->UpperBoundAsLiteral(target)})) {
1436 return false;
1437 }
1438 }
1439
1440 if (min_expr % mod_ > max_target) {
1441 DCHECK_GE(min_expr, 0);
1442 if (!integer_trail_->SafeEnqueue(
1443 expr.GreaterOrEqual((min_expr / mod_ + 1) * mod_ + min_target),
1444 {integer_trail_->LowerBoundAsLiteral(target),
1445 integer_trail_->UpperBoundAsLiteral(target),
1446 integer_trail_->LowerBoundAsLiteral(expr)})) {
1447 return false;
1448 }
1449 }
1450
1451 return true;
1452}
1453
1455 const int id = watcher->Register(this);
1456 watcher->WatchAffineExpression(expr_, id);
1457 watcher->WatchAffineExpression(target_, id);
1459}
1460
1461std::function<void(Model*)> IsOneOf(IntegerVariable var,
1462 const std::vector<Literal>& selectors,
1463 const std::vector<IntegerValue>& values) {
1464 return [=](Model* model) {
1465 IntegerTrail* integer_trail = model->GetOrCreate<IntegerTrail>();
1466 IntegerEncoder* encoder = model->GetOrCreate<IntegerEncoder>();
1467
1468 CHECK(!values.empty());
1469 CHECK_EQ(values.size(), selectors.size());
1470 std::vector<int64_t> unique_values;
1471 absl::flat_hash_map<int64_t, std::vector<Literal>> value_to_selector;
1472 for (int i = 0; i < values.size(); ++i) {
1473 unique_values.push_back(values[i].value());
1474 value_to_selector[values[i].value()].push_back(selectors[i]);
1475 }
1476 gtl::STLSortAndRemoveDuplicates(&unique_values);
1477
1478 integer_trail->UpdateInitialDomain(var, Domain::FromValues(unique_values));
1479 if (unique_values.size() == 1) {
1480 model->Add(ClauseConstraint(selectors));
1481 return;
1482 }
1483
1484 // Note that it is more efficient to call AssociateToIntegerEqualValue()
1485 // with the values ordered, like we do here.
1486 for (const int64_t v : unique_values) {
1487 const std::vector<Literal>& selectors = value_to_selector[v];
1488 if (selectors.size() == 1) {
1489 encoder->AssociateToIntegerEqualValue(selectors[0], var,
1490 IntegerValue(v));
1491 } else {
1492 const Literal l(model->Add(NewBooleanVariable()), true);
1493 model->Add(ReifiedBoolOr(selectors, l));
1494 encoder->AssociateToIntegerEqualValue(l, var, IntegerValue(v));
1495 }
1496 }
1497 };
1498}
1499
1500} // namespace sat
1501} // namespace operations_research
const std::vector< IntVar * > vars_
Definition: alldiff_cst.cc:44
int64_t max
Definition: alldiff_cst.cc:140
int64_t min
Definition: alldiff_cst.cc:139
#define CHECK(condition)
Definition: base/logging.h:495
#define CHECK_LT(val1, val2)
Definition: base/logging.h:706
#define CHECK_EQ(val1, val2)
Definition: base/logging.h:703
#define CHECK_GE(val1, val2)
Definition: base/logging.h:707
#define CHECK_GT(val1, val2)
Definition: base/logging.h:708
#define DCHECK_GE(val1, val2)
Definition: base/logging.h:895
#define DCHECK_GT(val1, val2)
Definition: base/logging.h:896
#define DCHECK_LT(val1, val2)
Definition: base/logging.h:894
#define VLOG(verboselevel)
Definition: base/logging.h:984
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)
Definition: mathutil.h:107
void SaveState(T *object)
Definition: rev.h:61
A simple class to enforce both an elapsed time limit and a deterministic time limit in the same threa...
Definition: time_limit.h:106
void AdvanceDeterministicTime(double deterministic_duration)
Advances the deterministic time.
Definition: time_limit.h:227
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 WatchLiteral(Literal l, int id, int watch_index=-1)
Definition: integer.h:1561
void WatchLowerBound(IntegerVariable var, int id, int watch_index=-1)
Definition: integer.h:1569
void WatchAffineExpression(AffineExpression e, int id)
Definition: integer.h:1278
void WatchUpperBound(IntegerVariable var, int id, int watch_index=-1)
Definition: integer.h:1587
int Register(PropagatorInterface *propagator)
Definition: integer.cc:2028
std::pair< IntegerValue, IntegerValue > ConditionalLb(IntegerLiteral integer_literal, IntegerVariable target_var) const
Definition: integer_expr.cc:92
IntegerSumLE(const std::vector< Literal > &enforcement_literals, const std::vector< IntegerVariable > &vars, const std::vector< IntegerValue > &coeffs, IntegerValue upper_bound, Model *model)
Definition: integer_expr.cc:44
ABSL_MUST_USE_RESULT bool Enqueue(IntegerLiteral i_lit, absl::Span< const Literal > literal_reason, absl::Span< const IntegerLiteral > integer_reason)
Definition: integer.cc:1048
int FindTrailIndexOfVarBefore(IntegerVariable var, int threshold) const
Definition: integer.cc:756
bool IsFixed(IntegerVariable i) const
Definition: integer.h:1453
IntegerLiteral LowerBoundAsLiteral(IntegerVariable i) const
Definition: integer.h:1477
bool ReportConflict(absl::Span< const Literal > literal_reason, absl::Span< const IntegerLiteral > integer_reason)
Definition: integer.h:924
void EnqueueLiteral(Literal literal, absl::Span< const Literal > literal_reason, absl::Span< const IntegerLiteral > integer_reason)
Definition: integer.cc:1162
IntegerValue UpperBound(IntegerVariable i) const
Definition: integer.h:1449
ABSL_MUST_USE_RESULT bool SafeEnqueue(IntegerLiteral i_lit, absl::Span< const IntegerLiteral > integer_reason)
Definition: integer.cc:1030
bool VariableLowerBoundIsFromLevelZero(IntegerVariable var) const
Definition: integer.h:941
void AppendRelaxedLinearReason(IntegerValue slack, absl::Span< const IntegerValue > coeffs, absl::Span< const IntegerVariable > vars, std::vector< IntegerLiteral > *reason) const
Definition: integer.cc:848
IntegerValue LevelZeroLowerBound(IntegerVariable var) const
Definition: integer.h:1529
void RelaxLinearReason(IntegerValue slack, absl::Span< const IntegerValue > coeffs, std::vector< IntegerLiteral > *reason) const
Definition: integer.cc:826
IntegerValue LowerBound(IntegerVariable i) const
Definition: integer.h:1445
IntegerLiteral UpperBoundAsLiteral(IntegerVariable i) const
Definition: integer.h:1482
bool UpdateInitialDomain(IntegerVariable var, Domain domain)
Definition: integer.cc:689
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.
Definition: sat/model.h:42
T * GetOrCreate()
Returns an object of type T that is unique to this model (like a "local" singleton).
Definition: sat/model.h:110
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
Definition: sat_base.h:383
bool LiteralIsTrue(Literal literal) const
Definition: sat_base.h:153
bool LiteralIsFalse(Literal literal) const
Definition: sat_base.h:150
int64_t b
int64_t a
int64_t value
IntVar *const expr_
Definition: element.cc:87
IntVar * var
Definition: expr_array.cc:1874
double upper
Definition: glpk_solver.cc:76
double upper_bound
GRBmodel * model
int index
void STLSortAndRemoveDuplicates(T *v, const LessFunc &less_func)
Definition: stl_util.h:58
void swap(IdMap< K, V > &a, IdMap< K, V > &b)
Definition: id_map.h:262
IntegerValue FloorRatio(IntegerValue dividend, IntegerValue positive_divisor)
Definition: integer.h:98
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)
Definition: sat_solver.h:965
IntegerValue CeilRatio(IntegerValue dividend, IntegerValue positive_divisor)
Definition: integer.h:89
const LiteralIndex kNoLiteralIndex(-1)
std::function< void(Model *)> ClauseConstraint(absl::Span< const Literal > literals)
Definition: sat_solver.h:935
std::function< void(Model *)> IsOneOf(IntegerVariable var, const std::vector< Literal > &selectors, const std::vector< IntegerValue > &values)
std::function< BooleanVariable(Model *)> NewBooleanVariable()
Definition: integer.h:1608
std::function< void(Model *)> LowerOrEqual(IntegerVariable v, int64_t ub)
Definition: integer.h:1706
constexpr IntegerValue kMinIntegerValue(-kMaxIntegerValue.value())
int64_t CeilSquareRoot(int64_t a)
Definition: sat/util.cc:203
IntegerVariable PositiveVariable(IntegerVariable i)
Definition: integer.h:149
IntegerValue PositiveRemainder(IntegerValue dividend, IntegerValue positive_divisor)
Definition: integer.h:113
std::function< int64_t(const Model &)> UpperBound(IntegerVariable v)
Definition: integer.h:1669
int64_t FloorSquareRoot(int64_t a)
Definition: sat/util.cc:194
std::vector< IntegerVariable > NegationOf(const std::vector< IntegerVariable > &vars)
Definition: integer.cc:47
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)
Literal literal
Definition: optimization.cc:89
if(!yyg->yy_init)
Definition: parser.yy.cc:965
AffineExpression Negated() const
Definition: integer.h:258
IntegerLiteral GreaterOrEqual(IntegerValue bound) const
Definition: integer.h:1416
IntegerLiteral LowerOrEqual(IntegerValue bound) const
Definition: integer.h:1432
static IntegerLiteral LowerOrEqual(IntegerVariable i, IntegerValue bound)
Definition: integer.h:1393
static IntegerLiteral GreaterOrEqual(IntegerVariable i, IntegerValue bound)
Definition: integer.h:1387
const double coeff