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"
28#include "ortools/util/sort.h"
29
30namespace operations_research {
31namespace sat {
32
33std::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
67std::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
78std::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
165LiteralIndex 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
172inline 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
181bool 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
448void 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
459int 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
478bool 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
530bool 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
const std::vector< IntVar * > vars_
Definition: alldiff_cst.cc:44
int64_t max
Definition: alldiff_cst.cc:140
int64_t min
Definition: alldiff_cst.cc:139
#define CHECK(condition)
Definition: base/logging.h:491
#define DCHECK_LE(val1, val2)
Definition: base/logging.h:888
#define DCHECK_NE(val1, val2)
Definition: base/logging.h:887
#define DCHECK_GE(val1, val2)
Definition: base/logging.h:890
#define LOG(severity)
Definition: base/logging.h:416
#define DCHECK(condition)
Definition: base/logging.h:885
#define DCHECK_EQ(val1, val2)
Definition: base/logging.h:886
AllDifferentBoundsPropagator(const std::vector< IntegerVariable > &vars, IntegerTrail *integer_trail)
void RegisterWith(GenericLiteralWatcher *watcher)
void RegisterWith(GenericLiteralWatcher *watcher)
AllDifferentConstraint(std::vector< IntegerVariable > variables, IntegerEncoder *encoder, Trail *trail, IntegerTrail *integer_trail)
void WatchLiteral(Literal l, int id, int watch_index=-1)
Definition: integer.h:1422
void WatchIntegerVariable(IntegerVariable i, int id, int watch_index=-1)
Definition: integer.h:1454
void SetPropagatorPriority(int id, int priority)
Definition: integer.cc:2019
int Register(PropagatorInterface *propagator)
Definition: integer.cc:1996
void FullyEncodeVariable(IntegerVariable var)
Definition: integer.cc:67
std::vector< ValueLiteralPair > FullDomainEncoding(IntegerVariable var) const
Definition: integer.cc:133
bool VariableIsFullyEncoded(IntegerVariable var) const
Definition: integer.cc:97
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
IntegerValue UpperBound(IntegerVariable i) const
Definition: integer.h:1349
IntegerValue LowerBound(IntegerVariable i) const
Definition: integer.h:1345
Class that owns everything related to a particular optimization model.
Definition: sat/model.h:38
std::vector< Literal > * GetEmptyVectorToStoreReason(int trail_index) const
Definition: sat_base.h:321
const VariablesAssignment & Assignment() const
Definition: sat_base.h:381
ABSL_MUST_USE_RESULT bool EnqueueWithStoredReason(Literal true_literal)
Definition: sat_base.h:285
std::vector< Literal > * MutableConflict()
Definition: sat_base.h:362
bool VariableIsAssigned(BooleanVariable var) const
Definition: sat_base.h:159
bool LiteralIsFalse(Literal literal) const
Definition: sat_base.h:148
int64_t b
int64_t a
Block * next
int64_t value
IntVar * var
Definition: expr_array.cc:1874
double lower_bound
GRBmodel * model
const int FATAL
Definition: log_severity.h:32
const bool DEBUG_MODE
Definition: macros.h:24
void swap(IdMap< K, V > &a, IdMap< K, V > &b)
Definition: id_map.h:263
std::function< void(Model *)> AllDifferentAC(const std::vector< IntegerVariable > &variables)
std::function< void(Model *)> ClauseConstraint(absl::Span< const Literal > literals)
Definition: sat_solver.h:906
std::function< void(Model *)> AllDifferentOnBounds(const std::vector< IntegerVariable > &vars)
const IntegerVariable kNoIntegerVariable(-1)
const LiteralIndex kTrueLiteralIndex(-2)
std::function< void(Model *)> AtMostOneConstraint(const std::vector< Literal > &literals)
Definition: sat_solver.h:892
const LiteralIndex kFalseLiteralIndex(-3)
std::function< void(Model *)> AllDifferentBinary(const std::vector< IntegerVariable > &vars)
std::vector< IntegerVariable > NegationOf(const std::vector< IntegerVariable > &vars)
Definition: integer.cc:29
std::function< std::vector< IntegerEncoder::ValueLiteralPair >(Model *)> FullyEncodeVariable(IntegerVariable var)
Definition: integer.h:1645
Collection of objects used to extend the Constraint Solver library.
void IncrementalSort(int max_comparisons, Iterator begin, Iterator end, Compare comp=Compare{}, bool is_stable=false)
Definition: sort.h:46
STL namespace.
int index
Definition: pack.cc:509
int64_t capacity
void FindStronglyConnectedComponents(const NodeIndex num_nodes, const Graph &graph, SccOutput *components)
static IntegerLiteral LowerOrEqual(IntegerVariable i, IntegerValue bound)
Definition: integer.h:1315
static IntegerLiteral GreaterOrEqual(IntegerVariable i, IntegerValue bound)
Definition: integer.h:1309