23#include "absl/container/btree_map.h"
24#include "absl/log/check.h"
25#include "absl/types/span.h"
39 const std::vector<IntegerVariable>& vars) {
45 absl::btree_map<IntegerValue, std::vector<Literal>> value_to_literals;
47 for (
const IntegerVariable
var : vars) {
50 value_to_literals[entry.value].push_back(entry.literal);
55 for (
const auto& entry : value_to_literals) {
56 if (entry.second.size() > 1) {
64 if (value_to_literals.size() == vars.size()) {
65 for (
const auto& entry : value_to_literals) {
73 const std::vector<AffineExpression>& expressions) {
75 if (expressions.empty())
return;
79 model->TakeOwnership(constraint);
84 const std::vector<IntegerVariable>& vars) {
86 if (vars.empty())
return;
87 std::vector<AffineExpression> expressions;
88 expressions.reserve(vars.size());
89 for (
const IntegerVariable
var : vars) {
95 model->TakeOwnership(constraint);
100 const std::vector<IntegerVariable>& variables) {
102 if (variables.size() < 3)
return;
108 model->TakeOwnership(constraint);
115 : num_variables_(variables.
size()),
116 variables_(
std::move(variables)),
118 integer_trail_(integer_trail) {
120 int64_t min_value = std::numeric_limits<int64_t>::max();
121 int64_t max_value = std::numeric_limits<int64_t>::min();
122 variable_min_value_.resize(num_variables_);
123 variable_max_value_.resize(num_variables_);
124 variable_literal_index_.resize(num_variables_);
125 int num_fixed_variables = 0;
126 for (
int x = 0;
x < num_variables_;
x++) {
127 variable_min_value_[
x] = integer_trail_->
LowerBound(variables_[
x]).value();
128 variable_max_value_[
x] = integer_trail_->
UpperBound(variables_[
x]).value();
131 min_value = std::min(min_value, variable_min_value_[
x]);
132 max_value = std::max(max_value, variable_max_value_[
x]);
136 if (variable_min_value_[
x] == variable_max_value_[
x]) {
137 num_fixed_variables++;
148 int64_t
size = variable_max_value_[
x] - variable_min_value_[
x] + 1;
151 int64_t
value = entry.value.value();
153 if (
value < variable_min_value_[
x] || variable_max_value_[
x] <
value) {
156 variable_literal_index_[
x][
value - variable_min_value_[
x]] =
157 entry.literal.Index();
160 min_all_values_ = min_value;
161 num_all_values_ = max_value - min_value + 1;
163 successor_.resize(num_variables_);
164 variable_to_value_.assign(num_variables_, -1);
165 visiting_.resize(num_variables_);
166 variable_visited_from_.resize(num_variables_);
167 residual_graph_successors_.resize(num_variables_ + num_all_values_ + 1);
168 component_number_.resize(num_variables_ + num_all_values_ + 1);
172 const int id = watcher->
Register(
this);
174 for (
const auto& literal_indices : variable_literal_index_) {
175 for (
const LiteralIndex li : literal_indices) {
186LiteralIndex AllDifferentConstraint::VariableLiteralIndexOf(
int x,
188 return (
value < variable_min_value_[
x] || variable_max_value_[
x] <
value)
190 : variable_literal_index_[
x][
value - variable_min_value_[
x]];
193inline bool AllDifferentConstraint::VariableHasPossibleValue(
int x,
195 LiteralIndex li = VariableLiteralIndexOf(
x,
value);
202bool AllDifferentConstraint::MakeAugmentingPath(
int start) {
207 int num_to_visit = 0;
210 visiting_[num_to_visit++] =
start;
211 variable_visited_[
start] =
true;
212 variable_visited_from_[
start] = -1;
214 while (num_visited < num_to_visit) {
216 const int node = visiting_[num_visited++];
218 for (
const int value : successor_[node]) {
219 if (value_visited_[
value])
continue;
220 value_visited_[
value] =
true;
221 if (value_to_variable_[
value] == -1) {
223 int path_node = node;
224 int path_value =
value;
225 while (path_node != -1) {
226 int old_value = variable_to_value_[path_node];
227 variable_to_value_[path_node] = path_value;
228 value_to_variable_[path_value] = path_node;
229 path_node = variable_visited_from_[path_node];
230 path_value = old_value;
235 const int next_node = value_to_variable_[
value];
236 variable_visited_[next_node] =
true;
237 visiting_[num_to_visit++] = next_node;
238 variable_visited_from_[next_node] = node;
262 prev_matching_ = variable_to_value_;
263 value_to_variable_.assign(num_all_values_, -1);
264 variable_to_value_.assign(num_variables_, -1);
265 for (
int x = 0;
x < num_variables_;
x++) {
266 successor_[
x].clear();
267 const int64_t min_value = integer_trail_->
LowerBound(variables_[
x]).value();
268 const int64_t max_value = integer_trail_->
UpperBound(variables_[
x]).value();
270 if (VariableHasPossibleValue(
x,
value)) {
271 const int offset_value =
value - min_all_values_;
273 successor_[
x].push_back(offset_value);
276 if (successor_[
x].
size() == 1) {
277 const int offset_value = successor_[
x][0];
278 if (value_to_variable_[offset_value] == -1) {
279 value_to_variable_[offset_value] =
x;
280 variable_to_value_[
x] = offset_value;
288 for (
int x = 0;
x < num_variables_;
x++) {
289 for (
const int offset_value : successor_[
x]) {
290 if (value_to_variable_[offset_value] != -1 &&
291 value_to_variable_[offset_value] !=
x) {
292 LOG(FATAL) <<
"Should have been propagated by AllDifferentBinary()!";
299 for (
int x = 0;
x < num_variables_;
x++) {
300 if (variable_to_value_[
x] != -1)
continue;
301 const int prev_value = prev_matching_[
x];
302 if (prev_value == -1 || value_to_variable_[prev_value] != -1)
continue;
304 if (VariableHasPossibleValue(
x, prev_matching_[
x] + min_all_values_)) {
305 variable_to_value_[
x] = prev_matching_[
x];
306 value_to_variable_[prev_matching_[
x]] =
x;
312 for (;
x < num_variables_;
x++) {
313 if (variable_to_value_[
x] == -1) {
314 value_visited_.assign(num_all_values_,
false);
315 variable_visited_.assign(num_variables_,
false);
316 MakeAugmentingPath(
x);
318 if (variable_to_value_[
x] == -1)
break;
324 if (
x < num_variables_) {
328 for (
int y = 0;
y < num_variables_;
y++) {
329 if (!variable_visited_[
y])
continue;
330 for (
int value = variable_min_value_[
y];
value <= variable_max_value_[
y];
332 const LiteralIndex li = VariableLiteralIndexOf(
y,
value);
333 if (li >= 0 && !value_visited_[
value - min_all_values_]) {
335 conflict->push_back(
Literal(li));
344 for (
int x = 0;
x < num_variables_;
x++) {
345 residual_graph_successors_[
x].clear();
346 for (
const int succ : successor_[
x]) {
347 if (succ != variable_to_value_[
x]) {
348 residual_graph_successors_[
x].push_back(num_variables_ + succ);
352 for (
int offset_value = 0; offset_value < num_all_values_; offset_value++) {
353 residual_graph_successors_[num_variables_ + offset_value].clear();
354 if (value_to_variable_[offset_value] != -1) {
355 residual_graph_successors_[num_variables_ + offset_value].push_back(
356 value_to_variable_[offset_value]);
359 const int dummy_node = num_variables_ + num_all_values_;
360 residual_graph_successors_[dummy_node].clear();
361 if (num_variables_ < num_all_values_) {
362 for (
int x = 0;
x < num_variables_;
x++) {
363 residual_graph_successors_[dummy_node].push_back(
x);
365 for (
int offset_value = 0; offset_value < num_all_values_; offset_value++) {
366 if (value_to_variable_[offset_value] == -1) {
367 residual_graph_successors_[num_variables_ + offset_value].push_back(
375 explicit SccOutput(std::vector<int>* c) : components(c) {}
376 void emplace_back(
int const*
b,
int const* e) {
377 for (
int const* it =
b; it < e; ++it) {
378 (*components)[*it] = num_components;
382 int num_components = 0;
383 std::vector<int>* components;
385 SccOutput scc_output(&component_number_);
387 static_cast<int>(residual_graph_successors_.size()),
388 residual_graph_successors_, &scc_output);
391 for (
int x = 0;
x < num_variables_;
x++) {
392 if (successor_[
x].
size() == 1)
continue;
393 for (
const int offset_value : successor_[
x]) {
394 const int value_node = offset_value + num_variables_;
395 if (variable_to_value_[
x] != offset_value &&
396 component_number_[
x] != component_number_[value_node] &&
397 VariableHasPossibleValue(
x, offset_value + min_all_values_)) {
402 value_visited_.assign(num_all_values_,
false);
403 variable_visited_.assign(num_variables_,
false);
405 const int old_variable = value_to_variable_[offset_value];
406 variable_to_value_[old_variable] = -1;
407 const int old_value = variable_to_value_[
x];
408 value_to_variable_[old_value] = -1;
409 variable_to_value_[
x] = offset_value;
410 value_to_variable_[offset_value] =
x;
412 value_visited_[offset_value] =
true;
413 MakeAugmentingPath(old_variable);
414 DCHECK_EQ(variable_to_value_[old_variable], -1);
417 for (
int y = 0;
y < num_variables_;
y++) {
418 if (!variable_visited_[
y])
continue;
419 for (
int value = variable_min_value_[
y];
421 const LiteralIndex li = VariableLiteralIndexOf(
y,
value);
422 if (li >= 0 && !value_visited_[
value - min_all_values_]) {
423 DCHECK(!VariableHasPossibleValue(
y,
value));
424 reason->push_back(
Literal(li));
429 const LiteralIndex li =
430 VariableLiteralIndexOf(
x, offset_value + min_all_values_);
442 const std::vector<AffineExpression>& expressions,
444 : integer_trail_(integer_trail) {
445 CHECK(!expressions.empty());
448 const int capacity = expressions.size() + 2;
449 index_to_start_index_.resize(capacity);
450 index_to_end_index_.resize(capacity);
451 index_is_present_.resize(capacity,
false);
454 for (
int i = 0;
i < expressions.size(); ++
i) {
455 bounds_.push_back({expressions[
i]});
456 negated_bounds_.push_back({expressions[
i].Negated()});
461 if (!PropagateLowerBounds())
return false;
465 std::swap(bounds_, negated_bounds_);
466 const bool result = PropagateLowerBounds();
467 std::swap(bounds_, negated_bounds_);
471void AllDifferentBoundsPropagator::FillHallReason(IntegerValue hall_lb,
472 IntegerValue hall_ub) {
473 integer_reason_.clear();
474 const int limit = GetIndex(hall_ub);
475 for (
int i = GetIndex(hall_lb);
i <= limit; ++
i) {
482int AllDifferentBoundsPropagator::FindStartIndexAndCompressPath(
int index) {
484 int start_index =
index;
486 const int next = index_to_start_index_[start_index];
487 if (start_index ==
next)
break;
493 const int next = index_to_start_index_[
index];
494 if (start_index ==
next)
break;
495 index_to_start_index_[
index] = start_index;
501bool AllDifferentBoundsPropagator::PropagateLowerBounds() {
503 for (CachedBounds& entry : bounds_) {
504 entry.lb = integer_trail_->
LowerBound(entry.expr);
505 entry.ub = integer_trail_->
UpperBound(entry.expr);
508 [](CachedBounds
a, CachedBounds
b) { return a.lb < b.lb; });
513 int num_in_window = 1;
516 IntegerValue min_lb = bounds_.front().lb;
518 const int size = bounds_.size();
519 for (
int i = 1;
i <
size; ++
i) {
520 const IntegerValue lb = bounds_[
i].lb;
525 if (lb <= min_lb + IntegerValue(num_in_window - 1)) {
531 if (num_in_window > 1) {
532 absl::Span<CachedBounds> window(&bounds_[
start], num_in_window);
533 if (!PropagateLowerBoundsInternal(min_lb, window)) {
545 if (num_in_window > 1) {
546 absl::Span<CachedBounds> window(&bounds_[
start], num_in_window);
547 return PropagateLowerBoundsInternal(min_lb, window);
553bool AllDifferentBoundsPropagator::PropagateLowerBoundsInternal(
554 IntegerValue min_lb, absl::Span<CachedBounds> bounds) {
555 hall_starts_.clear();
560 base_ = min_lb - IntegerValue(1);
563 for (
const int i : indices_to_clear_) {
564 index_is_present_[
i] =
false;
566 indices_to_clear_.clear();
569 std::sort(bounds.begin(), bounds.end(),
570 [](CachedBounds
a, CachedBounds
b) { return a.ub < b.ub; });
571 for (
const CachedBounds entry : bounds) {
572 const AffineExpression expr = entry.expr;
577 const IntegerValue lb = entry.lb;
578 const int lb_index = GetIndex(lb);
579 const bool value_is_covered = index_is_present_[lb_index];
582 if (value_is_covered) {
583 const int hall_index =
584 std::lower_bound(hall_ends_.begin(), hall_ends_.end(), lb) -
586 if (hall_index < hall_ends_.size() && hall_starts_[hall_index] <= lb) {
587 const IntegerValue hs = hall_starts_[hall_index];
588 const IntegerValue he = hall_ends_[hall_index];
589 FillHallReason(hs, he);
590 integer_reason_.push_back(expr.GreaterOrEqual(hs));
591 if (!integer_trail_->
SafeEnqueue(expr.GreaterOrEqual(he + 1),
603 int new_index = lb_index;
604 int start_index = lb_index;
605 int end_index = lb_index;
606 if (value_is_covered) {
607 start_index = FindStartIndexAndCompressPath(new_index);
608 new_index = index_to_end_index_[start_index] + 1;
609 end_index = new_index;
611 if (index_is_present_[new_index - 1]) {
612 start_index = FindStartIndexAndCompressPath(new_index - 1);
615 if (index_is_present_[new_index + 1]) {
616 end_index = index_to_end_index_[new_index + 1];
617 index_to_start_index_[new_index + 1] = start_index;
621 index_to_end_index_[start_index] = end_index;
625 index_to_start_index_[new_index] = start_index;
626 index_to_expr_[new_index] = expr;
627 index_is_present_[new_index] =
true;
628 indices_to_clear_.push_back(new_index);
637 const IntegerValue
end = GetValue(end_index);
647 if (
end == entry.ub) {
648 const IntegerValue
start = GetValue(start_index);
649 while (!hall_starts_.empty() &&
start <= hall_starts_.back()) {
650 hall_starts_.pop_back();
651 hall_ends_.pop_back();
653 DCHECK(hall_ends_.empty() || hall_ends_.back() <
start);
654 hall_starts_.push_back(
start);
655 hall_ends_.push_back(
end);
663 const int id = watcher->
Register(
this);
664 for (
const CachedBounds& entry : bounds_) {
void RegisterWith(GenericLiteralWatcher *watcher)
AllDifferentBoundsPropagator(const std::vector< AffineExpression > &expressions, IntegerTrail *integer_trail)
Implementation of AllDifferentAC().
AllDifferentConstraint(std::vector< IntegerVariable > variables, IntegerEncoder *encoder, Trail *trail, IntegerTrail *integer_trail)
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
void FullyEncodeVariable(IntegerVariable var)
bool VariableIsFullyEncoded(IntegerVariable var) const
IntegerValue LowerBound(IntegerVariable i) const
Returns the current lower/upper bound of the given integer variable.
ABSL_MUST_USE_RESULT bool SafeEnqueue(IntegerLiteral i_lit, absl::Span< const IntegerLiteral > integer_reason)
IntegerValue UpperBound(IntegerVariable i) const
std::vector< Literal > * MutableConflict()
std::vector< Literal > * GetEmptyVectorToStoreReason(int trail_index) const
ABSL_MUST_USE_RESULT bool EnqueueWithStoredReason(Literal true_literal)
const VariablesAssignment & Assignment() const
bool VariableIsAssigned(BooleanVariable var) const
Returns true iff the given variable is assigned.
bool LiteralIsFalse(Literal literal) const
std::function< std::vector< ValueLiteralPair >(Model *)> FullyEncodeVariable(IntegerVariable var)
std::function< void(Model *)> ClauseConstraint(absl::Span< const Literal > literals)
std::function< void(Model *)> AllDifferentAC(const std::vector< IntegerVariable > &variables)
const IntegerVariable kNoIntegerVariable(-1)
const LiteralIndex kTrueLiteralIndex(-2)
std::function< void(Model *)> AtMostOneConstraint(const std::vector< Literal > &literals)
const LiteralIndex kFalseLiteralIndex(-3)
std::function< void(Model *)> AllDifferentBinary(const std::vector< IntegerVariable > &vars)
std::function< void(Model *)> AllDifferentOnBounds(const std::vector< AffineExpression > &expressions)
In SWIG mode, we don't want anything besides these top-level includes.
void IncrementalSort(int max_comparisons, Iterator begin, Iterator end, Compare comp=Compare{}, bool is_stable=false)
std::optional< int64_t > end
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.