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