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