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