OR-Tools  9.1
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
80 // Reified case: If any of the enforcement_literals are false, we ignore the
81 // constraint.
82 int num_unassigned_enforcement_literal = 0;
83 LiteralIndex unique_unnasigned_literal = kNoLiteralIndex;
84 for (const Literal literal : enforcement_literals_) {
85 if (trail_->Assignment().LiteralIsFalse(literal)) return true;
86 if (!trail_->Assignment().LiteralIsTrue(literal)) {
87 ++num_unassigned_enforcement_literal;
88 unique_unnasigned_literal = literal.Index();
89 }
90 }
91
92 // Unfortunately, we can't propagate anything if we have more than one
93 // unassigned enforcement literal.
94 if (num_unassigned_enforcement_literal > 1) return true;
95
96 // Save the current sum of fixed variables.
97 if (is_registered_) {
98 rev_integer_value_repository_->SaveState(&rev_lb_fixed_vars_);
99 } else {
100 rev_num_fixed_vars_ = 0;
101 rev_lb_fixed_vars_ = 0;
102 }
103
104 // Compute the new lower bound and update the reversible structures.
105 IntegerValue lb_unfixed_vars = IntegerValue(0);
106 const int num_vars = vars_.size();
107 for (int i = rev_num_fixed_vars_; i < num_vars; ++i) {
108 const IntegerVariable var = vars_[i];
109 const IntegerValue coeff = coeffs_[i];
110 const IntegerValue lb = integer_trail_->LowerBound(var);
111 const IntegerValue ub = integer_trail_->UpperBound(var);
112 if (lb != ub) {
113 max_variations_[i] = (ub - lb) * coeff;
114 lb_unfixed_vars += lb * coeff;
115 } else {
116 // Update the set of fixed variables.
117 std::swap(vars_[i], vars_[rev_num_fixed_vars_]);
118 std::swap(coeffs_[i], coeffs_[rev_num_fixed_vars_]);
119 std::swap(max_variations_[i], max_variations_[rev_num_fixed_vars_]);
120 rev_num_fixed_vars_++;
121 rev_lb_fixed_vars_ += lb * coeff;
122 }
123 }
124 time_limit_->AdvanceDeterministicTime(
125 static_cast<double>(num_vars - rev_num_fixed_vars_) * 1e-9);
126
127 // Conflict?
128 const IntegerValue slack =
129 upper_bound_ - (rev_lb_fixed_vars_ + lb_unfixed_vars);
130 if (slack < 0) {
131 FillIntegerReason();
132 integer_trail_->RelaxLinearReason(-slack - 1, reason_coeffs_,
133 &integer_reason_);
134
135 if (num_unassigned_enforcement_literal == 1) {
136 // Propagate the only non-true literal to false.
137 const Literal to_propagate = Literal(unique_unnasigned_literal).Negated();
138 std::vector<Literal> tmp = literal_reason_;
139 tmp.erase(std::find(tmp.begin(), tmp.end(), to_propagate));
140 integer_trail_->EnqueueLiteral(to_propagate, tmp, integer_reason_);
141 return true;
142 }
143 return integer_trail_->ReportConflict(literal_reason_, integer_reason_);
144 }
145
146 // We can only propagate more if all the enforcement literals are true.
147 if (num_unassigned_enforcement_literal > 0) return true;
148
149 // The lower bound of all the variables except one can be used to update the
150 // upper bound of the last one.
151 for (int i = rev_num_fixed_vars_; i < num_vars; ++i) {
152 if (max_variations_[i] <= slack) continue;
153
154 const IntegerVariable var = vars_[i];
155 const IntegerValue coeff = coeffs_[i];
156 const IntegerValue div = slack / coeff;
157 const IntegerValue new_ub = integer_trail_->LowerBound(var) + div;
158 const IntegerValue propagation_slack = (div + 1) * coeff - slack - 1;
159 if (!integer_trail_->Enqueue(
161 /*lazy_reason=*/[this, propagation_slack](
162 IntegerLiteral i_lit, int trail_index,
163 std::vector<Literal>* literal_reason,
164 std::vector<int>* trail_indices_reason) {
165 *literal_reason = literal_reason_;
166 trail_indices_reason->clear();
167 reason_coeffs_.clear();
168 const int size = vars_.size();
169 for (int i = 0; i < size; ++i) {
170 const IntegerVariable var = vars_[i];
171 if (PositiveVariable(var) == PositiveVariable(i_lit.var)) {
172 continue;
173 }
174 const int index =
175 integer_trail_->FindTrailIndexOfVarBefore(var, trail_index);
176 if (index >= 0) {
177 trail_indices_reason->push_back(index);
178 if (propagation_slack > 0) {
179 reason_coeffs_.push_back(coeffs_[i]);
180 }
181 }
182 }
183 if (propagation_slack > 0) {
184 integer_trail_->RelaxLinearReason(
185 propagation_slack, reason_coeffs_, trail_indices_reason);
186 }
187 })) {
188 return false;
189 }
190 }
191
192 return true;
193}
194
195bool IntegerSumLE::PropagateAtLevelZero() {
196 // TODO(user): Deal with enforcements. It is just a bit of code to read the
197 // value of the literals at level zero.
198 if (!enforcement_literals_.empty()) return true;
199
200 // Compute the new lower bound and update the reversible structures.
201 IntegerValue min_activity = IntegerValue(0);
202 const int num_vars = vars_.size();
203 for (int i = 0; i < num_vars; ++i) {
204 const IntegerVariable var = vars_[i];
205 const IntegerValue coeff = coeffs_[i];
206 const IntegerValue lb = integer_trail_->LevelZeroLowerBound(var);
207 const IntegerValue ub = integer_trail_->LevelZeroUpperBound(var);
208 max_variations_[i] = (ub - lb) * coeff;
209 min_activity += lb * coeff;
210 }
211 time_limit_->AdvanceDeterministicTime(static_cast<double>(num_vars * 1e-9));
212
213 // Conflict?
214 const IntegerValue slack = upper_bound_ - min_activity;
215 if (slack < 0) {
216 return integer_trail_->ReportConflict({}, {});
217 }
218
219 // The lower bound of all the variables except one can be used to update the
220 // upper bound of the last one.
221 for (int i = 0; i < num_vars; ++i) {
222 if (max_variations_[i] <= slack) continue;
223
224 const IntegerVariable var = vars_[i];
225 const IntegerValue coeff = coeffs_[i];
226 const IntegerValue div = slack / coeff;
227 const IntegerValue new_ub = integer_trail_->LevelZeroLowerBound(var) + div;
228 if (!integer_trail_->Enqueue(IntegerLiteral::LowerOrEqual(var, new_ub), {},
229 {})) {
230 return false;
231 }
232 }
233
234 return true;
235}
236
237void IntegerSumLE::RegisterWith(GenericLiteralWatcher* watcher) {
238 is_registered_ = true;
239 const int id = watcher->Register(this);
240 for (const IntegerVariable& var : vars_) {
241 watcher->WatchLowerBound(var, id);
242 }
243 for (const Literal literal : enforcement_literals_) {
244 // We only watch the true direction.
245 //
246 // TODO(user): if there is more than one, maybe we should watch more to
247 // propagate a "conflict" as soon as only one is unassigned?
248 watcher->WatchLiteral(Literal(literal), id);
249 }
250 watcher->RegisterReversibleInt(id, &rev_num_fixed_vars_);
251}
252
253LevelZeroEquality::LevelZeroEquality(IntegerVariable target,
254 const std::vector<IntegerVariable>& vars,
255 const std::vector<IntegerValue>& coeffs,
256 Model* model)
257 : target_(target),
258 vars_(vars),
259 coeffs_(coeffs),
260 trail_(model->GetOrCreate<Trail>()),
261 integer_trail_(model->GetOrCreate<IntegerTrail>()) {
262 auto* watcher = model->GetOrCreate<GenericLiteralWatcher>();
263 const int id = watcher->Register(this);
264 watcher->SetPropagatorPriority(id, 2);
265 watcher->WatchIntegerVariable(target, id);
266 for (const IntegerVariable& var : vars_) {
267 watcher->WatchIntegerVariable(var, id);
268 }
269}
270
271// TODO(user): We could go even further than just the GCD, and do more
272// arithmetic to tighten the target bounds. See for instance a problem like
273// ej.mps.gz that we don't solve easily, but has just 3 variables! the goal is
274// to minimize X, given 31013 X - 41014 Y - 51015 Z = -31013 (all >=0, Y and Z
275// bounded with high values). I know some MIP solvers have a basic linear
276// diophantine equation support.
278 // TODO(user): Once the GCD is not 1, we could at any level make sure the
279 // objective is of the correct form. For now, this only happen in a few
280 // miplib problem that we close quickly, so I didn't add the extra code yet.
281 if (trail_->CurrentDecisionLevel() != 0) return true;
282
283 int64_t gcd = 0;
284 IntegerValue sum(0);
285 for (int i = 0; i < vars_.size(); ++i) {
286 if (integer_trail_->IsFixed(vars_[i])) {
287 sum += coeffs_[i] * integer_trail_->LowerBound(vars_[i]);
288 continue;
289 }
290 gcd = MathUtil::GCD64(gcd, std::abs(coeffs_[i].value()));
291 if (gcd == 1) break;
292 }
293 if (gcd == 0) return true; // All fixed.
294
295 if (gcd > gcd_) {
296 VLOG(1) << "Objective gcd: " << gcd;
297 }
298 CHECK_GE(gcd, gcd_);
299 gcd_ = IntegerValue(gcd);
300
301 const IntegerValue lb = integer_trail_->LowerBound(target_);
302 const IntegerValue lb_remainder = PositiveRemainder(lb - sum, gcd_);
303 if (lb_remainder != 0) {
304 if (!integer_trail_->Enqueue(
305 IntegerLiteral::GreaterOrEqual(target_, lb + gcd_ - lb_remainder),
306 {}, {}))
307 return false;
308 }
309
310 const IntegerValue ub = integer_trail_->UpperBound(target_);
311 const IntegerValue ub_remainder =
312 PositiveRemainder(ub - sum, IntegerValue(gcd));
313 if (ub_remainder != 0) {
314 if (!integer_trail_->Enqueue(
315 IntegerLiteral::LowerOrEqual(target_, ub - ub_remainder), {}, {}))
316 return false;
317 }
318
319 return true;
320}
321
322MinPropagator::MinPropagator(const std::vector<IntegerVariable>& vars,
323 IntegerVariable min_var,
324 IntegerTrail* integer_trail)
325 : vars_(vars), min_var_(min_var), integer_trail_(integer_trail) {}
326
328 if (vars_.empty()) return true;
329
330 // Count the number of interval that are possible candidate for the min.
331 // Only the intervals for which lb > current_min_ub cannot.
332 const IntegerLiteral min_ub_literal =
333 integer_trail_->UpperBoundAsLiteral(min_var_);
334 const IntegerValue current_min_ub = integer_trail_->UpperBound(min_var_);
335 int num_intervals_that_can_be_min = 0;
336 int last_possible_min_interval = 0;
337
338 IntegerValue min = kMaxIntegerValue;
339 for (int i = 0; i < vars_.size(); ++i) {
340 const IntegerValue lb = integer_trail_->LowerBound(vars_[i]);
341 min = std::min(min, lb);
342 if (lb <= current_min_ub) {
343 ++num_intervals_that_can_be_min;
344 last_possible_min_interval = i;
345 }
346 }
347
348 // Propagation a)
349 if (min > integer_trail_->LowerBound(min_var_)) {
350 integer_reason_.clear();
351 for (const IntegerVariable var : vars_) {
352 integer_reason_.push_back(IntegerLiteral::GreaterOrEqual(var, min));
353 }
354 if (!integer_trail_->Enqueue(IntegerLiteral::GreaterOrEqual(min_var_, min),
355 {}, integer_reason_)) {
356 return false;
357 }
358 }
359
360 // Propagation b)
361 if (num_intervals_that_can_be_min == 1) {
362 const IntegerValue ub_of_only_candidate =
363 integer_trail_->UpperBound(vars_[last_possible_min_interval]);
364 if (current_min_ub < ub_of_only_candidate) {
365 integer_reason_.clear();
366
367 // The reason is that all the other interval start after current_min_ub.
368 // And that min_ub has its current value.
369 integer_reason_.push_back(min_ub_literal);
370 for (const IntegerVariable var : vars_) {
371 if (var == vars_[last_possible_min_interval]) continue;
372 integer_reason_.push_back(
373 IntegerLiteral::GreaterOrEqual(var, current_min_ub + 1));
374 }
375 if (!integer_trail_->Enqueue(
376 IntegerLiteral::LowerOrEqual(vars_[last_possible_min_interval],
377 current_min_ub),
378 {}, integer_reason_)) {
379 return false;
380 }
381 }
382 }
383
384 // Conflict.
385 //
386 // TODO(user): Not sure this code is useful since this will be detected
387 // by the fact that the [lb, ub] of the min is empty. It depends on the
388 // propagation order though, but probably the precedences propagator would
389 // propagate before this one. So change this to a CHECK?
390 if (num_intervals_that_can_be_min == 0) {
391 integer_reason_.clear();
392
393 // Almost the same as propagation b).
394 integer_reason_.push_back(min_ub_literal);
395 for (const IntegerVariable var : vars_) {
396 integer_reason_.push_back(
397 IntegerLiteral::GreaterOrEqual(var, current_min_ub + 1));
398 }
399 return integer_trail_->ReportConflict(integer_reason_);
400 }
401
402 return true;
403}
404
406 const int id = watcher->Register(this);
407 for (const IntegerVariable& var : vars_) {
408 watcher->WatchLowerBound(var, id);
409 }
410 watcher->WatchUpperBound(min_var_, id);
411}
412
413LinMinPropagator::LinMinPropagator(const std::vector<LinearExpression>& exprs,
414 IntegerVariable min_var, Model* model)
415 : exprs_(exprs),
416 min_var_(min_var),
417 model_(model),
418 integer_trail_(model_->GetOrCreate<IntegerTrail>()) {}
419
420bool LinMinPropagator::PropagateLinearUpperBound(
421 const std::vector<IntegerVariable>& vars,
422 const std::vector<IntegerValue>& coeffs, const IntegerValue upper_bound) {
423 IntegerValue sum_lb = IntegerValue(0);
424 const int num_vars = vars.size();
425 std::vector<IntegerValue> max_variations;
426 for (int i = 0; i < num_vars; ++i) {
427 const IntegerVariable var = vars[i];
428 const IntegerValue coeff = coeffs[i];
429 // The coefficients are assumed to be positive for this to work properly.
430 DCHECK_GE(coeff, 0);
431 const IntegerValue lb = integer_trail_->LowerBound(var);
432 const IntegerValue ub = integer_trail_->UpperBound(var);
433 max_variations.push_back((ub - lb) * coeff);
434 sum_lb += lb * coeff;
435 }
436
437 model_->GetOrCreate<TimeLimit>()->AdvanceDeterministicTime(
438 static_cast<double>(num_vars) * 1e-9);
439
440 const IntegerValue slack = upper_bound - sum_lb;
441
442 std::vector<IntegerLiteral> linear_sum_reason;
443 std::vector<IntegerValue> reason_coeffs;
444 for (int i = 0; i < num_vars; ++i) {
445 const IntegerVariable var = vars[i];
446 if (!integer_trail_->VariableLowerBoundIsFromLevelZero(var)) {
447 linear_sum_reason.push_back(integer_trail_->LowerBoundAsLiteral(var));
448 reason_coeffs.push_back(coeffs[i]);
449 }
450 }
451 if (slack < 0) {
452 // Conflict.
453 integer_trail_->RelaxLinearReason(-slack - 1, reason_coeffs,
454 &linear_sum_reason);
455 std::vector<IntegerLiteral> local_reason =
456 integer_reason_for_unique_candidate_;
457 local_reason.insert(local_reason.end(), linear_sum_reason.begin(),
458 linear_sum_reason.end());
459 return integer_trail_->ReportConflict({}, local_reason);
460 }
461
462 // The lower bound of all the variables except one can be used to update the
463 // upper bound of the last one.
464 for (int i = 0; i < num_vars; ++i) {
465 if (max_variations[i] <= slack) continue;
466
467 const IntegerVariable var = vars[i];
468 const IntegerValue coeff = coeffs[i];
469 const IntegerValue div = slack / coeff;
470 const IntegerValue new_ub = integer_trail_->LowerBound(var) + div;
471
472 const IntegerValue propagation_slack = (div + 1) * coeff - slack - 1;
473 if (!integer_trail_->Enqueue(
475 /*lazy_reason=*/[this, &vars, &coeffs, propagation_slack](
476 IntegerLiteral i_lit, int trail_index,
477 std::vector<Literal>* literal_reason,
478 std::vector<int>* trail_indices_reason) {
479 literal_reason->clear();
480 trail_indices_reason->clear();
481 std::vector<IntegerValue> reason_coeffs;
482 const int size = vars.size();
483 for (int i = 0; i < size; ++i) {
484 const IntegerVariable var = vars[i];
485 if (PositiveVariable(var) == PositiveVariable(i_lit.var)) {
486 continue;
487 }
488 const int index =
489 integer_trail_->FindTrailIndexOfVarBefore(var, trail_index);
490 if (index >= 0) {
491 trail_indices_reason->push_back(index);
492 if (propagation_slack > 0) {
493 reason_coeffs.push_back(coeffs[i]);
494 }
495 }
496 }
497 if (propagation_slack > 0) {
498 integer_trail_->RelaxLinearReason(
499 propagation_slack, reason_coeffs, trail_indices_reason);
500 }
501 // Now add the old integer_reason that triggered this propatation.
502 for (IntegerLiteral reason_lit :
503 integer_reason_for_unique_candidate_) {
504 const int index = integer_trail_->FindTrailIndexOfVarBefore(
505 reason_lit.var, trail_index);
506 if (index >= 0) {
507 trail_indices_reason->push_back(index);
508 }
509 }
510 })) {
511 return false;
512 }
513 }
514 return true;
515}
516
518 if (exprs_.empty()) return true;
519
520 // Count the number of interval that are possible candidate for the min.
521 // Only the intervals for which lb > current_min_ub cannot.
522 const IntegerValue current_min_ub = integer_trail_->UpperBound(min_var_);
523 int num_intervals_that_can_be_min = 0;
524 int last_possible_min_interval = 0;
525
526 expr_lbs_.clear();
527 IntegerValue min_of_linear_expression_lb = kMaxIntegerValue;
528 for (int i = 0; i < exprs_.size(); ++i) {
529 const IntegerValue lb = LinExprLowerBound(exprs_[i], *integer_trail_);
530 expr_lbs_.push_back(lb);
531 min_of_linear_expression_lb = std::min(min_of_linear_expression_lb, lb);
532 if (lb <= current_min_ub) {
533 ++num_intervals_that_can_be_min;
534 last_possible_min_interval = i;
535 }
536 }
537
538 // Propagation a) lb(min) >= lb(MIN(exprs)) = MIN(lb(exprs));
539
540 // Conflict will be detected by the fact that the [lb, ub] of the min is
541 // empty. In case of conflict, we just need the reason for pushing UB + 1.
542 if (min_of_linear_expression_lb > current_min_ub) {
543 min_of_linear_expression_lb = current_min_ub + 1;
544 }
545 if (min_of_linear_expression_lb > integer_trail_->LowerBound(min_var_)) {
546 std::vector<IntegerLiteral> local_reason;
547 for (int i = 0; i < exprs_.size(); ++i) {
548 const IntegerValue slack = expr_lbs_[i] - min_of_linear_expression_lb;
549 integer_trail_->AppendRelaxedLinearReason(slack, exprs_[i].coeffs,
550 exprs_[i].vars, &local_reason);
551 }
552 if (!integer_trail_->Enqueue(IntegerLiteral::GreaterOrEqual(
553 min_var_, min_of_linear_expression_lb),
554 {}, local_reason)) {
555 return false;
556 }
557 }
558
559 // Propagation b) ub(min) >= ub(MIN(exprs)) and we can't propagate anything
560 // here unless there is just one possible expression 'e' that can be the min:
561 // for all u != e, lb(u) > ub(min);
562 // In this case, ub(min) >= ub(e).
563 if (num_intervals_that_can_be_min == 1) {
564 const IntegerValue ub_of_only_candidate =
565 LinExprUpperBound(exprs_[last_possible_min_interval], *integer_trail_);
566 if (current_min_ub < ub_of_only_candidate) {
567 // For this propagation, we only need to fill the integer reason once at
568 // the lowest level. At higher levels this reason still remains valid.
569 if (rev_unique_candidate_ == 0) {
570 integer_reason_for_unique_candidate_.clear();
571
572 // The reason is that all the other interval start after current_min_ub.
573 // And that min_ub has its current value.
574 integer_reason_for_unique_candidate_.push_back(
575 integer_trail_->UpperBoundAsLiteral(min_var_));
576 for (int i = 0; i < exprs_.size(); ++i) {
577 if (i == last_possible_min_interval) continue;
578 const IntegerValue slack = expr_lbs_[i] - (current_min_ub + 1);
579 integer_trail_->AppendRelaxedLinearReason(
580 slack, exprs_[i].coeffs, exprs_[i].vars,
581 &integer_reason_for_unique_candidate_);
582 }
583 rev_unique_candidate_ = 1;
584 }
585
586 return PropagateLinearUpperBound(
587 exprs_[last_possible_min_interval].vars,
588 exprs_[last_possible_min_interval].coeffs,
589 current_min_ub - exprs_[last_possible_min_interval].offset);
590 }
591 }
592
593 return true;
594}
595
597 const int id = watcher->Register(this);
598 for (const LinearExpression& expr : exprs_) {
599 for (int i = 0; i < expr.vars.size(); ++i) {
600 const IntegerVariable& var = expr.vars[i];
601 const IntegerValue coeff = expr.coeffs[i];
602 if (coeff > 0) {
603 watcher->WatchLowerBound(var, id);
604 } else {
605 watcher->WatchUpperBound(var, id);
606 }
607 }
608 }
609 watcher->WatchUpperBound(min_var_, id);
610 watcher->RegisterReversibleInt(id, &rev_unique_candidate_);
611}
612
614 IntegerVariable a, IntegerVariable b, IntegerVariable p,
615 IntegerTrail* integer_trail)
616 : a_(a), b_(b), p_(p), integer_trail_(integer_trail) {
617 // Note that we assume this is true at level zero, and so we never include
618 // that fact in the reasons we compute.
619 CHECK_GE(integer_trail_->LevelZeroLowerBound(a_), 0);
620 CHECK_GE(integer_trail_->LevelZeroLowerBound(b_), 0);
621}
622
623// TODO(user): We can tighten the bounds on p by removing extreme value that
624// do not contains divisor in the domains of a or b. There is an algo in O(
625// smallest domain size between a or b).
627 const IntegerValue max_a = integer_trail_->UpperBound(a_);
628 const IntegerValue max_b = integer_trail_->UpperBound(b_);
629 const IntegerValue new_max(CapProd(max_a.value(), max_b.value()));
630 if (new_max < integer_trail_->UpperBound(p_)) {
631 if (!integer_trail_->Enqueue(IntegerLiteral::LowerOrEqual(p_, new_max), {},
632 {integer_trail_->UpperBoundAsLiteral(a_),
633 integer_trail_->UpperBoundAsLiteral(b_)})) {
634 return false;
635 }
636 }
637
638 const IntegerValue min_a = integer_trail_->LowerBound(a_);
639 const IntegerValue min_b = integer_trail_->LowerBound(b_);
640 const IntegerValue new_min(CapProd(min_a.value(), min_b.value()));
641 if (new_min > integer_trail_->LowerBound(p_)) {
642 if (!integer_trail_->Enqueue(IntegerLiteral::GreaterOrEqual(p_, new_min),
643 {},
644 {integer_trail_->LowerBoundAsLiteral(a_),
645 integer_trail_->LowerBoundAsLiteral(b_)})) {
646 return false;
647 }
648 }
649
650 for (int i = 0; i < 2; ++i) {
651 const IntegerVariable a = i == 0 ? a_ : b_;
652 const IntegerVariable b = i == 0 ? b_ : a_;
653 const IntegerValue max_a = integer_trail_->UpperBound(a);
654 const IntegerValue min_b = integer_trail_->LowerBound(b);
655 const IntegerValue min_p = integer_trail_->LowerBound(p_);
656 const IntegerValue max_p = integer_trail_->UpperBound(p_);
657 const IntegerValue prod(CapProd(max_a.value(), min_b.value()));
658 if (prod > max_p) {
659 if (!integer_trail_->Enqueue(
660 IntegerLiteral::LowerOrEqual(a, FloorRatio(max_p, min_b)), {},
661 {integer_trail_->LowerBoundAsLiteral(b),
662 integer_trail_->UpperBoundAsLiteral(p_)})) {
663 return false;
664 }
665 } else if (prod < min_p) {
666 if (!integer_trail_->Enqueue(
667 IntegerLiteral::GreaterOrEqual(b, CeilRatio(min_p, max_a)), {},
668 {integer_trail_->UpperBoundAsLiteral(a),
669 integer_trail_->LowerBoundAsLiteral(p_)})) {
670 return false;
671 }
672 }
673 }
674
675 return true;
676}
677
679 const int id = watcher->Register(this);
680 watcher->WatchIntegerVariable(a_, id);
681 watcher->WatchIntegerVariable(b_, id);
682 watcher->WatchIntegerVariable(p_, id);
684}
685
686namespace {
687
688// TODO(user): Find better implementation? In pratice passing via double is
689// almost always correct, but the CapProd() might be a bit slow. However this
690// is only called when we do propagate something.
691IntegerValue FloorSquareRoot(IntegerValue a) {
692 IntegerValue result(static_cast<int64_t>(
693 std::floor(std::sqrt(static_cast<double>(a.value())))));
694 while (CapProd(result.value(), result.value()) > a) --result;
695 while (CapProd(result.value() + 1, result.value() + 1) <= a) ++result;
696 return result;
697}
698
699// TODO(user): Find better implementation?
700IntegerValue CeilSquareRoot(IntegerValue a) {
701 IntegerValue result(static_cast<int64_t>(
702 std::ceil(std::sqrt(static_cast<double>(a.value())))));
703 while (CapProd(result.value(), result.value()) < a) ++result;
704 while ((result.value() - 1) * (result.value() - 1) >= a) --result;
705 return result;
706}
707
708} // namespace
709
710SquarePropagator::SquarePropagator(IntegerVariable x, IntegerVariable s,
711 IntegerTrail* integer_trail)
712 : x_(x), s_(s), integer_trail_(integer_trail) {
713 CHECK_GE(integer_trail->LevelZeroLowerBound(x), 0);
714}
715
716// Propagation from x to s: s in [min_x * min_x, max_x * max_x].
717// Propagation from s to x: x in [ceil(sqrt(min_s)), floor(sqrt(max_s))].
719 const IntegerValue min_x = integer_trail_->LowerBound(x_);
720 const IntegerValue min_s = integer_trail_->LowerBound(s_);
721 const IntegerValue min_x_square(CapProd(min_x.value(), min_x.value()));
722 if (min_x_square > min_s) {
723 if (!integer_trail_->Enqueue(
724 IntegerLiteral::GreaterOrEqual(s_, min_x_square), {},
725 {IntegerLiteral::GreaterOrEqual(x_, min_x)})) {
726 return false;
727 }
728 } else if (min_x_square < min_s) {
729 const IntegerValue new_min = CeilSquareRoot(min_s);
730 if (!integer_trail_->Enqueue(IntegerLiteral::GreaterOrEqual(x_, new_min),
731 {},
732 {IntegerLiteral::GreaterOrEqual(
733 s_, (new_min - 1) * (new_min - 1) + 1)})) {
734 return false;
735 }
736 }
737
738 const IntegerValue max_x = integer_trail_->UpperBound(x_);
739 const IntegerValue max_s = integer_trail_->UpperBound(s_);
740 const IntegerValue max_x_square(CapProd(max_x.value(), max_x.value()));
741 if (max_x_square < max_s) {
742 if (!integer_trail_->Enqueue(IntegerLiteral::LowerOrEqual(s_, max_x_square),
743 {},
744 {IntegerLiteral::LowerOrEqual(x_, max_x)})) {
745 return false;
746 }
747 } else if (max_x_square > max_s) {
748 const IntegerValue new_max = FloorSquareRoot(max_s);
749 if (!integer_trail_->Enqueue(
750 IntegerLiteral::LowerOrEqual(x_, new_max), {},
751 {IntegerLiteral::LowerOrEqual(
752 s_, IntegerValue(
753 CapProd(new_max.value() + 1, new_max.value() + 1)) -
754 1)})) {
755 return false;
756 }
757 }
758
759 return true;
760}
761
763 const int id = watcher->Register(this);
764 watcher->WatchIntegerVariable(x_, id);
765 watcher->WatchIntegerVariable(s_, id);
767}
768
770 IntegerVariable num, IntegerVariable denom, IntegerVariable div,
771 IntegerTrail* integer_trail)
772 : num_(num), denom_(denom), div_(div), integer_trail_(integer_trail) {
773 // TODO(user): support these cases.
774 CHECK_GE(integer_trail->LevelZeroLowerBound(num), 0);
775 // The denominator can never be zero.
776 CHECK_GT(integer_trail->LevelZeroLowerBound(denom), 0);
777}
778
780 const IntegerValue min_num = integer_trail_->LowerBound(num_);
781 const IntegerValue max_num = integer_trail_->UpperBound(num_);
782 const IntegerValue min_denom = integer_trail_->LowerBound(denom_);
783 const IntegerValue max_denom = integer_trail_->UpperBound(denom_);
784 const IntegerValue min_div = integer_trail_->LowerBound(div_);
785 const IntegerValue max_div = integer_trail_->UpperBound(div_);
786
787 const IntegerValue new_max_div = max_num / min_denom;
788 if (max_div > new_max_div) {
789 if (!integer_trail_->Enqueue(
790 IntegerLiteral::LowerOrEqual(div_, new_max_div), {},
791 {integer_trail_->UpperBoundAsLiteral(num_),
792 integer_trail_->LowerBoundAsLiteral(denom_)})) {
793 return false;
794 }
795 }
796
797 const IntegerValue new_min_div = min_num / max_denom;
798 if (min_div < new_min_div) {
799 if (!integer_trail_->Enqueue(
800 IntegerLiteral::GreaterOrEqual(div_, new_min_div), {},
801 {integer_trail_->LowerBoundAsLiteral(num_),
802 integer_trail_->UpperBoundAsLiteral(denom_)})) {
803 return false;
804 }
805 }
806
807 // We start from num / denom <= max_div.
808 // num < (max_div + 1) * denom
809 // num + 1 <= (max_div + 1) * max_denom.
810 const IntegerValue new_max_num = (max_div + 1) * max_denom - 1;
811 if (max_num > new_max_num) {
812 if (!integer_trail_->Enqueue(
813 IntegerLiteral::LowerOrEqual(num_, new_max_num), {},
814 {integer_trail_->UpperBoundAsLiteral(denom_),
815 integer_trail_->UpperBoundAsLiteral(div_)})) {
816 return false;
817 }
818 }
819
820 // We start from num / denom >= min_div.
821 // num >= min_div * denom.
822 // num >= min_div * min_denom.
823 const IntegerValue new_min_num = min_denom * min_div;
824 if (min_num < new_min_num) {
825 if (!integer_trail_->Enqueue(
826 IntegerLiteral::GreaterOrEqual(num_, new_min_num), {},
827 {integer_trail_->LowerBoundAsLiteral(denom_),
828 integer_trail_->LowerBoundAsLiteral(div_)})) {
829 return false;
830 }
831 }
832
833 // We start with num / denom >= min_div.
834 // So num >= min_div * denom
835 // If min_div == 0 we can't deduce anything.
836 // Otherwise, denom <= num / min_div and denom <= max_num / min_div.
837 if (min_div > 0) {
838 // const IntegerValue new_max_denom = (max_num - 1) / (min_div - 1);
839 const IntegerValue new_max_denom = max_num / min_div;
840 if (max_denom > new_max_denom) {
841 if (!integer_trail_->Enqueue(
842 IntegerLiteral::LowerOrEqual(denom_, new_max_denom), {},
843 {integer_trail_->UpperBoundAsLiteral(num_),
844 integer_trail_->LowerBoundAsLiteral(div_)})) {
845 return false;
846 }
847 }
848 }
849
850 // We start from num / denom <= max_div.
851 // num < (max_div + 1) * denom.
852 // num + 1 <= (max_div + 1) * denom.
853 // denom >= CeilRatio(num + 1, max_div+1) >= CeilRatio(min_num + 1, max_div +
854 // 1).
855 const IntegerValue new_min_denom = CeilRatio(min_num + 1, max_div + 1);
856 if (min_denom < new_min_denom) {
857 if (!integer_trail_->Enqueue(
858 IntegerLiteral::GreaterOrEqual(denom_, new_min_denom), {},
859 {integer_trail_->LowerBoundAsLiteral(num_),
860 integer_trail_->UpperBoundAsLiteral(div_)})) {
861 return false;
862 }
863 }
864
865 return true;
866}
867
869 const int id = watcher->Register(this);
870 watcher->WatchIntegerVariable(num_, id);
871 watcher->WatchIntegerVariable(denom_, id);
872 watcher->WatchIntegerVariable(div_, id);
874}
875
877 IntegerValue b,
878 IntegerVariable c,
879 IntegerTrail* integer_trail)
880 : a_(a), b_(b), c_(c), integer_trail_(integer_trail) {}
881
883 const IntegerValue min_a = integer_trail_->LowerBound(a_);
884 const IntegerValue max_a = integer_trail_->UpperBound(a_);
885 IntegerValue min_c = integer_trail_->LowerBound(c_);
886 IntegerValue max_c = integer_trail_->UpperBound(c_);
887
888 CHECK_GT(b_, 0);
889
890 if (max_a / b_ < max_c) {
891 max_c = max_a / b_;
892 if (!integer_trail_->Enqueue(IntegerLiteral::LowerOrEqual(c_, max_c), {},
893 {integer_trail_->UpperBoundAsLiteral(a_)})) {
894 return false;
895 }
896 } else if (max_a / b_ > max_c) {
897 const IntegerValue new_max_a =
898 max_c >= 0 ? max_c * b_ + b_ - 1
899 : IntegerValue(CapProd(max_c.value(), b_.value()));
900 CHECK_LT(new_max_a, max_a);
901 if (!integer_trail_->Enqueue(IntegerLiteral::LowerOrEqual(a_, new_max_a),
902 {},
903 {integer_trail_->UpperBoundAsLiteral(c_)})) {
904 return false;
905 }
906 }
907
908 if (min_a / b_ > min_c) {
909 min_c = min_a / b_;
910 if (!integer_trail_->Enqueue(IntegerLiteral::GreaterOrEqual(c_, min_c), {},
911 {integer_trail_->LowerBoundAsLiteral(a_)})) {
912 return false;
913 }
914 } else if (min_a / b_ < min_c) {
915 const IntegerValue new_min_a =
916 min_c > 0 ? IntegerValue(CapProd(min_c.value(), b_.value()))
917 : min_c * b_ - b_ + 1;
918 CHECK_GT(new_min_a, min_a);
919 if (!integer_trail_->Enqueue(IntegerLiteral::GreaterOrEqual(a_, new_min_a),
920 {},
921 {integer_trail_->LowerBoundAsLiteral(c_)})) {
922 return false;
923 }
924 }
925
926 return true;
927}
928
930 const int id = watcher->Register(this);
931 watcher->WatchIntegerVariable(a_, id);
932 watcher->WatchIntegerVariable(c_, id);
933}
934
935std::function<void(Model*)> IsOneOf(IntegerVariable var,
936 const std::vector<Literal>& selectors,
937 const std::vector<IntegerValue>& values) {
938 return [=](Model* model) {
939 IntegerTrail* integer_trail = model->GetOrCreate<IntegerTrail>();
940 IntegerEncoder* encoder = model->GetOrCreate<IntegerEncoder>();
941
942 CHECK(!values.empty());
943 CHECK_EQ(values.size(), selectors.size());
944 std::vector<int64_t> unique_values;
945 absl::flat_hash_map<int64_t, std::vector<Literal>> value_to_selector;
946 for (int i = 0; i < values.size(); ++i) {
947 unique_values.push_back(values[i].value());
948 value_to_selector[values[i].value()].push_back(selectors[i]);
949 }
950 gtl::STLSortAndRemoveDuplicates(&unique_values);
951
952 integer_trail->UpdateInitialDomain(var, Domain::FromValues(unique_values));
953 if (unique_values.size() == 1) {
954 model->Add(ClauseConstraint(selectors));
955 return;
956 }
957
958 // Note that it is more efficient to call AssociateToIntegerEqualValue()
959 // with the values ordered, like we do here.
960 for (const int64_t v : unique_values) {
961 const std::vector<Literal>& selectors = value_to_selector[v];
962 if (selectors.size() == 1) {
963 encoder->AssociateToIntegerEqualValue(selectors[0], var,
964 IntegerValue(v));
965 } else {
966 const Literal l(model->Add(NewBooleanVariable()), true);
967 model->Add(ReifiedBoolOr(selectors, l));
968 encoder->AssociateToIntegerEqualValue(l, var, IntegerValue(v));
969 }
970 }
971 };
972}
973
974} // namespace sat
975} // namespace operations_research
const std::vector< IntVar * > vars_
Definition: alldiff_cst.cc:44
int64_t min
Definition: alldiff_cst.cc:139
#define CHECK(condition)
Definition: base/logging.h:491
#define CHECK_LT(val1, val2)
Definition: base/logging.h:701
#define CHECK_EQ(val1, val2)
Definition: base/logging.h:698
#define CHECK_GE(val1, val2)
Definition: base/logging.h:702
#define CHECK_GT(val1, val2)
Definition: base/logging.h:703
#define DCHECK_GE(val1, val2)
Definition: base/logging.h:890
#define VLOG(verboselevel)
Definition: base/logging.h:979
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:105
void AdvanceDeterministicTime(double deterministic_duration)
Advances the deterministic time.
Definition: time_limit.h:226
FixedDivisionPropagator(IntegerVariable a, IntegerValue b, IntegerVariable c, IntegerTrail *integer_trail)
void RegisterWith(GenericLiteralWatcher *watcher)
void WatchLiteral(Literal l, int id, int watch_index=-1)
Definition: integer.h:1422
void WatchLowerBound(IntegerVariable var, int id, int watch_index=-1)
Definition: integer.h:1430
void WatchIntegerVariable(IntegerVariable i, int id, int watch_index=-1)
Definition: integer.h:1454
void WatchUpperBound(IntegerVariable var, int id, int watch_index=-1)
Definition: integer.h:1448
int Register(PropagatorInterface *propagator)
Definition: integer.cc:1996
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:1028
int FindTrailIndexOfVarBefore(IntegerVariable var, int threshold) const
Definition: integer.cc:754
bool IsFixed(IntegerVariable i) const
Definition: integer.h:1353
IntegerLiteral LowerBoundAsLiteral(IntegerVariable i) const
Definition: integer.h:1387
bool ReportConflict(absl::Span< const Literal > literal_reason, absl::Span< const IntegerLiteral > integer_reason)
Definition: integer.h:849
void EnqueueLiteral(Literal literal, absl::Span< const Literal > literal_reason, absl::Span< const IntegerLiteral > integer_reason)
Definition: integer.cc:1142
IntegerValue UpperBound(IntegerVariable i) const
Definition: integer.h:1349
bool VariableLowerBoundIsFromLevelZero(IntegerVariable var) const
Definition: integer.h:866
void AppendRelaxedLinearReason(IntegerValue slack, absl::Span< const IntegerValue > coeffs, absl::Span< const IntegerVariable > vars, std::vector< IntegerLiteral > *reason) const
Definition: integer.cc:846
IntegerValue LevelZeroLowerBound(IntegerVariable var) const
Definition: integer.h:1407
void RelaxLinearReason(IntegerValue slack, absl::Span< const IntegerValue > coeffs, std::vector< IntegerLiteral > *reason) const
Definition: integer.cc:824
IntegerValue LowerBound(IntegerVariable i) const
Definition: integer.h:1345
IntegerLiteral UpperBoundAsLiteral(IntegerVariable i) const
Definition: integer.h:1392
bool UpdateInitialDomain(IntegerVariable var, Domain domain)
Definition: integer.cc:686
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)
PositiveDivisionPropagator(IntegerVariable num, IntegerVariable denom, IntegerVariable div, IntegerTrail *integer_trail)
void RegisterWith(GenericLiteralWatcher *watcher)
PositiveProductPropagator(IntegerVariable a, IntegerVariable b, IntegerVariable p, IntegerTrail *integer_trail)
void RegisterWith(GenericLiteralWatcher *watcher)
SquarePropagator(IntegerVariable x, IntegerVariable s, IntegerTrail *integer_trail)
const VariablesAssignment & Assignment() const
Definition: sat_base.h:381
bool LiteralIsTrue(Literal literal) const
Definition: sat_base.h:151
bool LiteralIsFalse(Literal literal) const
Definition: sat_base.h:148
int64_t b
int64_t a
int64_t value
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:91
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:82
const LiteralIndex kNoLiteralIndex(-1)
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:1469
std::function< void(Model *)> LowerOrEqual(IntegerVariable v, int64_t ub)
Definition: integer.h:1567
IntegerVariable PositiveVariable(IntegerVariable i)
Definition: integer.h:142
IntegerValue PositiveRemainder(IntegerValue dividend, IntegerValue positive_divisor)
Definition: integer.h:106
std::function< int64_t(const Model &)> UpperBound(IntegerVariable v)
Definition: integer.h:1530
std::vector< IntegerVariable > NegationOf(const std::vector< IntegerVariable > &vars)
Definition: integer.cc:29
IntegerValue LinExprUpperBound(const LinearExpression &expr, const IntegerTrail &integer_trail)
Collection of objects used to extend the Constraint Solver library.
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
static IntegerLiteral LowerOrEqual(IntegerVariable i, IntegerValue bound)
Definition: integer.h:1315
static IntegerLiteral GreaterOrEqual(IntegerVariable i, IntegerValue bound)
Definition: integer.h:1309