23#include "absl/algorithm/container.h"
24#include "absl/container/btree_map.h"
25#include "absl/container/flat_hash_map.h"
26#include "absl/log/check.h"
27#include "absl/types/span.h"
42 absl::Span<const IntegerVariable> vars) {
43 return [=, vars = std::vector<IntegerVariable>(vars.begin(), vars.end())](
49 absl::btree_map<IntegerValue, std::vector<Literal>> value_to_literals;
51 for (
const IntegerVariable var : vars) {
54 value_to_literals[entry.value].push_back(entry.literal);
59 for (
const auto& entry : value_to_literals) {
60 if (entry.second.size() > 1) {
68 if (value_to_literals.size() == vars.size()) {
69 for (
const auto& entry : value_to_literals) {
77 absl::Span<const AffineExpression> expressions) {
78 return [=, expressions = std::vector<AffineExpression>(
79 expressions.begin(), expressions.end())](
Model* model) {
80 if (expressions.empty())
return;
84 model->TakeOwnership(constraint);
89 absl::Span<const IntegerVariable> vars) {
90 return [=, vars = std::vector<IntegerVariable>(vars.begin(), vars.end())](
92 if (vars.empty())
return;
93 std::vector<AffineExpression> expressions;
94 expressions.reserve(vars.size());
95 for (
const IntegerVariable var : vars) {
101 model->TakeOwnership(constraint);
106 absl::Span<const IntegerVariable> variables) {
107 return [variables](
Model* model) {
108 if (variables.size() < 3)
return;
113 model->TakeOwnership(constraint);
118 absl::Span<const IntegerVariable> variables,
Model* model)
119 : num_variables_(variables.size()),
120 trail_(model->GetOrCreate<
Trail>()),
125 absl::flat_hash_map<IntegerValue, int> dense_indexing;
126 variable_to_possible_values_.resize(num_variables_);
128 for (
int x = 0; x < num_variables_; x++) {
129 const IntegerValue lb = integer_trail_->LowerBound(variables[x]);
130 const IntegerValue ub = integer_trail_->UpperBound(variables[x]);
135 const auto [it, inserted] = dense_indexing.insert({lb, num_values_});
136 if (inserted) ++num_values_;
138 variable_to_possible_values_[x].push_back(
139 {it->second, encoder->GetTrueLiteral()});
144 if (!encoder->VariableIsFullyEncoded(variables[x])) {
145 encoder->FullyEncodeVariable(variables[x]);
149 for (
const auto [value, lit] : encoder->FullDomainEncoding(variables[x])) {
150 const auto [it, inserted] = dense_indexing.insert({value, num_values_});
151 if (inserted) ++num_values_;
153 variable_to_possible_values_[x].push_back({it->second, lit});
158 variable_to_possible_values_[x],
159 [](
const std::pair<int, Literal>& a,
const std::pair<int, Literal>&
b) {
160 return a.first <
b.first;
164 variable_to_value_.assign(num_variables_, -1);
165 visiting_.resize(num_variables_);
166 variable_visited_from_.resize(num_variables_);
167 component_number_.resize(num_variables_ + num_values_ + 1);
171 int num_nodes, absl::Span<const int> tails, absl::Span<const int> heads,
172 absl::Span<const Literal> literals,
Model* model)
173 : num_variables_(num_nodes),
174 trail_(model->GetOrCreate<
Trail>()),
176 num_values_ = num_nodes;
179 const int num_arcs = tails.size();
180 variable_to_possible_values_.resize(num_variables_);
181 for (
int a = 0; a < num_arcs; ++a) {
182 variable_to_possible_values_[tails[a]].push_back({heads[a], literals[a]});
185 variable_to_value_.assign(num_variables_, -1);
186 visiting_.resize(num_variables_);
187 variable_visited_from_.resize(num_variables_);
188 component_number_.resize(num_variables_ + num_values_ + 1);
192 const int id = watcher->
Register(
this);
194 for (
int x = 0; x < num_variables_; x++) {
195 for (
const auto [_, lit] : variable_to_possible_values_[x]) {
197 if (!trail_->Assignment().LiteralIsAssigned(lit)) {
205bool AllDifferentConstraint::MakeAugmentingPath(
int start) {
210 int num_to_visit = 0;
213 visiting_[num_to_visit++] = start;
214 variable_visited_[start] =
true;
215 variable_visited_from_[start] = -1;
217 while (num_visited < num_to_visit) {
219 const int node = visiting_[num_visited++];
221 for (
const int value : successor_[node]) {
222 if (value_visited_[value])
continue;
223 value_visited_[value] =
true;
224 if (value_to_variable_[value] == -1) {
226 int path_node = node;
227 int path_value = value;
228 while (path_node != -1) {
229 int old_value = variable_to_value_[path_node];
230 variable_to_value_[path_node] = path_value;
231 value_to_variable_[path_value] = path_node;
232 path_node = variable_visited_from_[path_node];
233 path_value = old_value;
238 const int next_node = value_to_variable_[value];
239 variable_visited_[next_node] =
true;
240 visiting_[num_to_visit++] = next_node;
241 variable_visited_from_[next_node] = node;
265 prev_matching_ = variable_to_value_;
266 value_to_variable_.assign(num_values_, -1);
267 variable_to_value_.assign(num_variables_, -1);
270 for (
int x = 0; x < num_variables_; x++) {
272 for (
const auto [value, lit] : variable_to_possible_values_[x]) {
273 if (assignment.LiteralIsFalse(lit))
continue;
276 successor_.AppendToLastVector(value);
279 if (prev_matching_[x] == value && value_to_variable_[value] == -1) {
280 variable_to_value_[x] = prev_matching_[x];
281 value_to_variable_[prev_matching_[x]] = x;
284 if (successor_[x].size() == 1) {
285 const int value = successor_[x][0];
286 if (value_to_variable_[value] == -1) {
287 value_to_variable_[value] = x;
288 variable_to_value_[x] = value;
295 for (; x < num_variables_; x++) {
296 if (variable_to_value_[x] == -1) {
297 value_visited_.assign(num_values_,
false);
298 variable_visited_.assign(num_variables_,
false);
299 MakeAugmentingPath(x);
301 if (variable_to_value_[x] == -1)
break;
307 if (x < num_variables_) {
309 std::vector<Literal>* conflict = trail_->MutableConflict();
311 for (
int y = 0; y < num_variables_; y++) {
312 if (!variable_visited_[y])
continue;
313 for (
const auto [value, lit] : variable_to_possible_values_[y]) {
314 if (!value_visited_[value]) {
315 DCHECK(assignment.LiteralIsFalse(lit));
316 conflict->push_back(lit);
325 residual_graph_successors_.clear();
326 for (
int x = 0; x < num_variables_; x++) {
327 residual_graph_successors_.Add({});
328 for (
const int succ : successor_[x]) {
329 if (succ != variable_to_value_[x]) {
330 residual_graph_successors_.AppendToLastVector(num_variables_ + succ);
335 const int dummy_node = num_variables_ + num_values_;
336 const bool need_dummy = num_variables_ < num_values_;
337 for (
int value = 0; value < num_values_; value++) {
338 residual_graph_successors_.Add({});
339 if (value_to_variable_[value] != -1) {
340 residual_graph_successors_.AppendToLastVector(value_to_variable_[value]);
341 }
else if (need_dummy) {
342 residual_graph_successors_.AppendToLastVector(dummy_node);
346 DCHECK_EQ(residual_graph_successors_.size(), dummy_node);
347 residual_graph_successors_.Add({});
348 for (
int x = 0; x < num_variables_; x++) {
349 residual_graph_successors_.AppendToLastVector(x);
355 explicit SccOutput(std::vector<int>* c) : components(c) {}
356 void emplace_back(
int const*
b,
int const* e) {
357 for (
int const* it =
b; it < e; ++it) {
358 (*components)[*it] = num_components;
362 int num_components = 0;
363 std::vector<int>* components;
365 SccOutput scc_output(&component_number_);
367 static_cast<int>(residual_graph_successors_.size()),
368 residual_graph_successors_, &scc_output);
371 for (
int x = 0; x < num_variables_; x++) {
372 if (successor_[x].size() == 1)
continue;
373 for (
const auto [value, x_lit] : variable_to_possible_values_[x]) {
374 if (assignment.LiteralIsFalse(x_lit))
continue;
376 const int value_node = value + num_variables_;
377 DCHECK_LT(value_node, component_number_.size());
378 if (variable_to_value_[x] != value &&
379 component_number_[x] != component_number_[value_node]) {
384 value_visited_.assign(num_values_,
false);
385 variable_visited_.assign(num_variables_,
false);
387 const int old_variable = value_to_variable_[value];
388 DCHECK_GE(old_variable, 0);
389 DCHECK_LT(old_variable, num_variables_);
390 variable_to_value_[old_variable] = -1;
391 const int old_value = variable_to_value_[x];
392 value_to_variable_[old_value] = -1;
393 variable_to_value_[x] = value;
394 value_to_variable_[value] = x;
396 value_visited_[value] =
true;
397 MakeAugmentingPath(old_variable);
398 DCHECK_EQ(variable_to_value_[old_variable], -1);
400 std::vector<Literal>* reason = trail_->GetEmptyVectorToStoreReason();
401 for (
int y = 0; y < num_variables_; y++) {
402 if (!variable_visited_[y])
continue;
403 for (
const auto [value, y_lit] : variable_to_possible_values_[y]) {
404 if (!value_visited_[value]) {
405 DCHECK(assignment.LiteralIsFalse(y_lit));
406 reason->push_back(y_lit);
411 return trail_->EnqueueWithStoredReason(x_lit.Negated());
420 absl::Span<const AffineExpression> expressions,
IntegerTrail* integer_trail)
421 : integer_trail_(integer_trail) {
422 CHECK(!expressions.empty());
425 const int capacity = expressions.size() + 2;
426 index_to_start_index_.resize(capacity);
427 index_to_end_index_.resize(capacity);
428 index_is_present_.Resize(capacity);
431 for (
int i = 0;
i < expressions.size(); ++
i) {
432 bounds_.push_back({expressions[
i]});
433 negated_bounds_.push_back({expressions[
i].Negated()});
438 if (!PropagateLowerBounds())
return false;
442 std::swap(bounds_, negated_bounds_);
443 const bool result = PropagateLowerBounds();
444 std::swap(bounds_, negated_bounds_);
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) {
459int AllDifferentBoundsPropagator::FindStartIndexAndCompressPath(
int index) {
461 int start_index = index;
463 const int next = index_to_start_index_[start_index];
464 if (start_index == next)
break;
470 const int next = index_to_start_index_[index];
471 if (start_index == next)
break;
472 index_to_start_index_[index] = start_index;
478bool AllDifferentBoundsPropagator::PropagateLowerBounds() {
480 for (CachedBounds& entry : bounds_) {
481 entry.lb = integer_trail_->LowerBound(entry.expr);
482 entry.ub = integer_trail_->UpperBound(entry.expr);
485 [](CachedBounds a, CachedBounds
b) { return a.lb < b.lb; });
490 int num_in_window = 1;
493 IntegerValue min_lb = bounds_.front().lb;
495 const int size = bounds_.size();
496 for (
int i = 1;
i < size; ++
i) {
497 const IntegerValue lb = bounds_[
i].lb;
502 if (lb <= min_lb + IntegerValue(num_in_window - 1)) {
508 if (num_in_window > 1) {
509 absl::Span<CachedBounds> window(&bounds_[start], num_in_window);
510 if (!PropagateLowerBoundsInternal(min_lb, window)) {
522 if (num_in_window > 1) {
523 absl::Span<CachedBounds> window(&bounds_[start], num_in_window);
524 return PropagateLowerBoundsInternal(min_lb, window);
530bool AllDifferentBoundsPropagator::PropagateLowerBoundsInternal(
531 IntegerValue min_lb, absl::Span<CachedBounds> bounds) {
532 hall_starts_.clear();
537 base_ = min_lb - IntegerValue(1);
539 index_is_present_.ResetAllToFalse();
542 std::sort(bounds.begin(), bounds.end(),
543 [](CachedBounds a, CachedBounds
b) { return a.ub < b.ub; });
544 for (
const CachedBounds entry : bounds) {
545 const AffineExpression expr = entry.expr;
550 const IntegerValue lb = entry.lb;
551 const int lb_index = GetIndex(lb);
552 const bool value_is_covered = index_is_present_[lb_index];
555 if (value_is_covered) {
556 const int hall_index =
557 std::lower_bound(hall_ends_.begin(), hall_ends_.end(), lb) -
559 if (hall_index < hall_ends_.size() && hall_starts_[hall_index] <= lb) {
560 const IntegerValue hs = hall_starts_[hall_index];
561 const IntegerValue he = hall_ends_[hall_index];
562 FillHallReason(hs, he);
563 integer_reason_.push_back(expr.GreaterOrEqual(hs));
564 if (!integer_trail_->SafeEnqueue(expr.GreaterOrEqual(he + 1),
576 int new_index = lb_index;
577 int start_index = lb_index;
578 int end_index = lb_index;
579 if (value_is_covered) {
580 start_index = FindStartIndexAndCompressPath(new_index);
581 new_index = index_to_end_index_[start_index] + 1;
582 end_index = new_index;
584 if (index_is_present_[new_index - 1]) {
585 start_index = FindStartIndexAndCompressPath(new_index - 1);
588 if (index_is_present_[new_index + 1]) {
589 end_index = index_to_end_index_[new_index + 1];
590 index_to_start_index_[new_index + 1] = start_index;
594 index_to_end_index_[start_index] = end_index;
598 index_to_start_index_[new_index] = start_index;
599 index_to_expr_[new_index] = expr;
600 index_is_present_.Set(new_index);
609 const IntegerValue
end = GetValue(end_index);
610 if (
end > integer_trail_->UpperBound(expr))
return true;
619 if (
end == entry.ub) {
620 const IntegerValue start = GetValue(start_index);
621 while (!hall_starts_.empty() && start <= hall_starts_.back()) {
622 hall_starts_.pop_back();
623 hall_ends_.pop_back();
625 DCHECK(hall_ends_.empty() || hall_ends_.back() < start);
626 hall_starts_.push_back(start);
627 hall_ends_.push_back(
end);
635 const int id = watcher->
Register(
this);
636 for (
const CachedBounds& entry : bounds_) {
void RegisterWith(GenericLiteralWatcher *watcher)
AllDifferentBoundsPropagator(absl::Span< const AffineExpression > expressions, IntegerTrail *integer_trail)
Implementation of AllDifferentAC().
AllDifferentConstraint(absl::Span< const IntegerVariable > variables, Model *model)
void RegisterWith(GenericLiteralWatcher *watcher)
void WatchAffineExpression(AffineExpression e, int id)
void NotifyThatPropagatorMayNotReachFixedPointInOnePass(int id)
void WatchLiteral(Literal l, int id, int watch_index=-1)
void SetPropagatorPriority(int id, int priority)
int Register(PropagatorInterface *propagator)
Registers a propagator and returns its unique ids.
const std::vector< ValueLiteralPair > & FullDomainEncoding(IntegerVariable var) const
std::function< std::vector< ValueLiteralPair >(Model *)> FullyEncodeVariable(IntegerVariable var)
std::function< void(Model *)> ClauseConstraint(absl::Span< const Literal > literals)
const IntegerVariable kNoIntegerVariable(-1)
std::function< void(Model *)> AllDifferentBinary(absl::Span< const IntegerVariable > vars)
std::function< void(Model *)> AllDifferentOnBounds(absl::Span< const AffineExpression > expressions)
std::function< void(Model *)> AtMostOneConstraint(absl::Span< const Literal > literals)
std::function< void(Model *)> AllDifferentAC(absl::Span< const IntegerVariable > variables)
In SWIG mode, we don't want anything besides these top-level includes.
ClosedInterval::Iterator end(ClosedInterval interval)
void IncrementalSort(int max_comparisons, Iterator begin, Iterator end, Compare comp=Compare{}, bool is_stable=false)
void FindStronglyConnectedComponents(NodeIndex num_nodes, const Graph &graph, SccOutput *components)
Simple wrapper function for most usage.
IntegerLiteral GreaterOrEqual(IntegerValue bound) const
var * coeff + constant >= bound.
IntegerLiteral LowerOrEqual(IntegerValue bound) const
var * coeff + constant <= bound.