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