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