OR-Tools  8.0
integer_expr.cc
Go to the documentation of this file.
1 // Copyright 2010-2018 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 <memory>
18 #include <vector>
19 
20 #include "absl/container/flat_hash_map.h"
21 #include "absl/memory/memory.h"
22 #include "ortools/base/stl_util.h"
23 #include "ortools/sat/integer.h"
26 
27 namespace operations_research {
28 namespace sat {
29 
30 IntegerSumLE::IntegerSumLE(const std::vector<Literal>& enforcement_literals,
31  const std::vector<IntegerVariable>& vars,
32  const std::vector<IntegerValue>& coeffs,
33  IntegerValue upper, Model* model)
34  : enforcement_literals_(enforcement_literals),
35  upper_bound_(upper),
36  trail_(model->GetOrCreate<Trail>()),
37  integer_trail_(model->GetOrCreate<IntegerTrail>()),
38  time_limit_(model->GetOrCreate<TimeLimit>()),
39  rev_integer_value_repository_(
40  model->GetOrCreate<RevIntegerValueRepository>()),
41  vars_(vars),
42  coeffs_(coeffs) {
43  // TODO(user): deal with this corner case.
44  CHECK(!vars_.empty());
45  max_variations_.resize(vars_.size());
46 
47  // Handle negative coefficients.
48  for (int i = 0; i < vars.size(); ++i) {
49  if (coeffs_[i] < 0) {
50  vars_[i] = NegationOf(vars_[i]);
51  coeffs_[i] = -coeffs_[i];
52  }
53  }
54 
55  // Literal reason will only be used with the negation of enforcement_literals.
56  for (const Literal literal : enforcement_literals) {
57  literal_reason_.push_back(literal.Negated());
58  }
59 
60  // Initialize the reversible numbers.
61  rev_num_fixed_vars_ = 0;
62  rev_lb_fixed_vars_ = IntegerValue(0);
63 }
64 
65 void IntegerSumLE::FillIntegerReason() {
66  integer_reason_.clear();
67  reason_coeffs_.clear();
68  const int num_vars = vars_.size();
69  for (int i = 0; i < num_vars; ++i) {
70  const IntegerVariable var = vars_[i];
71  if (!integer_trail_->VariableLowerBoundIsFromLevelZero(var)) {
72  integer_reason_.push_back(integer_trail_->LowerBoundAsLiteral(var));
73  reason_coeffs_.push_back(coeffs_[i]);
74  }
75  }
76 }
77 
79  // Reified case: If any of the enforcement_literals are false, we ignore the
80  // constraint.
81  int num_unassigned_enforcement_literal = 0;
82  LiteralIndex unique_unnasigned_literal = kNoLiteralIndex;
83  for (const Literal literal : enforcement_literals_) {
84  if (trail_->Assignment().LiteralIsFalse(literal)) return true;
85  if (!trail_->Assignment().LiteralIsTrue(literal)) {
86  ++num_unassigned_enforcement_literal;
87  unique_unnasigned_literal = literal.Index();
88  }
89  }
90 
91  // Unfortunately, we can't propagate anything if we have more than one
92  // unassigned enforcement literal.
93  if (num_unassigned_enforcement_literal > 1) return true;
94 
95  // Save the current sum of fixed variables.
96  if (is_registered_) {
97  rev_integer_value_repository_->SaveState(&rev_lb_fixed_vars_);
98  }
99 
100  // Compute the new lower bound and update the reversible structures.
101  IntegerValue lb_unfixed_vars = IntegerValue(0);
102  const int num_vars = vars_.size();
103  for (int i = rev_num_fixed_vars_; i < num_vars; ++i) {
104  const IntegerVariable var = vars_[i];
105  const IntegerValue coeff = coeffs_[i];
106  const IntegerValue lb = integer_trail_->LowerBound(var);
107  const IntegerValue ub = integer_trail_->UpperBound(var);
108  if (lb != ub) {
109  max_variations_[i] = (ub - lb) * coeff;
110  lb_unfixed_vars += lb * coeff;
111  } else {
112  // Update the set of fixed variables.
113  std::swap(vars_[i], vars_[rev_num_fixed_vars_]);
114  std::swap(coeffs_[i], coeffs_[rev_num_fixed_vars_]);
115  std::swap(max_variations_[i], max_variations_[rev_num_fixed_vars_]);
116  rev_num_fixed_vars_++;
117  rev_lb_fixed_vars_ += lb * coeff;
118  }
119  }
120  time_limit_->AdvanceDeterministicTime(
121  static_cast<double>(num_vars - rev_num_fixed_vars_) * 1e-9);
122 
123  // Conflict?
124  const IntegerValue slack =
125  upper_bound_ - (rev_lb_fixed_vars_ + lb_unfixed_vars);
126  if (slack < 0) {
127  FillIntegerReason();
128  integer_trail_->RelaxLinearReason(-slack - 1, reason_coeffs_,
129  &integer_reason_);
130 
131  if (num_unassigned_enforcement_literal == 1) {
132  // Propagate the only non-true literal to false.
133  const Literal to_propagate = Literal(unique_unnasigned_literal).Negated();
134  std::vector<Literal> tmp = literal_reason_;
135  tmp.erase(std::find(tmp.begin(), tmp.end(), to_propagate));
136  integer_trail_->EnqueueLiteral(to_propagate, tmp, integer_reason_);
137  return true;
138  }
139  return integer_trail_->ReportConflict(literal_reason_, integer_reason_);
140  }
141 
142  // We can only propagate more if all the enforcement literals are true.
143  if (num_unassigned_enforcement_literal > 0) return true;
144 
145  // The lower bound of all the variables except one can be used to update the
146  // upper bound of the last one.
147  for (int i = rev_num_fixed_vars_; i < num_vars; ++i) {
148  if (max_variations_[i] <= slack) continue;
149 
150  const IntegerVariable var = vars_[i];
151  const IntegerValue coeff = coeffs_[i];
152  const IntegerValue div = slack / coeff;
153  const IntegerValue new_ub = integer_trail_->LowerBound(var) + div;
154  const IntegerValue propagation_slack = (div + 1) * coeff - slack - 1;
155  if (!integer_trail_->Enqueue(
157  /*lazy_reason=*/[this, propagation_slack](
158  IntegerLiteral i_lit, int trail_index,
159  std::vector<Literal>* literal_reason,
160  std::vector<int>* trail_indices_reason) {
161  *literal_reason = literal_reason_;
162  trail_indices_reason->clear();
163  reason_coeffs_.clear();
164  const int size = vars_.size();
165  for (int i = 0; i < size; ++i) {
166  const IntegerVariable var = vars_[i];
167  if (PositiveVariable(var) == PositiveVariable(i_lit.var)) {
168  continue;
169  }
170  const int index =
171  integer_trail_->FindTrailIndexOfVarBefore(var, trail_index);
172  if (index >= 0) {
173  trail_indices_reason->push_back(index);
174  if (propagation_slack > 0) {
175  reason_coeffs_.push_back(coeffs_[i]);
176  }
177  }
178  }
179  if (propagation_slack > 0) {
180  integer_trail_->RelaxLinearReason(
181  propagation_slack, reason_coeffs_, trail_indices_reason);
182  }
183  })) {
184  return false;
185  }
186  }
187 
188  return true;
189 }
190 
191 void IntegerSumLE::RegisterWith(GenericLiteralWatcher* watcher) {
192  is_registered_ = true;
193  const int id = watcher->Register(this);
194  for (const IntegerVariable& var : vars_) {
195  watcher->WatchLowerBound(var, id);
196  }
197  for (const Literal literal : enforcement_literals_) {
198  // We only watch the true direction.
199  //
200  // TODO(user): if there is more than one, maybe we should watch more to
201  // propagate a "conflict" as soon as only one is unassigned?
202  watcher->WatchLiteral(Literal(literal), id);
203  }
204  watcher->RegisterReversibleInt(id, &rev_num_fixed_vars_);
205 }
206 
207 MinPropagator::MinPropagator(const std::vector<IntegerVariable>& vars,
208  IntegerVariable min_var,
209  IntegerTrail* integer_trail)
210  : vars_(vars), min_var_(min_var), integer_trail_(integer_trail) {}
211 
213  if (vars_.empty()) return true;
214 
215  // Count the number of interval that are possible candidate for the min.
216  // Only the intervals for which lb > current_min_ub cannot.
217  const IntegerLiteral min_ub_literal =
218  integer_trail_->UpperBoundAsLiteral(min_var_);
219  const IntegerValue current_min_ub = integer_trail_->UpperBound(min_var_);
220  int num_intervals_that_can_be_min = 0;
221  int last_possible_min_interval = 0;
222 
223  IntegerValue min = kMaxIntegerValue;
224  for (int i = 0; i < vars_.size(); ++i) {
225  const IntegerValue lb = integer_trail_->LowerBound(vars_[i]);
226  min = std::min(min, lb);
227  if (lb <= current_min_ub) {
228  ++num_intervals_that_can_be_min;
229  last_possible_min_interval = i;
230  }
231  }
232 
233  // Propagation a)
234  if (min > integer_trail_->LowerBound(min_var_)) {
235  integer_reason_.clear();
236  for (const IntegerVariable var : vars_) {
237  integer_reason_.push_back(IntegerLiteral::GreaterOrEqual(var, min));
238  }
239  if (!integer_trail_->Enqueue(IntegerLiteral::GreaterOrEqual(min_var_, min),
240  {}, integer_reason_)) {
241  return false;
242  }
243  }
244 
245  // Propagation b)
246  if (num_intervals_that_can_be_min == 1) {
247  const IntegerValue ub_of_only_candidate =
248  integer_trail_->UpperBound(vars_[last_possible_min_interval]);
249  if (current_min_ub < ub_of_only_candidate) {
250  integer_reason_.clear();
251 
252  // The reason is that all the other interval start after current_min_ub.
253  // And that min_ub has its current value.
254  integer_reason_.push_back(min_ub_literal);
255  for (const IntegerVariable var : vars_) {
256  if (var == vars_[last_possible_min_interval]) continue;
257  integer_reason_.push_back(
258  IntegerLiteral::GreaterOrEqual(var, current_min_ub + 1));
259  }
260  if (!integer_trail_->Enqueue(
261  IntegerLiteral::LowerOrEqual(vars_[last_possible_min_interval],
262  current_min_ub),
263  {}, integer_reason_)) {
264  return false;
265  }
266  }
267  }
268 
269  // Conflict.
270  //
271  // TODO(user): Not sure this code is useful since this will be detected
272  // by the fact that the [lb, ub] of the min is empty. It depends on the
273  // propagation order though, but probably the precedences propagator would
274  // propagate before this one. So change this to a CHECK?
275  if (num_intervals_that_can_be_min == 0) {
276  integer_reason_.clear();
277 
278  // Almost the same as propagation b).
279  integer_reason_.push_back(min_ub_literal);
280  for (const IntegerVariable var : vars_) {
281  integer_reason_.push_back(
282  IntegerLiteral::GreaterOrEqual(var, current_min_ub + 1));
283  }
284  return integer_trail_->ReportConflict(integer_reason_);
285  }
286 
287  return true;
288 }
289 
291  const int id = watcher->Register(this);
292  for (const IntegerVariable& var : vars_) {
293  watcher->WatchLowerBound(var, id);
294  }
295  watcher->WatchUpperBound(min_var_, id);
296 }
297 
298 LinMinPropagator::LinMinPropagator(const std::vector<LinearExpression>& exprs,
299  IntegerVariable min_var, Model* model)
300  : exprs_(exprs),
301  min_var_(min_var),
302  model_(model),
303  integer_trail_(model_->GetOrCreate<IntegerTrail>()) {}
304 
305 bool LinMinPropagator::PropagateLinearUpperBound(
306  const std::vector<IntegerVariable>& vars,
307  const std::vector<IntegerValue>& coeffs, const IntegerValue upper_bound) {
308  IntegerValue sum_lb = IntegerValue(0);
309  const int num_vars = vars.size();
310  std::vector<IntegerValue> max_variations;
311  for (int i = 0; i < num_vars; ++i) {
312  const IntegerVariable var = vars[i];
313  const IntegerValue coeff = coeffs[i];
314  // The coefficients are assumed to be positive for this to work properly.
315  DCHECK_GE(coeff, 0);
316  const IntegerValue lb = integer_trail_->LowerBound(var);
317  const IntegerValue ub = integer_trail_->UpperBound(var);
318  max_variations.push_back((ub - lb) * coeff);
319  sum_lb += lb * coeff;
320  }
321 
322  model_->GetOrCreate<TimeLimit>()->AdvanceDeterministicTime(
323  static_cast<double>(num_vars) * 1e-9);
324 
325  const IntegerValue slack = upper_bound - sum_lb;
326 
327  std::vector<IntegerLiteral> linear_sum_reason;
328  std::vector<IntegerValue> reason_coeffs;
329  for (int i = 0; i < num_vars; ++i) {
330  const IntegerVariable var = vars[i];
331  if (!integer_trail_->VariableLowerBoundIsFromLevelZero(var)) {
332  linear_sum_reason.push_back(integer_trail_->LowerBoundAsLiteral(var));
333  reason_coeffs.push_back(coeffs[i]);
334  }
335  }
336  if (slack < 0) {
337  // Conflict.
338  integer_trail_->RelaxLinearReason(-slack - 1, reason_coeffs,
339  &linear_sum_reason);
340  std::vector<IntegerLiteral> local_reason =
341  integer_reason_for_unique_candidate_;
342  local_reason.insert(local_reason.end(), linear_sum_reason.begin(),
343  linear_sum_reason.end());
344  return integer_trail_->ReportConflict({}, local_reason);
345  }
346 
347  // The lower bound of all the variables except one can be used to update the
348  // upper bound of the last one.
349  for (int i = 0; i < num_vars; ++i) {
350  if (max_variations[i] <= slack) continue;
351 
352  const IntegerVariable var = vars[i];
353  const IntegerValue coeff = coeffs[i];
354  const IntegerValue div = slack / coeff;
355  const IntegerValue new_ub = integer_trail_->LowerBound(var) + div;
356 
357  const IntegerValue propagation_slack = (div + 1) * coeff - slack - 1;
358  if (!integer_trail_->Enqueue(
360  /*lazy_reason=*/[this, &vars, &coeffs, propagation_slack](
361  IntegerLiteral i_lit, int trail_index,
362  std::vector<Literal>* literal_reason,
363  std::vector<int>* trail_indices_reason) {
364  literal_reason->clear();
365  trail_indices_reason->clear();
366  std::vector<IntegerValue> reason_coeffs;
367  const int size = vars.size();
368  for (int i = 0; i < size; ++i) {
369  const IntegerVariable var = vars[i];
370  if (PositiveVariable(var) == PositiveVariable(i_lit.var)) {
371  continue;
372  }
373  const int index =
374  integer_trail_->FindTrailIndexOfVarBefore(var, trail_index);
375  if (index >= 0) {
376  trail_indices_reason->push_back(index);
377  if (propagation_slack > 0) {
378  reason_coeffs.push_back(coeffs[i]);
379  }
380  }
381  }
382  if (propagation_slack > 0) {
383  integer_trail_->RelaxLinearReason(
384  propagation_slack, reason_coeffs, trail_indices_reason);
385  }
386  // Now add the old integer_reason that triggered this propatation.
387  for (IntegerLiteral reason_lit :
388  integer_reason_for_unique_candidate_) {
389  const int index = integer_trail_->FindTrailIndexOfVarBefore(
390  reason_lit.var, trail_index);
391  if (index >= 0) {
392  trail_indices_reason->push_back(index);
393  }
394  }
395  })) {
396  return false;
397  }
398  }
399  return true;
400 }
401 
403  if (exprs_.empty()) return true;
404 
405  expr_lbs_.clear();
406 
407  // Count the number of interval that are possible candidate for the min.
408  // Only the intervals for which lb > current_min_ub cannot.
409  const IntegerLiteral min_ub_literal =
410  integer_trail_->UpperBoundAsLiteral(min_var_);
411  const IntegerValue current_min_ub = integer_trail_->UpperBound(min_var_);
412  int num_intervals_that_can_be_min = 0;
413  int last_possible_min_interval = 0;
414 
415  IntegerValue min_of_linear_expression_lb = kMaxIntegerValue;
416  for (int i = 0; i < exprs_.size(); ++i) {
417  const IntegerValue lb = LinExprLowerBound(exprs_[i], *integer_trail_);
418  expr_lbs_.push_back(lb);
419  min_of_linear_expression_lb = std::min(min_of_linear_expression_lb, lb);
420  if (lb <= current_min_ub) {
421  ++num_intervals_that_can_be_min;
422  last_possible_min_interval = i;
423  }
424  }
425 
426  // Propagation a) lb(min) >= lb(MIN(exprs)) = MIN(lb(exprs));
427 
428  // Conflict will be detected by the fact that the [lb, ub] of the min is
429  // empty. In case of conflict, we just need the reason for pushing UB + 1.
430  if (min_of_linear_expression_lb > current_min_ub) {
431  min_of_linear_expression_lb = current_min_ub + 1;
432  }
433 
434  // Early experiments seems to show that the code if faster without relaxing
435  // the linear reason. But that might change in the future.
436  const bool use_slack = false;
437  if (min_of_linear_expression_lb > integer_trail_->LowerBound(min_var_)) {
438  std::vector<IntegerLiteral> local_reason;
439  for (int i = 0; i < exprs_.size(); ++i) {
440  const IntegerValue slack = expr_lbs_[i] - min_of_linear_expression_lb;
441  integer_trail_->AppendRelaxedLinearReason(
442  (use_slack ? slack : IntegerValue(0)), exprs_[i].coeffs,
443  exprs_[i].vars, &local_reason);
444  }
445  if (!integer_trail_->Enqueue(IntegerLiteral::GreaterOrEqual(
446  min_var_, min_of_linear_expression_lb),
447  {}, local_reason)) {
448  return false;
449  }
450  }
451 
452  // Propagation b) ub(min) >= ub(MIN(exprs)) and we can't propagate anything
453  // here unless there is just one possible expression 'e' that can be the min:
454  // for all u != e, lb(u) > ub(min);
455  // In this case, ub(min) >= ub(e).
456  if (num_intervals_that_can_be_min == 1) {
457  const IntegerValue ub_of_only_candidate =
458  LinExprUpperBound(exprs_[last_possible_min_interval], *integer_trail_);
459  if (current_min_ub < ub_of_only_candidate) {
460  // For this propagation, we only need to fill the integer reason once at
461  // the lowest level. At higher levels this reason still remains valid.
462  if (rev_unique_candidate_ == 0) {
463  integer_reason_for_unique_candidate_.clear();
464 
465  // The reason is that all the other interval start after current_min_ub.
466  // And that min_ub has its current value.
467  integer_reason_for_unique_candidate_.push_back(min_ub_literal);
468  for (int i = 0; i < exprs_.size(); ++i) {
469  if (i == last_possible_min_interval) continue;
470  const IntegerValue slack = expr_lbs_[i] - (current_min_ub + 1);
471  integer_trail_->AppendRelaxedLinearReason(
472  (use_slack ? slack : IntegerValue(0)), exprs_[i].coeffs,
473  exprs_[i].vars, &integer_reason_for_unique_candidate_);
474  }
475  rev_unique_candidate_ = 1;
476  }
477 
478  return PropagateLinearUpperBound(
479  exprs_[last_possible_min_interval].vars,
480  exprs_[last_possible_min_interval].coeffs,
481  current_min_ub - exprs_[last_possible_min_interval].offset);
482  }
483  }
484 
485  return true;
486 }
487 
489  const int id = watcher->Register(this);
490  for (const LinearExpression& expr : exprs_) {
491  for (int i = 0; i < expr.vars.size(); ++i) {
492  const IntegerVariable& var = expr.vars[i];
493  const IntegerValue coeff = expr.coeffs[i];
494  if (coeff > 0) {
495  watcher->WatchLowerBound(var, id);
496  } else {
497  watcher->WatchUpperBound(var, id);
498  }
499  }
500  }
501  watcher->WatchUpperBound(min_var_, id);
502  watcher->RegisterReversibleInt(id, &rev_unique_candidate_);
503 }
504 
506  IntegerVariable a, IntegerVariable b, IntegerVariable p,
507  IntegerTrail* integer_trail)
508  : a_(a), b_(b), p_(p), integer_trail_(integer_trail) {
509  // Note that we assume this is true at level zero, and so we never include
510  // that fact in the reasons we compute.
511  CHECK_GE(integer_trail_->LevelZeroLowerBound(a_), 0);
512  CHECK_GE(integer_trail_->LevelZeroLowerBound(b_), 0);
513 }
514 
515 // TODO(user): We can tighten the bounds on p by removing extreme value that
516 // do not contains divisor in the domains of a or b. There is an algo in O(
517 // smallest domain size between a or b).
519  const IntegerValue max_a = integer_trail_->UpperBound(a_);
520  const IntegerValue max_b = integer_trail_->UpperBound(b_);
521  const IntegerValue new_max(CapProd(max_a.value(), max_b.value()));
522  if (new_max < integer_trail_->UpperBound(p_)) {
523  if (!integer_trail_->Enqueue(IntegerLiteral::LowerOrEqual(p_, new_max), {},
524  {integer_trail_->UpperBoundAsLiteral(a_),
525  integer_trail_->UpperBoundAsLiteral(b_)})) {
526  return false;
527  }
528  }
529 
530  const IntegerValue min_a = integer_trail_->LowerBound(a_);
531  const IntegerValue min_b = integer_trail_->LowerBound(b_);
532  const IntegerValue new_min(CapProd(min_a.value(), min_b.value()));
533  if (new_min > integer_trail_->LowerBound(p_)) {
534  if (!integer_trail_->Enqueue(IntegerLiteral::GreaterOrEqual(p_, new_min),
535  {},
536  {integer_trail_->LowerBoundAsLiteral(a_),
537  integer_trail_->LowerBoundAsLiteral(b_)})) {
538  return false;
539  }
540  }
541 
542  for (int i = 0; i < 2; ++i) {
543  const IntegerVariable a = i == 0 ? a_ : b_;
544  const IntegerVariable b = i == 0 ? b_ : a_;
545  const IntegerValue max_a = integer_trail_->UpperBound(a);
546  const IntegerValue min_b = integer_trail_->LowerBound(b);
547  const IntegerValue min_p = integer_trail_->LowerBound(p_);
548  const IntegerValue max_p = integer_trail_->UpperBound(p_);
549  const IntegerValue prod(CapProd(max_a.value(), min_b.value()));
550  if (prod > max_p) {
551  if (!integer_trail_->Enqueue(
552  IntegerLiteral::LowerOrEqual(a, FloorRatio(max_p, min_b)), {},
553  {integer_trail_->LowerBoundAsLiteral(b),
554  integer_trail_->UpperBoundAsLiteral(p_)})) {
555  return false;
556  }
557  } else if (prod < min_p) {
558  if (!integer_trail_->Enqueue(
559  IntegerLiteral::GreaterOrEqual(b, CeilRatio(min_p, max_a)), {},
560  {integer_trail_->UpperBoundAsLiteral(a),
561  integer_trail_->LowerBoundAsLiteral(p_)})) {
562  return false;
563  }
564  }
565  }
566 
567  return true;
568 }
569 
571  const int id = watcher->Register(this);
572  watcher->WatchIntegerVariable(a_, id);
573  watcher->WatchIntegerVariable(b_, id);
574  watcher->WatchIntegerVariable(p_, id);
576 }
577 
578 namespace {
579 
580 // TODO(user): Find better implementation?
581 IntegerValue FloorSquareRoot(IntegerValue a) {
582  IntegerValue result(static_cast<int64>(std::floor(std::sqrt(ToDouble(a)))));
583  while (result * result > a) --result;
584  while ((result + 1) * (result + 1) <= a) ++result;
585  return result;
586 }
587 
588 // TODO(user): Find better implementation?
589 IntegerValue CeilSquareRoot(IntegerValue a) {
590  IntegerValue result(static_cast<int64>(std::ceil(std::sqrt(ToDouble(a)))));
591  while (result * result < a) ++result;
592  while ((result - 1) * (result - 1) >= a) --result;
593  return result;
594 }
595 
596 } // namespace
597 
598 SquarePropagator::SquarePropagator(IntegerVariable x, IntegerVariable s,
599  IntegerTrail* integer_trail)
600  : x_(x), s_(s), integer_trail_(integer_trail) {
601  CHECK_GE(integer_trail->LevelZeroLowerBound(x), 0);
602 }
603 
604 // Propagation from x to s: s in [min_x * min_x, max_x * max_x].
605 // Propagation from s to x: x in [ceil(sqrt(min_s)), floor(sqrt(max_s))].
607  const IntegerValue min_x = integer_trail_->LowerBound(x_);
608  const IntegerValue min_s = integer_trail_->LowerBound(s_);
609  const IntegerValue min_x_square(CapProd(min_x.value(), min_x.value()));
610  if (min_x_square > min_s) {
611  if (!integer_trail_->Enqueue(
612  IntegerLiteral::GreaterOrEqual(s_, min_x_square), {},
613  {IntegerLiteral::GreaterOrEqual(x_, min_x)})) {
614  return false;
615  }
616  } else if (min_x_square < min_s) {
617  const IntegerValue new_min = CeilSquareRoot(min_s);
618  if (!integer_trail_->Enqueue(IntegerLiteral::GreaterOrEqual(x_, new_min),
619  {},
620  {IntegerLiteral::GreaterOrEqual(
621  s_, (new_min - 1) * (new_min - 1) + 1)})) {
622  return false;
623  }
624  }
625 
626  const IntegerValue max_x = integer_trail_->UpperBound(x_);
627  const IntegerValue max_s = integer_trail_->UpperBound(s_);
628  const IntegerValue max_x_square(CapProd(max_x.value(), max_x.value()));
629  if (max_x_square < max_s) {
630  if (!integer_trail_->Enqueue(IntegerLiteral::LowerOrEqual(s_, max_x_square),
631  {},
632  {IntegerLiteral::LowerOrEqual(x_, max_x)})) {
633  return false;
634  }
635  } else if (max_x_square > max_s) {
636  const IntegerValue new_max = FloorSquareRoot(max_s);
637  if (!integer_trail_->Enqueue(IntegerLiteral::LowerOrEqual(x_, new_max), {},
638  {IntegerLiteral::LowerOrEqual(
639  s_, (new_max + 1) * (new_max + 1) - 1)})) {
640  return false;
641  }
642  }
643 
644  return true;
645 }
646 
648  const int id = watcher->Register(this);
649  watcher->WatchIntegerVariable(x_, id);
650  watcher->WatchIntegerVariable(s_, id);
652 }
653 
654 DivisionPropagator::DivisionPropagator(IntegerVariable a, IntegerVariable b,
655  IntegerVariable c,
656  IntegerTrail* integer_trail)
657  : a_(a), b_(b), c_(c), integer_trail_(integer_trail) {
658  // TODO(user): support these cases.
659  CHECK_GE(integer_trail->LevelZeroLowerBound(a), 0);
660  CHECK_GT(integer_trail->LevelZeroLowerBound(b), 0); // b can never be zero.
661 }
662 
664  const IntegerValue min_a = integer_trail_->LowerBound(a_);
665  const IntegerValue max_a = integer_trail_->UpperBound(a_);
666  const IntegerValue min_b = integer_trail_->LowerBound(b_);
667  const IntegerValue max_b = integer_trail_->UpperBound(b_);
668  IntegerValue min_c = integer_trail_->LowerBound(c_);
669  IntegerValue max_c = integer_trail_->UpperBound(c_);
670 
671  if (max_a / min_b < max_c) {
672  max_c = max_a / min_b;
673  if (!integer_trail_->Enqueue(IntegerLiteral::LowerOrEqual(c_, max_c), {},
674  {integer_trail_->UpperBoundAsLiteral(a_),
675  integer_trail_->LowerBoundAsLiteral(b_)})) {
676  return false;
677  }
678  }
679  if (min_a / max_b > min_c) {
680  min_c = min_a / max_b;
681  if (!integer_trail_->Enqueue(IntegerLiteral::GreaterOrEqual(c_, min_c), {},
682  {integer_trail_->LowerBoundAsLiteral(a_),
683  integer_trail_->UpperBoundAsLiteral(b_)})) {
684  return false;
685  }
686  }
687 
688  // TODO(user): propagate the bounds on a and b from the ones of c.
689  // Note however that what we did is enough to enforce the constraint when
690  // all the values are fixed.
691  return true;
692 }
693 
695  const int id = watcher->Register(this);
696  watcher->WatchIntegerVariable(a_, id);
697  watcher->WatchIntegerVariable(b_, id);
698  watcher->WatchIntegerVariable(c_, id);
700 }
701 
703  IntegerValue b,
704  IntegerVariable c,
705  IntegerTrail* integer_trail)
706  : a_(a), b_(b), c_(c), integer_trail_(integer_trail) {}
707 
709  const IntegerValue min_a = integer_trail_->LowerBound(a_);
710  const IntegerValue max_a = integer_trail_->UpperBound(a_);
711  IntegerValue min_c = integer_trail_->LowerBound(c_);
712  IntegerValue max_c = integer_trail_->UpperBound(c_);
713 
714  CHECK_GT(b_, 0);
715 
716  if (max_a / b_ < max_c) {
717  max_c = max_a / b_;
718  if (!integer_trail_->Enqueue(IntegerLiteral::LowerOrEqual(c_, max_c), {},
719  {integer_trail_->UpperBoundAsLiteral(a_)})) {
720  return false;
721  }
722  } else if (max_a / b_ > max_c) {
723  const IntegerValue new_max_a =
724  max_c >= 0 ? max_c * b_ + b_ - 1
725  : IntegerValue(CapProd(max_c.value(), b_.value()));
726  CHECK_LT(new_max_a, max_a);
727  if (!integer_trail_->Enqueue(IntegerLiteral::LowerOrEqual(a_, new_max_a),
728  {},
729  {integer_trail_->UpperBoundAsLiteral(c_)})) {
730  return false;
731  }
732  }
733 
734  if (min_a / b_ > min_c) {
735  min_c = min_a / b_;
736  if (!integer_trail_->Enqueue(IntegerLiteral::GreaterOrEqual(c_, min_c), {},
737  {integer_trail_->LowerBoundAsLiteral(a_)})) {
738  return false;
739  }
740  } else if (min_a / b_ < min_c) {
741  const IntegerValue new_min_a =
742  min_c > 0 ? IntegerValue(CapProd(min_c.value(), b_.value()))
743  : min_c * b_ - b_ + 1;
744  CHECK_GT(new_min_a, min_a);
745  if (!integer_trail_->Enqueue(IntegerLiteral::GreaterOrEqual(a_, new_min_a),
746  {},
747  {integer_trail_->LowerBoundAsLiteral(c_)})) {
748  return false;
749  }
750  }
751 
752  return true;
753 }
754 
756  const int id = watcher->Register(this);
757  watcher->WatchIntegerVariable(a_, id);
758  watcher->WatchIntegerVariable(c_, id);
759 }
760 
761 std::function<void(Model*)> IsOneOf(IntegerVariable var,
762  const std::vector<Literal>& selectors,
763  const std::vector<IntegerValue>& values) {
764  return [=](Model* model) {
765  IntegerTrail* integer_trail = model->GetOrCreate<IntegerTrail>();
766  IntegerEncoder* encoder = model->GetOrCreate<IntegerEncoder>();
767 
768  CHECK(!values.empty());
769  CHECK_EQ(values.size(), selectors.size());
770  std::vector<int64> unique_values;
771  absl::flat_hash_map<int64, std::vector<Literal>> value_to_selector;
772  for (int i = 0; i < values.size(); ++i) {
773  unique_values.push_back(values[i].value());
774  value_to_selector[values[i].value()].push_back(selectors[i]);
775  }
776  gtl::STLSortAndRemoveDuplicates(&unique_values);
777 
778  integer_trail->UpdateInitialDomain(var, Domain::FromValues(unique_values));
779  if (unique_values.size() == 1) {
780  model->Add(ClauseConstraint(selectors));
781  return;
782  }
783 
784  // Note that it is more efficient to call AssociateToIntegerEqualValue()
785  // with the values ordered, like we do here.
786  for (const int64 v : unique_values) {
787  const std::vector<Literal>& selectors = value_to_selector[v];
788  if (selectors.size() == 1) {
789  encoder->AssociateToIntegerEqualValue(selectors[0], var,
790  IntegerValue(v));
791  } else {
792  const Literal l(model->Add(NewBooleanVariable()), true);
793  model->Add(ReifiedBoolOr(selectors, l));
794  encoder->AssociateToIntegerEqualValue(l, var, IntegerValue(v));
795  }
796  }
797  };
798 }
799 
800 } // namespace sat
801 } // namespace operations_research
var
IntVar * var
Definition: expr_array.cc:1858
operations_research::sat::GenericLiteralWatcher::Register
int Register(PropagatorInterface *propagator)
Definition: integer.cc:1897
if
if(!yyg->yy_init)
Definition: parser.yy.cc:965
min
int64 min
Definition: alldiff_cst.cc:138
operations_research::sat::IntegerTrail
Definition: integer.h:523
operations_research::sat::FixedDivisionPropagator::RegisterWith
void RegisterWith(GenericLiteralWatcher *watcher)
Definition: integer_expr.cc:755
operations_research::sat::FloorRatio
IntegerValue FloorRatio(IntegerValue dividend, IntegerValue positive_divisor)
Definition: integer.h:90
time_limit.h
operations_research::sat::GenericLiteralWatcher::WatchLowerBound
void WatchLowerBound(IntegerVariable var, int id, int watch_index=-1)
Definition: integer.h:1301
operations_research::CapProd
int64 CapProd(int64 x, int64 y)
Definition: saturated_arithmetic.h:231
operations_research::sat::kNoLiteralIndex
const LiteralIndex kNoLiteralIndex(-1)
operations_research::sat::CeilRatio
IntegerValue CeilRatio(IntegerValue dividend, IntegerValue positive_divisor)
Definition: integer.h:81
operations_research::sat::ReifiedBoolOr
std::function< void(Model *)> ReifiedBoolOr(const std::vector< Literal > &literals, Literal r)
Definition: sat_solver.h:923
operations_research::sat::IntegerTrail::LevelZeroLowerBound
IntegerValue LevelZeroLowerBound(IntegerVariable var) const
Definition: integer.h:1278
operations_research::sat::PositiveProductPropagator::Propagate
bool Propagate() final
Definition: integer_expr.cc:518
operations_research::sat::IntegerTrail::VariableLowerBoundIsFromLevelZero
bool VariableLowerBoundIsFromLevelZero(IntegerVariable var) const
Definition: integer.h:800
operations_research::sat::GenericLiteralWatcher::RegisterReversibleInt
void RegisterReversibleInt(int id, int *rev)
Definition: integer.cc:1941
value
int64 value
Definition: demon_profiler.cc:43
operations_research::Domain::FromValues
static Domain FromValues(std::vector< int64 > values)
Creates a domain from the union of an unsorted list of integer values.
Definition: sorted_interval_list.cc:137
operations_research::sat::SquarePropagator::Propagate
bool Propagate() final
Definition: integer_expr.cc:606
operations_research::sat::LinExprUpperBound
IntegerValue LinExprUpperBound(const LinearExpression &expr, const IntegerTrail &integer_trail)
Definition: linear_constraint.cc:301
operations_research
The vehicle routing library lets one model and solve generic vehicle routing problems ranging from th...
Definition: dense_doubly_linked_list.h:21
operations_research::sat::IntegerTrail::EnqueueLiteral
void EnqueueLiteral(Literal literal, absl::Span< const Literal > literal_reason, absl::Span< const IntegerLiteral > integer_reason)
Definition: integer.cc:1057
operations_research::sat::NegationOf
std::vector< IntegerVariable > NegationOf(const std::vector< IntegerVariable > &vars)
Definition: integer.cc:42
operations_research::sat::FixedDivisionPropagator::FixedDivisionPropagator
FixedDivisionPropagator(IntegerVariable a, IntegerValue b, IntegerVariable c, IntegerTrail *integer_trail)
Definition: integer_expr.cc:702
operations_research::sat::VariablesAssignment::LiteralIsTrue
bool LiteralIsTrue(Literal literal) const
Definition: sat_base.h:150
operations_research::sat::IntegerLiteral::GreaterOrEqual
static IntegerLiteral GreaterOrEqual(IntegerVariable i, IntegerValue bound)
Definition: integer.h:1208
operations_research::sat::DivisionPropagator::DivisionPropagator
DivisionPropagator(IntegerVariable a, IntegerVariable b, IntegerVariable c, IntegerTrail *integer_trail)
Definition: integer_expr.cc:654
operations_research::sat::PositiveVariable
IntegerVariable PositiveVariable(IntegerVariable i)
Definition: integer.h:134
int64
int64_t int64
Definition: integral_types.h:34
operations_research::sat::Literal::Negated
Literal Negated() const
Definition: sat_base.h:91
operations_research::TimeLimit
A simple class to enforce both an elapsed time limit and a deterministic time limit in the same threa...
Definition: time_limit.h:105
index
int index
Definition: pack.cc:508
operations_research::sat::IntegerTrail::UpdateInitialDomain
bool UpdateInitialDomain(IntegerVariable var, Domain domain)
Definition: integer.cc:647
operations_research::sat::GenericLiteralWatcher
Definition: integer.h:1067
a
int64 a
Definition: constraint_solver/table.cc:42
operations_research::sat::IntegerTrail::UpperBoundAsLiteral
IntegerLiteral UpperBoundAsLiteral(IntegerVariable i) const
Definition: integer.h:1263
operations_research::sat::IntegerTrail::AppendRelaxedLinearReason
void AppendRelaxedLinearReason(IntegerValue slack, absl::Span< const IntegerValue > coeffs, absl::Span< const IntegerVariable > vars, std::vector< IntegerLiteral > *reason) const
Definition: integer.cc:806
operations_research::sat::NewBooleanVariable
std::function< BooleanVariable(Model *)> NewBooleanVariable()
Definition: integer.h:1331
operations_research::sat::IntegerTrail::UpperBound
IntegerValue UpperBound(IntegerVariable i) const
Definition: integer.h:1232
operations_research::sat::IntegerTrail::Enqueue
ABSL_MUST_USE_RESULT bool Enqueue(IntegerLiteral i_lit, absl::Span< const Literal > literal_reason, absl::Span< const IntegerLiteral > integer_reason)
Definition: integer.cc:988
operations_research::sat::DivisionPropagator::Propagate
bool Propagate() final
Definition: integer_expr.cc:663
operations_research::sat::MinPropagator::RegisterWith
void RegisterWith(GenericLiteralWatcher *watcher)
Definition: integer_expr.cc:290
operations_research::sat::PositiveProductPropagator::RegisterWith
void RegisterWith(GenericLiteralWatcher *watcher)
Definition: integer_expr.cc:570
operations_research::sat::GenericLiteralWatcher::NotifyThatPropagatorMayNotReachFixedPointInOnePass
void NotifyThatPropagatorMayNotReachFixedPointInOnePass(int id)
Definition: integer.cc:1927
gtl::STLSortAndRemoveDuplicates
void STLSortAndRemoveDuplicates(T *v, const LessFunc &less_func)
Definition: stl_util.h:58
operations_research::sat::IsOneOf
std::function< void(Model *)> IsOneOf(IntegerVariable var, const std::vector< Literal > &selectors, const std::vector< IntegerValue > &values)
Definition: integer_expr.cc:761
operations_research::sat::kMaxIntegerValue
constexpr IntegerValue kMaxIntegerValue(std::numeric_limits< IntegerValue::ValueType >::max() - 1)
integer_expr.h
operations_research::sat::Trail::Assignment
const VariablesAssignment & Assignment() const
Definition: sat_base.h:380
operations_research::sat::LinMinPropagator::RegisterWith
void RegisterWith(GenericLiteralWatcher *watcher)
Definition: integer_expr.cc:488
operations_research::sat::DivisionPropagator::RegisterWith
void RegisterWith(GenericLiteralWatcher *watcher)
Definition: integer_expr.cc:694
operations_research::sat::LinearExpression
Definition: linear_constraint.h:172
operations_research::sat::Model
Class that owns everything related to a particular optimization model.
Definition: sat/model.h:38
operations_research::sat::IntegerTrail::LowerBoundAsLiteral
IntegerLiteral LowerBoundAsLiteral(IntegerVariable i) const
Definition: integer.h:1258
operations_research::sat::IntegerLiteral
Definition: integer.h:153
operations_research::sat::LinMinPropagator::Propagate
bool Propagate() final
Definition: integer_expr.cc:402
operations_research::sat::GenericLiteralWatcher::WatchIntegerVariable
void WatchIntegerVariable(IntegerVariable i, int id, int watch_index=-1)
Definition: integer.h:1316
operations_research::sat::LinExprLowerBound
IntegerValue LinExprLowerBound(const LinearExpression &expr, const IntegerTrail &integer_trail)
Definition: linear_constraint.cc:291
operations_research::sat::IntegerLiteral::LowerOrEqual
static IntegerLiteral LowerOrEqual(IntegerVariable i, IntegerValue bound)
Definition: integer.h:1214
operations_research::sat::FixedDivisionPropagator::Propagate
bool Propagate() final
Definition: integer_expr.cc:708
sorted_interval_list.h
operations_research::sat::Model::GetOrCreate
T * GetOrCreate()
Returns an object of type T that is unique to this model (like a "local" singleton).
Definition: sat/model.h:106
operations_research::sat::ClauseConstraint
std::function< void(Model *)> ClauseConstraint(absl::Span< const Literal > literals)
Definition: sat_solver.h:893
model
GRBmodel * model
Definition: gurobi_interface.cc:195
operations_research::TimeLimit::AdvanceDeterministicTime
void AdvanceDeterministicTime(double deterministic_duration)
Advances the deterministic time.
Definition: time_limit.h:226
operations_research::sat::Literal
Definition: sat_base.h:64
operations_research::sat::RevIntegerValueRepository
Definition: integer.h:1056
operations_research::sat::ToDouble
double ToDouble(IntegerValue value)
Definition: integer.h:69
operations_research::sat::PositiveProductPropagator::PositiveProductPropagator
PositiveProductPropagator(IntegerVariable a, IntegerVariable b, IntegerVariable p, IntegerTrail *integer_trail)
Definition: integer_expr.cc:505
operations_research::sat::MinPropagator::Propagate
bool Propagate() final
Definition: integer_expr.cc:212
operations_research::sat::GenericLiteralWatcher::WatchLiteral
void WatchLiteral(Literal l, int id, int watch_index=-1)
Definition: integer.h:1293
operations_research::sat::IntegerTrail::ReportConflict
bool ReportConflict(absl::Span< const Literal > literal_reason, absl::Span< const IntegerLiteral > integer_reason)
Definition: integer.h:783
stl_util.h
vars_
const std::vector< IntVar * > vars_
Definition: alldiff_cst.cc:43
operations_research::sat::IntegerSumLE::IntegerSumLE
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:30
operations_research::sat::IntegerTrail::RelaxLinearReason
void RelaxLinearReason(IntegerValue slack, absl::Span< const IntegerValue > coeffs, std::vector< IntegerLiteral > *reason) const
Definition: integer.cc:784
operations_research::sat::UpperBound
std::function< int64(const Model &)> UpperBound(IntegerVariable v)
Definition: integer.h:1392
operations_research::sat::SquarePropagator::SquarePropagator
SquarePropagator(IntegerVariable x, IntegerVariable s, IntegerTrail *integer_trail)
Definition: integer_expr.cc:598
operations_research::sat::IntegerTrail::FindTrailIndexOfVarBefore
int FindTrailIndexOfVarBefore(IntegerVariable var, int threshold) const
Definition: integer.cc:715
b
int64 b
Definition: constraint_solver/table.cc:43
operations_research::sat::IntegerSumLE::Propagate
bool Propagate() final
Definition: integer_expr.cc:78
operations_research::sat::IntegerTrail::LowerBound
IntegerValue LowerBound(IntegerVariable i) const
Definition: integer.h:1228
operations_research::sat::SquarePropagator::RegisterWith
void RegisterWith(GenericLiteralWatcher *watcher)
Definition: integer_expr.cc:647
operations_research::sat::LinMinPropagator::LinMinPropagator
LinMinPropagator(const std::vector< LinearExpression > &exprs, IntegerVariable min_var, Model *model)
Definition: integer_expr.cc:298
literal
Literal literal
Definition: optimization.cc:84
operations_research::RevRepository::SaveState
void SaveState(T *object)
Definition: rev.h:61
operations_research::sat::IntegerEncoder
Definition: integer.h:267
integer.h
operations_research::sat::VariablesAssignment::LiteralIsFalse
bool LiteralIsFalse(Literal literal) const
Definition: sat_base.h:147
operations_research::sat::GenericLiteralWatcher::WatchUpperBound
void WatchUpperBound(IntegerVariable var, int id, int watch_index=-1)
Definition: integer.h:1310
operations_research::sat::Trail
Definition: sat_base.h:233