20#include "absl/container/flat_hash_map.h"
21#include "absl/container/flat_hash_set.h"
22#include "absl/log/check.h"
23#include "absl/meta/type_traits.h"
24#include "absl/types/span.h"
39 absl::Span<const int> tails,
40 absl::Span<const int> heads,
41 absl::Span<const Literal> literals,
43 : num_nodes_(num_nodes),
45 trail_(model->GetOrCreate<
Trail>()),
47 CHECK(!tails.empty()) <<
"Empty constraint, shouldn't be constructed!";
48 next_.resize(num_nodes_, -1);
49 prev_.resize(num_nodes_, -1);
50 next_literal_.resize(num_nodes_);
51 must_be_in_cycle_.resize(num_nodes_);
52 absl::flat_hash_map<LiteralIndex, int> literal_to_watch_index;
55 const int num_arcs = tails.size();
56 std::vector<int> keys;
57 std::vector<Arc> values;
58 keys.reserve(num_arcs);
59 values.reserve(num_arcs);
61 graph_.reserve(num_arcs);
63 for (
int arc = 0; arc < num_arcs; ++arc) {
64 const int head = heads[arc];
65 const int tail = tails[arc];
66 const Literal literal = literals[arc];
67 if (assignment_.LiteralIsFalse(literal))
continue;
70 self_arcs_[tail] = literal.
Index();
72 graph_[{tail, head}] = literal;
75 if (assignment_.LiteralIsTrue(literal)) {
76 if (next_[tail] != -1 || prev_[head] != -1) {
77 VLOG(1) <<
"Trivially UNSAT or duplicate arcs while adding " << tail
87 const Literal watched_literal = tail == head ? literal.
Negated() : literal;
88 const auto& it = literal_to_watch_index.find(watched_literal.
Index());
89 int watch_index = it != literal_to_watch_index.end() ? it->second : -1;
90 if (watch_index == -1) {
91 watch_index = watch_index_to_literal_.size();
92 literal_to_watch_index[watched_literal.
Index()] = watch_index;
93 watch_index_to_literal_.push_back(watched_literal);
96 keys.push_back(watch_index);
97 values.push_back({tail, head});
99 watch_index_to_arcs_.ResetFromFlatMapping(keys, values);
101 for (
int node = 0; node < num_nodes_; ++node) {
103 assignment_.LiteralIsFalse(
Literal(self_arcs_[node]))) {
106 if (node == 0 || !options_.multiple_subcircuit_through_zero) {
107 must_be_in_cycle_[rev_must_be_in_cycle_size_++] = node;
114 const int id = watcher->
Register(
this);
115 for (
int w = 0;
w < watch_index_to_literal_.size(); ++
w) {
129 if (level == level_ends_.size())
return;
130 if (level > level_ends_.size()) {
131 while (level > level_ends_.size()) {
132 level_ends_.push_back(added_arcs_.size());
138 for (
int i = level_ends_[level];
i < added_arcs_.size(); ++
i) {
139 const Arc arc = added_arcs_[
i];
140 next_[arc.tail] = -1;
141 prev_[arc.head] = -1;
143 added_arcs_.resize(level_ends_[level]);
144 level_ends_.resize(level);
147void CircuitPropagator::FillReasonForPath(
int start_node,
148 std::vector<Literal>* reason)
const {
149 CHECK_NE(start_node, -1);
151 int node = start_node;
152 while (next_[node] != -1) {
154 reason->push_back(
Literal(next_literal_[node]).Negated());
157 if (node == start_node)
break;
163void CircuitPropagator::AddArc(
int tail,
int head, LiteralIndex literal_index) {
164 if (tail != 0 || !options_.multiple_subcircuit_through_zero) {
166 next_literal_[tail] = literal_index;
168 if (head != 0 || !options_.multiple_subcircuit_through_zero) {
174 const std::vector<int>& watch_indices) {
175 for (
const int w : watch_indices) {
176 const Literal literal = watch_index_to_literal_[
w];
177 for (
const Arc arc : watch_index_to_arcs_[
w]) {
179 if (arc.tail == arc.head) {
180 must_be_in_cycle_[rev_must_be_in_cycle_size_++] = arc.tail;
186 if (next_[arc.tail] != -1) {
187 std::vector<Literal>* conflict = trail_->MutableConflict();
192 *conflict = {literal.
Negated()};
196 if (prev_[arc.head] != -1) {
197 std::vector<Literal>* conflict = trail_->MutableConflict();
202 *conflict = {literal.
Negated()};
208 AddArc(arc.tail, arc.head, literal.
Index());
209 added_arcs_.push_back(arc);
218 processed_.assign(num_nodes_,
false);
219 for (
int n = 0; n < num_nodes_; ++n) {
220 if (processed_[n])
continue;
221 if (next_[n] == n)
continue;
222 if (next_[n] == -1 && prev_[n] == -1)
continue;
226 in_current_path_.assign(num_nodes_,
false);
232 in_current_path_[n] =
true;
233 processed_[n] =
true;
234 while (next_[end_node] != -1) {
235 end_node = next_[end_node];
236 in_current_path_[end_node] =
true;
237 processed_[end_node] =
true;
238 if (end_node == n)
break;
240 while (prev_[start_node] != -1) {
241 start_node = prev_[start_node];
242 in_current_path_[start_node] =
true;
243 processed_[start_node] =
true;
244 if (start_node == n)
break;
249 if (options_.multiple_subcircuit_through_zero) {
251 if (start_node == end_node && !in_current_path_[0]) {
252 FillReasonForPath(start_node, trail_->MutableConflict());
258 if (start_node != end_node && start_node != 0 && end_node != 0) {
259 const auto it = graph_.find({end_node, start_node});
260 if (it == graph_.end())
continue;
261 const Literal literal = it->second;
262 if (assignment_.LiteralIsFalse(literal))
continue;
264 std::vector<Literal>* reason = trail_->GetEmptyVectorToStoreReason();
265 FillReasonForPath(start_node, reason);
266 if (!trail_->EnqueueWithStoredReason(literal.
Negated())) {
280 bool miss_some_nodes =
false;
282 for (
int i = 0;
i < rev_must_be_in_cycle_size_; ++
i) {
283 const int node = must_be_in_cycle_[
i];
284 if (!in_current_path_[node]) {
285 miss_some_nodes =
true;
286 extra_reason = self_arcs_[node];
291 if (miss_some_nodes) {
293 if (start_node == end_node) {
294 FillReasonForPath(start_node, trail_->MutableConflict());
296 trail_->MutableConflict()->push_back(
Literal(extra_reason));
303 if (start_node != end_node) {
304 const auto it = graph_.find({end_node, start_node});
305 if (it == graph_.end())
continue;
306 const Literal literal = it->second;
307 if (assignment_.LiteralIsFalse(literal))
continue;
309 std::vector<Literal>* reason = trail_->GetEmptyVectorToStoreReason();
310 FillReasonForPath(start_node, reason);
312 reason->push_back(
Literal(extra_reason));
314 const bool ok = trail_->EnqueueWithStoredReason(literal.
Negated());
315 if (!ok)
return false;
322 if (start_node != end_node)
continue;
324 for (
int node = 0; node < num_nodes_; ++node) {
325 if (in_current_path_[node])
continue;
326 if (self_arcs_[node] >= 0 &&
327 assignment_.LiteralIsTrue(
Literal(self_arcs_[node]))) {
333 CHECK_EQ(next_[node], -1);
339 assignment_.LiteralIsFalse(
Literal(self_arcs_[node]))) {
340 FillReasonForPath(start_node, trail_->MutableConflict());
342 trail_->MutableConflict()->push_back(
Literal(self_arcs_[node]));
348 const Literal literal(self_arcs_[node]);
350 variable_with_same_reason = literal.
Variable();
351 FillReasonForPath(start_node, trail_->GetEmptyVectorToStoreReason());
352 const bool ok = trail_->EnqueueWithStoredReason(literal);
353 if (!ok)
return false;
355 trail_->EnqueueWithSameReasonAs(literal, variable_with_same_reason);
363 absl::Span<const int> heads,
364 absl::Span<const Literal> literals,
366 : num_nodes_(num_nodes),
367 trail_(model->GetOrCreate<
Trail>()),
369 CHECK(!tails.empty()) <<
"Empty constraint, shouldn't be constructed!";
371 graph_.resize(num_nodes);
372 graph_literals_.resize(num_nodes);
374 const int num_arcs = tails.size();
375 absl::flat_hash_map<LiteralIndex, int> literal_to_watch_index;
376 for (
int arc = 0; arc < num_arcs; ++arc) {
377 const int head = heads[arc];
378 const int tail = tails[arc];
379 const Literal literal = literals[arc];
381 if (assignment_.LiteralIsFalse(literal))
continue;
382 if (assignment_.LiteralIsTrue(literal)) {
384 graph_[tail].push_back(head);
385 graph_literals_[tail].push_back(literal);
390 const auto [it, inserted] = literal_to_watch_index.insert(
391 {literal.
Index(), watch_index_to_literal_.size()});
393 watch_index_to_literal_.push_back(literal);
394 watch_index_to_arcs_.push_back({});
396 watch_index_to_arcs_[it->second].push_back({tail, head});
407 const int id = watcher->
Register(
this);
408 for (
int w = 0;
w < watch_index_to_literal_.size(); ++
w) {
418 if (level == level_ends_.size())
return;
419 if (level > level_ends_.size()) {
420 while (level > level_ends_.size()) {
421 level_ends_.push_back(touched_nodes_.size());
427 for (
int i = level_ends_[level];
i < touched_nodes_.size(); ++
i) {
428 graph_literals_[touched_nodes_[
i]].pop_back();
429 graph_[touched_nodes_[
i]].pop_back();
431 touched_nodes_.resize(level_ends_[level]);
432 level_ends_.resize(level);
436 const std::vector<int>& watch_indices) {
437 for (
const int w : watch_indices) {
438 const Literal literal = watch_index_to_literal_[
w];
439 for (
const auto& [tail, head] : watch_index_to_arcs_[
w]) {
440 graph_[tail].push_back(head);
441 graph_literals_[tail].push_back(literal);
442 touched_nodes_.push_back(tail);
459 for (
const std::vector<int>& compo : components_) {
460 if (compo.size() <= 1)
continue;
468 absl::flat_hash_set<int> nodes(compo.begin(), compo.end());
469 std::vector<Literal>* conflict = trail_->MutableConflict();
471 for (
const int tail : compo) {
472 const int degree = graph_[tail].size();
473 CHECK_EQ(degree, graph_literals_[tail].size());
474 for (
int i = 0;
i < degree; ++
i) {
475 if (nodes.contains(graph_[tail][
i])) {
476 conflict->push_back(graph_literals_[tail][
i].Negated());
487 std::vector<std::vector<Literal>> graph,
488 absl::Span<const int> distinguished_nodes,
Model* model)
489 : graph_(
std::move(graph)),
490 num_nodes_(graph_.size()),
491 trail_(model->GetOrCreate<
Trail>()) {
492 node_is_distinguished_.resize(num_nodes_,
false);
493 for (
const int node : distinguished_nodes) {
494 node_is_distinguished_[node] =
true;
499 const int watcher_id = watcher->
Register(
this);
503 for (
int node1 = 0; node1 < num_nodes_; node1++) {
504 for (
int node2 = 0; node2 < num_nodes_; node2++) {
505 const Literal l = graph_[node1][node2];
506 if (trail_->Assignment().LiteralIsFalse(l))
continue;
507 if (trail_->Assignment().LiteralIsTrue(l)) {
508 fixed_arcs_.emplace_back(node1, node2);
510 watcher->
WatchLiteral(l, watcher_id, watch_index_to_arc_.size());
511 watch_index_to_arc_.emplace_back(node1, node2);
519 if (level == level_ends_.size())
return;
520 if (level > level_ends_.size()) {
521 while (level > level_ends_.size()) {
522 level_ends_.push_back(fixed_arcs_.size());
526 fixed_arcs_.resize(level_ends_[level]);
527 level_ends_.resize(level);
532 const std::vector<int>& watch_indices) {
533 for (
const int w : watch_indices) {
534 const auto& arc = watch_index_to_arc_[
w];
535 fixed_arcs_.push_back(arc);
540void CircuitCoveringPropagator::FillFixedPathInReason(
541 int start,
int end, std::vector<Literal>* reason) {
545 DCHECK_NE(next_[current], -1);
547 reason->push_back(graph_[current][next_[current]].Negated());
548 current = next_[current];
549 }
while (current != end);
554 next_.assign(num_nodes_, -1);
555 prev_.assign(num_nodes_, -1);
556 for (
const auto& arc : fixed_arcs_) {
558 if (next_[arc.first] != -1) {
559 *trail_->MutableConflict() = {
560 graph_[arc.first][next_[arc.first]].Negated(),
561 graph_[arc.first][arc.second].Negated()};
564 next_[arc.first] = arc.second;
566 if (prev_[arc.second] != -1) {
567 *trail_->MutableConflict() = {
568 graph_[prev_[arc.second]][arc.second].Negated(),
569 graph_[arc.first][arc.second].Negated()};
572 prev_[arc.second] = arc.first;
577 visited_.assign(num_nodes_,
false);
578 for (
int node = 0; node < num_nodes_; node++) {
580 if (visited_[node])
continue;
581 if (prev_[node] == -1 && next_[node] == -1)
continue;
582 if (prev_[node] == node)
continue;
586 for (
int current = prev_[node]; current != -1 && current != node;
587 current = prev_[current]) {
593 int distinguished = node_is_distinguished_[start] ? start : -1;
594 int current = next_[start];
596 visited_[start] =
true;
597 while (current != -1 && current != start) {
598 if (node_is_distinguished_[current]) {
599 if (distinguished != -1) {
600 FillFixedPathInReason(distinguished, current,
601 trail_->MutableConflict());
604 distinguished = current;
606 visited_[current] =
true;
608 current = next_[current];
612 if (start == current && distinguished == -1) {
613 FillFixedPathInReason(start, start, trail_->MutableConflict());
618 if (current == -1 && distinguished == -1 &&
619 !trail_->Assignment().LiteralIsFalse(graph_[end][start])) {
620 auto* reason = trail_->GetEmptyVectorToStoreReason();
621 FillFixedPathInReason(start, end, reason);
623 trail_->EnqueueWithStoredReason(graph_[end][start].Negated());
624 if (!ok)
return false;
631 absl::Span<
const std::vector<Literal>> graph) {
632 return [=, graph = std::vector<std::vector<Literal>>(
633 graph.begin(), graph.end())](
Model* model) {
634 const int n = graph.size();
635 std::vector<Literal> exactly_one_constraint;
636 exactly_one_constraint.reserve(n);
637 for (
const bool transpose : {
false,
true}) {
638 for (
int i = 0;
i < n; ++
i) {
639 exactly_one_constraint.clear();
640 for (
int j = 0; j < n; ++j) {
641 exactly_one_constraint.push_back(transpose ? graph[j][
i]
651 absl::Span<const int> heads,
652 absl::Span<const Literal> literals,
Model* model,
653 bool multiple_subcircuit_through_zero) {
654 const int num_arcs = tails.size();
655 CHECK_GT(num_arcs, 0);
656 CHECK_EQ(heads.size(), num_arcs);
657 CHECK_EQ(literals.size(), num_arcs);
664 std::vector<std::vector<Literal>> exactly_one_incoming(num_nodes);
665 std::vector<std::vector<Literal>> exactly_one_outgoing(num_nodes);
666 for (
int arc = 0; arc < num_arcs; arc++) {
667 const int tail = tails[arc];
668 const int head = heads[arc];
669 exactly_one_outgoing[tail].push_back(literals[arc]);
670 exactly_one_incoming[head].push_back(literals[arc]);
672 for (
int i = 0;
i < exactly_one_incoming.size(); ++
i) {
673 if (
i == 0 && multiple_subcircuit_through_zero)
continue;
674 if (!implications->AddAtMostOne(exactly_one_incoming[
i])) {
675 sat_solver->NotifyThatModelIsUnsat();
678 sat_solver->AddProblemClause(exactly_one_incoming[
i]);
679 if (sat_solver->ModelIsUnsat())
return;
681 for (
int i = 0;
i < exactly_one_outgoing.size(); ++
i) {
682 if (
i == 0 && multiple_subcircuit_through_zero)
continue;
683 if (!implications->AddAtMostOne(exactly_one_outgoing[
i])) {
684 sat_solver->NotifyThatModelIsUnsat();
687 sat_solver->AddProblemClause(exactly_one_outgoing[
i]);
688 if (sat_solver->ModelIsUnsat())
return;
700 if (model->
GetOrCreate<SatParameters>()->use_all_different_for_circuit() &&
701 !multiple_subcircuit_through_zero) {
710 absl::Span<
const std::vector<Literal>> graph,
711 absl::Span<const int> distinguished_nodes) {
713 distinguished_nodes = std::vector<int>(distinguished_nodes.begin(),
714 distinguished_nodes.end()),
715 graph = std::vector<std::vector<Literal>>(
716 graph.begin(), graph.end())](
Model* model) {
720 model->TakeOwnership(constraint);
Implementation of AllDifferentAC().
void RegisterWith(GenericLiteralWatcher *watcher)
CircuitCoveringPropagator(std::vector< std::vector< Literal > > graph, absl::Span< const int > distinguished_nodes, Model *model)
void RegisterWith(GenericLiteralWatcher *watcher)
void SetLevel(int level) final
bool IncrementalPropagate(const std::vector< int > &watch_indices) final
void RegisterWith(GenericLiteralWatcher *watcher)
bool IncrementalPropagate(const std::vector< int > &watch_indices) final
void SetLevel(int level) final
CircuitPropagator(int num_nodes, absl::Span< const int > tails, absl::Span< const int > heads, absl::Span< const Literal > literals, Options options, Model *model)
void RegisterReversibleInt(int id, int *rev)
void NotifyThatPropagatorMayNotReachFixedPointInOnePass(int id)
void WatchLiteral(Literal l, int id, int watch_index=-1)
void RegisterReversibleClass(int id, ReversibleInterface *rev)
int Register(PropagatorInterface *propagator)
Registers a propagator and returns its unique ids.
LiteralIndex Index() const
BooleanVariable Variable() const
bool IncrementalPropagate(const std::vector< int > &watch_indices) final
NoCyclePropagator(int num_nodes, absl::Span< const int > tails, absl::Span< const int > heads, absl::Span< const Literal > literals, Model *model)
void SetLevel(int level) final
const VariablesAssignment & Assignment() const
bool LiteralIsTrue(Literal literal) const
const LiteralIndex kNoLiteralIndex(-1)
void LoadSubcircuitConstraint(int num_nodes, absl::Span< const int > tails, absl::Span< const int > heads, absl::Span< const Literal > literals, Model *model, bool multiple_subcircuit_through_zero)
std::function< void(Model *)> CircuitCovering(absl::Span< const std::vector< Literal > > graph, absl::Span< const int > distinguished_nodes)
const LiteralIndex kFalseLiteralIndex(-3)
std::function< void(Model *)> ExactlyOneConstraint(absl::Span< const Literal > literals)
std::function< void(Model *)> ExactlyOnePerRowAndPerColumn(absl::Span< const std::vector< Literal > > graph)
const BooleanVariable kNoBooleanVariable(-1)
In SWIG mode, we don't want anything besides these top-level includes.
trees with all degrees equal w the current value of w
void FindStronglyConnectedComponents(NodeIndex num_nodes, const Graph &graph, SccOutput *components)
Simple wrapper function for most usage.
bool multiple_subcircuit_through_zero