OR-Tools  9.1
all_different.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 <limits>
19 #include <map>
20 #include <memory>
21 
22 #include "absl/container/flat_hash_set.h"
23 #include "ortools/base/int_type.h"
24 #include "ortools/base/logging.h"
25 #include "ortools/base/map_util.h"
27 #include "ortools/sat/sat_solver.h"
28 #include "ortools/util/sort.h"
29 
30 namespace operations_research {
31 namespace sat {
32 
33 std::function<void(Model*)> AllDifferentBinary(
34  const std::vector<IntegerVariable>& vars) {
35  return [=](Model* model) {
36  // Fully encode all the given variables and construct a mapping value ->
37  // List of literal each indicating that a given variable takes this value.
38  //
39  // Note that we use a map to always add the constraints in the same order.
40  std::map<IntegerValue, std::vector<Literal>> value_to_literals;
41  IntegerEncoder* encoder = model->GetOrCreate<IntegerEncoder>();
42  for (const IntegerVariable var : vars) {
44  for (const auto& entry : encoder->FullDomainEncoding(var)) {
45  value_to_literals[entry.value].push_back(entry.literal);
46  }
47  }
48 
49  // Add an at most one constraint for each value.
50  for (const auto& entry : value_to_literals) {
51  if (entry.second.size() > 1) {
52  model->Add(AtMostOneConstraint(entry.second));
53  }
54  }
55 
56  // If the number of values is equal to the number of variables, we have
57  // a permutation. We can add a bool_or for each literals attached to a
58  // value.
59  if (value_to_literals.size() == vars.size()) {
60  for (const auto& entry : value_to_literals) {
61  model->Add(ClauseConstraint(entry.second));
62  }
63  }
64  };
65 }
66 
67 std::function<void(Model*)> AllDifferentOnBounds(
68  const std::vector<IntegerVariable>& vars) {
69  return [=](Model* model) {
70  if (vars.empty()) return;
71  auto* constraint = new AllDifferentBoundsPropagator(
72  vars, model->GetOrCreate<IntegerTrail>());
73  constraint->RegisterWith(model->GetOrCreate<GenericLiteralWatcher>());
74  model->TakeOwnership(constraint);
75  };
76 }
77 
78 std::function<void(Model*)> AllDifferentAC(
79  const std::vector<IntegerVariable>& variables) {
80  return [=](Model* model) {
81  if (variables.size() < 3) return;
82 
84  variables, model->GetOrCreate<IntegerEncoder>(),
85  model->GetOrCreate<Trail>(), model->GetOrCreate<IntegerTrail>());
86  constraint->RegisterWith(model->GetOrCreate<GenericLiteralWatcher>());
87  model->TakeOwnership(constraint);
88  };
89 }
90 
92  std::vector<IntegerVariable> variables, IntegerEncoder* encoder,
93  Trail* trail, IntegerTrail* integer_trail)
94  : num_variables_(variables.size()),
95  variables_(std::move(variables)),
96  trail_(trail),
97  integer_trail_(integer_trail) {
98  // Initialize literals cache.
99  int64_t min_value = std::numeric_limits<int64_t>::max();
100  int64_t max_value = std::numeric_limits<int64_t>::min();
101  variable_min_value_.resize(num_variables_);
102  variable_max_value_.resize(num_variables_);
103  variable_literal_index_.resize(num_variables_);
104  int num_fixed_variables = 0;
105  for (int x = 0; x < num_variables_; x++) {
106  variable_min_value_[x] = integer_trail_->LowerBound(variables_[x]).value();
107  variable_max_value_[x] = integer_trail_->UpperBound(variables_[x]).value();
108 
109  // Compute value range of all variables.
110  min_value = std::min(min_value, variable_min_value_[x]);
111  max_value = std::max(max_value, variable_max_value_[x]);
112 
113  // FullyEncode does not like 1-value domains, handle this case first.
114  // TODO(user): Prune now, ignore these variables during solving.
115  if (variable_min_value_[x] == variable_max_value_[x]) {
116  num_fixed_variables++;
117  variable_literal_index_[x].push_back(kTrueLiteralIndex);
118  continue;
119  }
120 
121  // Force full encoding if not already done.
122  if (!encoder->VariableIsFullyEncoded(variables_[x])) {
123  encoder->FullyEncodeVariable(variables_[x]);
124  }
125 
126  // Fill cache with literals, default value is kFalseLiteralIndex.
127  int64_t size = variable_max_value_[x] - variable_min_value_[x] + 1;
128  variable_literal_index_[x].resize(size, kFalseLiteralIndex);
129  for (const auto& entry : encoder->FullDomainEncoding(variables_[x])) {
130  int64_t value = entry.value.value();
131  // Can happen because of initial propagation!
132  if (value < variable_min_value_[x] || variable_max_value_[x] < value) {
133  continue;
134  }
135  variable_literal_index_[x][value - variable_min_value_[x]] =
136  entry.literal.Index();
137  }
138  }
139  min_all_values_ = min_value;
140  num_all_values_ = max_value - min_value + 1;
141 
142  successor_.resize(num_variables_);
143  variable_to_value_.assign(num_variables_, -1);
144  visiting_.resize(num_variables_);
145  variable_visited_from_.resize(num_variables_);
146  residual_graph_successors_.resize(num_variables_ + num_all_values_ + 1);
147  component_number_.resize(num_variables_ + num_all_values_ + 1);
148 }
149 
151  const int id = watcher->Register(this);
152  watcher->SetPropagatorPriority(id, 2);
153  for (const auto& literal_indices : variable_literal_index_) {
154  for (const LiteralIndex li : literal_indices) {
155  // Watch only unbound literals.
156  if (li >= 0 &&
157  !trail_->Assignment().VariableIsAssigned(Literal(li).Variable())) {
158  watcher->WatchLiteral(Literal(li), id);
159  watcher->WatchLiteral(Literal(li).Negated(), id);
160  }
161  }
162  }
163 }
164 
165 LiteralIndex AllDifferentConstraint::VariableLiteralIndexOf(int x,
166  int64_t value) {
167  return (value < variable_min_value_[x] || variable_max_value_[x] < value)
169  : variable_literal_index_[x][value - variable_min_value_[x]];
170 }
171 
172 inline bool AllDifferentConstraint::VariableHasPossibleValue(int x,
173  int64_t value) {
174  LiteralIndex li = VariableLiteralIndexOf(x, value);
175  if (li == kFalseLiteralIndex) return false;
176  if (li == kTrueLiteralIndex) return true;
177  DCHECK_GE(li, 0);
178  return !trail_->Assignment().LiteralIsFalse(Literal(li));
179 }
180 
181 bool AllDifferentConstraint::MakeAugmentingPath(int start) {
182  // Do a BFS and use visiting_ as a queue, with num_visited pointing
183  // at its begin() and num_to_visit its end().
184  // To switch to the augmenting path once a nonmatched value was found,
185  // we remember the BFS tree in variable_visited_from_.
186  int num_to_visit = 0;
187  int num_visited = 0;
188  // Enqueue start.
189  visiting_[num_to_visit++] = start;
190  variable_visited_[start] = true;
191  variable_visited_from_[start] = -1;
192 
193  while (num_visited < num_to_visit) {
194  // Dequeue node to visit.
195  const int node = visiting_[num_visited++];
196 
197  for (const int value : successor_[node]) {
198  if (value_visited_[value]) continue;
199  value_visited_[value] = true;
200  if (value_to_variable_[value] == -1) {
201  // value is not matched: change path from node to start, and return.
202  int path_node = node;
203  int path_value = value;
204  while (path_node != -1) {
205  int old_value = variable_to_value_[path_node];
206  variable_to_value_[path_node] = path_value;
207  value_to_variable_[path_value] = path_node;
208  path_node = variable_visited_from_[path_node];
209  path_value = old_value;
210  }
211  return true;
212  } else {
213  // Enqueue node matched to value.
214  const int next_node = value_to_variable_[value];
215  variable_visited_[next_node] = true;
216  visiting_[num_to_visit++] = next_node;
217  variable_visited_from_[next_node] = node;
218  }
219  }
220  }
221  return false;
222 }
223 
224 // The algorithm copies the solver state to successor_, which is used to compute
225 // a matching. If all variables can be matched, it generates the residual graph
226 // in separate vectors, computes its SCCs, and filters variable -> value if
227 // variable is not in the same SCC as value.
228 // Explanations for failure and filtering are fine-grained:
229 // failure is explained by a Hall set, i.e. dom(variables) \subseteq {values},
230 // with |variables| < |values|; filtering is explained by the Hall set that
231 // would happen if the variable was assigned to the value.
232 //
233 // TODO(user): If needed, there are several ways performance could be
234 // improved.
235 // If copying the variable state is too costly, it could be maintained instead.
236 // If the propagator has too many fruitless calls (without failing/pruning),
237 // we can remember the O(n) arcs used in the matching and the SCC decomposition,
238 // and guard calls to Propagate() if these arcs are still valid.
240  // Copy variable state to graph state.
241  prev_matching_ = variable_to_value_;
242  value_to_variable_.assign(num_all_values_, -1);
243  variable_to_value_.assign(num_variables_, -1);
244  for (int x = 0; x < num_variables_; x++) {
245  successor_[x].clear();
246  const int64_t min_value = integer_trail_->LowerBound(variables_[x]).value();
247  const int64_t max_value = integer_trail_->UpperBound(variables_[x]).value();
248  for (int64_t value = min_value; value <= max_value; value++) {
249  if (VariableHasPossibleValue(x, value)) {
250  const int offset_value = value - min_all_values_;
251  // Forward-checking should propagate x != value.
252  successor_[x].push_back(offset_value);
253  }
254  }
255  if (successor_[x].size() == 1) {
256  const int offset_value = successor_[x][0];
257  if (value_to_variable_[offset_value] == -1) {
258  value_to_variable_[offset_value] = x;
259  variable_to_value_[x] = offset_value;
260  }
261  }
262  }
263 
264  // Because we currently propagates all clauses before entering this
265  // propagator, we known that this can't happen.
266  if (DEBUG_MODE) {
267  for (int x = 0; x < num_variables_; x++) {
268  for (const int offset_value : successor_[x]) {
269  if (value_to_variable_[offset_value] != -1 &&
270  value_to_variable_[offset_value] != x) {
271  LOG(FATAL) << "Should have been propagated by AllDifferentBinary()!";
272  }
273  }
274  }
275  }
276 
277  // Seed with previous matching.
278  for (int x = 0; x < num_variables_; x++) {
279  if (variable_to_value_[x] != -1) continue;
280  const int prev_value = prev_matching_[x];
281  if (prev_value == -1 || value_to_variable_[prev_value] != -1) continue;
282 
283  if (VariableHasPossibleValue(x, prev_matching_[x] + min_all_values_)) {
284  variable_to_value_[x] = prev_matching_[x];
285  value_to_variable_[prev_matching_[x]] = x;
286  }
287  }
288 
289  // Compute max matching.
290  int x = 0;
291  for (; x < num_variables_; x++) {
292  if (variable_to_value_[x] == -1) {
293  value_visited_.assign(num_all_values_, false);
294  variable_visited_.assign(num_variables_, false);
295  MakeAugmentingPath(x);
296  }
297  if (variable_to_value_[x] == -1) break; // No augmenting path exists.
298  }
299 
300  // Fail if covering variables impossible.
301  // Explain with the forbidden parts of the graph that prevent
302  // MakeAugmentingPath from increasing the matching size.
303  if (x < num_variables_) {
304  // For now explain all forbidden arcs.
305  std::vector<Literal>* conflict = trail_->MutableConflict();
306  conflict->clear();
307  for (int y = 0; y < num_variables_; y++) {
308  if (!variable_visited_[y]) continue;
309  for (int value = variable_min_value_[y]; value <= variable_max_value_[y];
310  value++) {
311  const LiteralIndex li = VariableLiteralIndexOf(y, value);
312  if (li >= 0 && !value_visited_[value - min_all_values_]) {
313  DCHECK(trail_->Assignment().LiteralIsFalse(Literal(li)));
314  conflict->push_back(Literal(li));
315  }
316  }
317  }
318  return false;
319  }
320 
321  // The current matching is a valid solution, now try to filter values.
322  // Build residual graph, compute its SCCs.
323  for (int x = 0; x < num_variables_; x++) {
324  residual_graph_successors_[x].clear();
325  for (const int succ : successor_[x]) {
326  if (succ != variable_to_value_[x]) {
327  residual_graph_successors_[x].push_back(num_variables_ + succ);
328  }
329  }
330  }
331  for (int offset_value = 0; offset_value < num_all_values_; offset_value++) {
332  residual_graph_successors_[num_variables_ + offset_value].clear();
333  if (value_to_variable_[offset_value] != -1) {
334  residual_graph_successors_[num_variables_ + offset_value].push_back(
335  value_to_variable_[offset_value]);
336  }
337  }
338  const int dummy_node = num_variables_ + num_all_values_;
339  residual_graph_successors_[dummy_node].clear();
340  if (num_variables_ < num_all_values_) {
341  for (int x = 0; x < num_variables_; x++) {
342  residual_graph_successors_[dummy_node].push_back(x);
343  }
344  for (int offset_value = 0; offset_value < num_all_values_; offset_value++) {
345  if (value_to_variable_[offset_value] == -1) {
346  residual_graph_successors_[num_variables_ + offset_value].push_back(
347  dummy_node);
348  }
349  }
350  }
351 
352  // Compute SCCs, make node -> component map.
353  struct SccOutput {
354  explicit SccOutput(std::vector<int>* c) : components(c) {}
355  void emplace_back(int const* b, int const* e) {
356  for (int const* it = b; it < e; ++it) {
357  (*components)[*it] = num_components;
358  }
359  ++num_components;
360  }
361  int num_components = 0;
362  std::vector<int>* components;
363  };
364  SccOutput scc_output(&component_number_);
366  static_cast<int>(residual_graph_successors_.size()),
367  residual_graph_successors_, &scc_output);
368 
369  // Remove arcs var -> val where SCC(var) -/->* SCC(val).
370  for (int x = 0; x < num_variables_; x++) {
371  if (successor_[x].size() == 1) continue;
372  for (const int offset_value : successor_[x]) {
373  const int value_node = offset_value + num_variables_;
374  if (variable_to_value_[x] != offset_value &&
375  component_number_[x] != component_number_[value_node] &&
376  VariableHasPossibleValue(x, offset_value + min_all_values_)) {
377  // We can deduce that x != value. To explain, force x == offset_value,
378  // then find another assignment for the variable matched to
379  // offset_value. It will fail: explaining why is the same as
380  // explaining failure as above, and it is an explanation of x != value.
381  value_visited_.assign(num_all_values_, false);
382  variable_visited_.assign(num_variables_, false);
383  // Undo x -> old_value and old_variable -> offset_value.
384  const int old_variable = value_to_variable_[offset_value];
385  variable_to_value_[old_variable] = -1;
386  const int old_value = variable_to_value_[x];
387  value_to_variable_[old_value] = -1;
388  variable_to_value_[x] = offset_value;
389  value_to_variable_[offset_value] = x;
390 
391  value_visited_[offset_value] = true;
392  MakeAugmentingPath(old_variable);
393  DCHECK_EQ(variable_to_value_[old_variable], -1); // No reassignment.
394 
395  std::vector<Literal>* reason = trail_->GetEmptyVectorToStoreReason();
396  for (int y = 0; y < num_variables_; y++) {
397  if (!variable_visited_[y]) continue;
398  for (int value = variable_min_value_[y];
399  value <= variable_max_value_[y]; value++) {
400  const LiteralIndex li = VariableLiteralIndexOf(y, value);
401  if (li >= 0 && !value_visited_[value - min_all_values_]) {
402  DCHECK(!VariableHasPossibleValue(y, value));
403  reason->push_back(Literal(li));
404  }
405  }
406  }
407 
408  const LiteralIndex li =
409  VariableLiteralIndexOf(x, offset_value + min_all_values_);
412  return trail_->EnqueueWithStoredReason(Literal(li).Negated());
413  }
414  }
415  }
416 
417  return true;
418 }
419 
421  const std::vector<IntegerVariable>& vars, IntegerTrail* integer_trail)
422  : integer_trail_(integer_trail) {
423  CHECK(!vars.empty());
424 
425  // We need +2 for sentinels.
426  const int capacity = vars.size() + 2;
427  index_to_start_index_.resize(capacity);
428  index_to_end_index_.resize(capacity);
429  index_to_var_.resize(capacity, kNoIntegerVariable);
430 
431  for (int i = 0; i < vars.size(); ++i) {
432  vars_.push_back({vars[i]});
433  negated_vars_.push_back({NegationOf(vars[i])});
434  }
435 }
436 
438  if (!PropagateLowerBounds()) return false;
439 
440  // Note that it is not required to swap back vars_ and negated_vars_.
441  // TODO(user): investigate the impact.
442  std::swap(vars_, negated_vars_);
443  const bool result = PropagateLowerBounds();
444  std::swap(vars_, negated_vars_);
445  return result;
446 }
447 
448 void AllDifferentBoundsPropagator::FillHallReason(IntegerValue hall_lb,
449  IntegerValue hall_ub) {
450  integer_reason_.clear();
451  const int limit = GetIndex(hall_ub);
452  for (int i = GetIndex(hall_lb); i <= limit; ++i) {
453  const IntegerVariable var = index_to_var_[i];
454  integer_reason_.push_back(IntegerLiteral::GreaterOrEqual(var, hall_lb));
455  integer_reason_.push_back(IntegerLiteral::LowerOrEqual(var, hall_ub));
456  }
457 }
458 
459 int AllDifferentBoundsPropagator::FindStartIndexAndCompressPath(int index) {
460  // First, walk the pointer until we find one pointing to itself.
461  int start_index = index;
462  while (true) {
463  const int next = index_to_start_index_[start_index];
464  if (start_index == next) break;
465  start_index = next;
466  }
467 
468  // Second, redo the same thing and make everyone point to the representative.
469  while (true) {
470  const int next = index_to_start_index_[index];
471  if (start_index == next) break;
472  index_to_start_index_[index] = start_index;
473  index = next;
474  }
475  return start_index;
476 }
477 
478 bool AllDifferentBoundsPropagator::PropagateLowerBounds() {
479  // Start by filling the cached bounds and sorting by increasing lb.
480  for (VarValue& entry : vars_) {
481  entry.lb = integer_trail_->LowerBound(entry.var);
482  entry.ub = integer_trail_->UpperBound(entry.var);
483  }
484  IncrementalSort(vars_.begin(), vars_.end(),
485  [](VarValue a, VarValue b) { return a.lb < b.lb; });
486 
487  // We will split the variable in vars sorted by lb in contiguous subset with
488  // index of the form [start, start + num_in_window).
489  int start = 0;
490  int num_in_window = 1;
491 
492  // Minimum lower bound in the current window.
493  IntegerValue min_lb = vars_.front().lb;
494 
495  const int size = vars_.size();
496  for (int i = 1; i < size; ++i) {
497  const IntegerValue lb = vars_[i].lb;
498 
499  // If the lower bounds of all the other variables is greater, then it can
500  // never fall into a potential hall interval formed by the variable in the
501  // current window, so we can split the problem into independent parts.
502  if (lb <= min_lb + IntegerValue(num_in_window - 1)) {
503  ++num_in_window;
504  continue;
505  }
506 
507  // Process the current window.
508  if (num_in_window > 1) {
509  absl::Span<VarValue> window(&vars_[start], num_in_window);
510  if (!PropagateLowerBoundsInternal(min_lb, window)) {
511  return false;
512  }
513  }
514 
515  // Start of the next window.
516  start = i;
517  num_in_window = 1;
518  min_lb = lb;
519  }
520 
521  // Take care of the last window.
522  if (num_in_window > 1) {
523  absl::Span<VarValue> window(&vars_[start], num_in_window);
524  return PropagateLowerBoundsInternal(min_lb, window);
525  }
526 
527  return true;
528 }
529 
530 bool AllDifferentBoundsPropagator::PropagateLowerBoundsInternal(
531  IntegerValue min_lb, absl::Span<VarValue> vars) {
532  hall_starts_.clear();
533  hall_ends_.clear();
534 
535  // All cached lb in vars will be in [min_lb, min_lb + vars_.size()).
536  // Make sure we change our base_ so that GetIndex() fit in our buffers.
537  base_ = min_lb - IntegerValue(1);
538 
539  // Sparse cleaning of value_to_nodes_.
540  for (const int i : indices_to_clear_) {
541  index_to_var_[i] = kNoIntegerVariable;
542  }
543  indices_to_clear_.clear();
544 
545  // Sort vars by increasing ub.
546  std::sort(vars.begin(), vars.end(),
547  [](VarValue a, VarValue b) { return a.ub < b.ub; });
548  for (const VarValue entry : vars) {
549  const IntegerVariable var = entry.var;
550 
551  // Note that it is important to use the cache to make sure GetIndex() is
552  // not out of bound in case integer_trail_->LowerBound() changed when we
553  // pushed something.
554  const IntegerValue lb = entry.lb;
555  const int lb_index = GetIndex(lb);
556  const bool value_is_covered = PointIsPresent(lb_index);
557 
558  // Check if lb is in an Hall interval, and push it if this is the case.
559  if (value_is_covered) {
560  const int hall_index =
561  std::lower_bound(hall_ends_.begin(), hall_ends_.end(), lb) -
562  hall_ends_.begin();
563  if (hall_index < hall_ends_.size() && hall_starts_[hall_index] <= lb) {
564  const IntegerValue hs = hall_starts_[hall_index];
565  const IntegerValue he = hall_ends_[hall_index];
566  FillHallReason(hs, he);
567  integer_reason_.push_back(IntegerLiteral::GreaterOrEqual(var, hs));
568  if (!integer_trail_->Enqueue(
570  /*literal_reason=*/{}, integer_reason_)) {
571  return false;
572  }
573  }
574  }
575 
576  // Update our internal representation of the non-consecutive intervals.
577  //
578  // If lb is not used, we add a node there, otherwise we add it to the
579  // right of the interval that contains lb. In both cases, if there is an
580  // interval to the left (resp. right) we merge them.
581  int new_index = lb_index;
582  int start_index = lb_index;
583  int end_index = lb_index;
584  if (value_is_covered) {
585  start_index = FindStartIndexAndCompressPath(new_index);
586  new_index = index_to_end_index_[start_index] + 1;
587  end_index = new_index;
588  } else {
589  if (PointIsPresent(new_index - 1)) {
590  start_index = FindStartIndexAndCompressPath(new_index - 1);
591  }
592  }
593  if (PointIsPresent(new_index + 1)) {
594  end_index = index_to_end_index_[new_index + 1];
595  index_to_start_index_[new_index + 1] = start_index;
596  }
597 
598  // Update the end of the representative.
599  index_to_end_index_[start_index] = end_index;
600 
601  // This is the only place where we "add" a new node.
602  {
603  index_to_start_index_[new_index] = start_index;
604  index_to_var_[new_index] = var;
605  indices_to_clear_.push_back(new_index);
606  }
607 
608  // We cannot have a conflict, because it should have beend detected before
609  // by pushing an interval lower bound past its upper bound.
610  //
611  // TODO(user): Not 100% clear since pushing can have side-effect, maybe we
612  // should just report the conflict if it happens!
613  const IntegerValue end = GetValue(end_index);
614  DCHECK_LE(end, integer_trail_->UpperBound(var));
615 
616  // If we have a new Hall interval, add it to the set. Note that it will
617  // always be last, and if it overlaps some previous Hall intervals, it
618  // always overlaps them fully.
619  //
620  // Note: It is okay to not use entry.ub here if we want to fetch the last
621  // value, but in practice it shouldn't really change when we push a
622  // lower_bound and it is faster to use the cached entry.
623  if (end == entry.ub) {
624  const IntegerValue start = GetValue(start_index);
625  while (!hall_starts_.empty() && start <= hall_starts_.back()) {
626  hall_starts_.pop_back();
627  hall_ends_.pop_back();
628  }
629  DCHECK(hall_ends_.empty() || hall_ends_.back() < start);
630  hall_starts_.push_back(start);
631  hall_ends_.push_back(end);
632  }
633  }
634  return true;
635 }
636 
638  GenericLiteralWatcher* watcher) {
639  const int id = watcher->Register(this);
640  for (const VarValue entry : vars_) {
641  watcher->WatchIntegerVariable(entry.var, id);
642  }
644 }
645 
646 } // namespace sat
647 } // namespace operations_research
#define CHECK(condition)
Definition: base/logging.h:491
std::function< void(Model *)> AllDifferentBinary(const std::vector< IntegerVariable > &vars)
Definition: all_different.h:35
void IncrementalSort(int max_comparisons, Iterator begin, Iterator end, Compare comp=Compare{}, bool is_stable=false)
Definition: sort.h:46
const bool DEBUG_MODE
Definition: macros.h:24
int64_t min
Definition: alldiff_cst.cc:139
void RegisterWith(GenericLiteralWatcher *watcher)
const int FATAL
Definition: log_severity.h:32
Class that owns everything related to a particular optimization model.
Definition: sat/model.h:38
bool VariableIsFullyEncoded(IntegerVariable var) const
Definition: integer.cc:97
static IntegerLiteral LowerOrEqual(IntegerVariable i, IntegerValue bound)
Definition: integer.h:1315
std::vector< Literal > * MutableConflict()
Definition: sat_base.h:362
AllDifferentBoundsPropagator(const std::vector< IntegerVariable > &vars, IntegerTrail *integer_trail)
IntegerValue LowerBound(IntegerVariable i) const
Definition: integer.h:1345
bool LiteralIsFalse(Literal literal) const
Definition: sat_base.h:148
void swap(IdMap< K, V > &a, IdMap< K, V > &b)
Definition: id_map.h:263
#define LOG(severity)
Definition: base/logging.h:416
GRBmodel * model
const LiteralIndex kTrueLiteralIndex(-2)
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:1028
std::vector< Literal > * GetEmptyVectorToStoreReason(int trail_index) const
Definition: sat_base.h:321
int64_t max
Definition: alldiff_cst.cc:140
Block * next
void FullyEncodeVariable(IntegerVariable var)
Definition: integer.cc:67
std::function< void(Model *)> AtMostOneConstraint(const std::vector< Literal > &literals)
Definition: sat_solver.h:892
#define DCHECK_NE(val1, val2)
Definition: base/logging.h:887
double lower_bound
bool VariableIsAssigned(BooleanVariable var) const
Definition: sat_base.h:159
void SetPropagatorPriority(int id, int priority)
Definition: integer.cc:2019
int64_t capacity
std::function< std::vector< IntegerEncoder::ValueLiteralPair >Model *)> FullyEncodeVariable(IntegerVariable var)
Definition: integer.h:1645
int index
Definition: pack.cc:509
#define DCHECK_GE(val1, val2)
Definition: base/logging.h:890
void WatchLiteral(Literal l, int id, int watch_index=-1)
Definition: integer.h:1422
const std::vector< IntVar * > vars_
Definition: alldiff_cst.cc:44
const LiteralIndex kFalseLiteralIndex(-3)
std::vector< IntegerVariable > NegationOf(const std::vector< IntegerVariable > &vars)
Definition: integer.cc:29
#define DCHECK(condition)
Definition: base/logging.h:885
AllDifferentConstraint(std::vector< IntegerVariable > variables, IntegerEncoder *encoder, Trail *trail, IntegerTrail *integer_trail)
void FindStronglyConnectedComponents(const NodeIndex num_nodes, const Graph &graph, SccOutput *components)
#define DCHECK_EQ(val1, val2)
Definition: base/logging.h:886
void WatchIntegerVariable(IntegerVariable i, int id, int watch_index=-1)
Definition: integer.h:1454
std::function< void(Model *)> AllDifferentAC(const std::vector< IntegerVariable > &variables)
Definition: all_different.h:59
#define DCHECK_LE(val1, val2)
Definition: base/logging.h:888
int Register(PropagatorInterface *propagator)
Definition: integer.cc:1996
IntegerValue UpperBound(IntegerVariable i) const
Definition: integer.h:1349
Collection of objects used to extend the Constraint Solver library.
const IntegerVariable kNoIntegerVariable(-1)
std::function< void(Model *)> AllDifferentOnBounds(const std::vector< IntegerVariable > &vars)
Definition: all_different.h:46
static IntegerLiteral GreaterOrEqual(IntegerVariable i, IntegerValue bound)
Definition: integer.h:1309
std::vector< ValueLiteralPair > FullDomainEncoding(IntegerVariable var) const
Definition: integer.cc:133
const VariablesAssignment & Assignment() const
Definition: sat_base.h:381
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
ABSL_MUST_USE_RESULT bool EnqueueWithStoredReason(Literal true_literal)
Definition: sat_base.h:285
int64_t value
int64_t a