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