22 #include "absl/container/btree_set.h"
23 #include "absl/container/inlined_vector.h"
24 #include "absl/types/span.h"
45 void AppendLowerBoundReasonIfValid(IntegerVariable
var,
46 const IntegerTrail& i_trail,
47 std::vector<IntegerLiteral>* reason) {
49 reason->push_back(i_trail.LowerBoundAsLiteral(
var));
57 if (shared_stats_ ==
nullptr)
return;
58 std::vector<std::pair<std::string, int64_t>> stats;
59 stats.push_back({
"precedences/num_cycles", num_cycles_});
60 stats.push_back({
"precedences/num_pushes", num_pushes_});
62 {
"precedences/num_enforcement_pushes", num_enforcement_pushes_});
69 while (propagation_trail_index_ < trail_->
Index()) {
71 if (
literal.Index() >= literal_to_new_impacted_arcs_.
size())
continue;
76 literal_to_new_impacted_arcs_[
literal.Index()]) {
77 if (--arc_counts_[arc_index] == 0) {
78 const ArcInfo&
arc = arcs_[arc_index];
86 literal_to_new_impacted_arcs_[
literal.Index()]) {
87 if (arc_counts_[arc_index] > 0)
continue;
88 const ArcInfo&
arc = arcs_[arc_index];
90 const IntegerValue new_head_lb =
93 if (!EnqueueAndCheck(
arc, new_head_lb, trail_))
return false;
99 InitializeBFQueueWithModifiedNodes();
100 if (!BellmanFordTarjan(trail_))
return false;
110 DCHECK(NoPropagationLeft(*trail_));
114 PropagateOptionalArcs(trail_);
123 if (
var >= impacted_arcs_.
size())
return true;
124 for (
const ArcIndex arc_index : impacted_arcs_[
var]) {
125 const ArcInfo&
arc = arcs_[arc_index];
127 const IntegerValue new_head_lb =
129 if (new_head_lb > integer_trail_->
LowerBound(
arc.head_var)) {
130 if (!EnqueueAndCheck(
arc, new_head_lb, trail_))
return false;
145 if (
literal.Index() >= literal_to_new_impacted_arcs_.
size())
continue;
147 literal_to_new_impacted_arcs_[
literal.Index()]) {
148 if (arc_counts_[arc_index]++ == 0) {
149 const ArcInfo&
arc = arcs_[arc_index];
161 const std::vector<IntegerVariable>& vars,
162 std::vector<IntegerPrecedences>* output) {
163 tmp_sorted_vars_.clear();
164 tmp_precedences_.clear();
166 const IntegerVariable
var = vars[
index];
168 if (
var >= impacted_arcs_.
size())
continue;
169 for (
const ArcIndex arc_index : impacted_arcs_[
var]) {
170 const ArcInfo&
arc = arcs_[arc_index];
173 IntegerValue offset =
arc.offset;
182 if (offset < 0)
continue;
184 if (var_to_degree_[
arc.head_var] == 0) {
185 tmp_sorted_vars_.push_back(
192 if (var_to_last_index_[
arc.head_var] ==
index)
continue;
194 var_to_last_index_[
arc.head_var] =
index;
195 var_to_degree_[
arc.head_var]++;
196 tmp_precedences_.push_back(
197 {
index,
arc.head_var, arc_index.value(), offset});
208 std::sort(tmp_sorted_vars_.begin(), tmp_sorted_vars_.end());
214 for (
const SortedVar pair : tmp_sorted_vars_) {
215 const int degree = var_to_degree_[pair.var];
217 var_to_degree_[pair.var] =
start;
221 var_to_degree_[pair.var] = -1;
226 if (var_to_degree_[precedence.var] < 0)
continue;
227 (*output)[var_to_degree_[precedence.var]++] = precedence;
232 for (
const SortedVar pair : tmp_sorted_vars_) {
233 var_to_degree_[pair.var] = 0;
238 bool call_compute_precedences,
const std::vector<IntegerVariable>& vars,
239 std::vector<FullIntegerPrecedence>* output) {
243 if (call_compute_precedences) {
244 std::vector<PrecedencesPropagator::IntegerPrecedences> before;
248 const int size = before.size();
249 for (
int i = 0; i < size;) {
251 data.
var = before[i].var;
252 const IntegerVariable
var = before[i].var;
254 for (; i < size && before[i].var ==
var; ++i) {
256 data.
offsets.push_back(before[i].offset);
258 output->push_back(std::move(data));
273 for (
const auto& arcs : impacted_arcs_) {
274 for (
const ArcIndex arc_index : arcs) {
275 const ArcInfo&
arc = arcs_[arc_index];
276 if (
arc.tail_var ==
arc.head_var)
continue;
282 bool graph_has_cycle =
false;
283 std::vector<IntegerVariable> topological_order;
284 while (sorter.
GetNext(&
next, &graph_has_cycle,
nullptr)) {
285 topological_order.push_back(IntegerVariable(
next));
286 if (graph_has_cycle)
return;
294 absl::flat_hash_set<IntegerVariable> is_interesting;
295 absl::flat_hash_set<IntegerVariable> to_consider(vars.begin(), vars.end());
296 absl::flat_hash_map<IntegerVariable,
297 absl::flat_hash_map<IntegerVariable, IntegerValue>>
298 vars_before_with_offset;
299 absl::flat_hash_map<IntegerVariable, IntegerValue> tail_map;
300 for (
const IntegerVariable tail_var : topological_order) {
301 if (!to_consider.contains(tail_var) &&
302 !vars_before_with_offset.contains(tail_var)) {
307 if (tail_var >= impacted_arcs_.size())
continue;
313 const auto it = vars_before_with_offset.find(tail_var);
314 if (it != vars_before_with_offset.end()) {
315 tail_map = it->second;
319 for (
const ArcIndex arc_index : impacted_arcs_[tail_var]) {
320 const ArcInfo&
arc = arcs_[arc_index];
321 if (
arc.tail_var ==
arc.head_var)
continue;
323 CHECK_EQ(
arc.tail_var, tail_var);
326 if (tail_map.empty() && !to_consider.contains(tail_var))
continue;
328 IntegerValue arc_offset =
arc.offset;
333 auto& to_update = vars_before_with_offset[
arc.head_var];
334 for (
const auto& [var_before, offset] : tail_map) {
335 if (!to_update.contains(var_before)) {
336 to_update[var_before] = arc_offset + offset;
338 to_update[var_before] =
339 std::max(arc_offset + offset, to_update[var_before]);
342 if (to_consider.contains(tail_var)) {
343 if (!to_update.contains(tail_var)) {
344 to_update[tail_var] = arc_offset;
346 to_update[tail_var] =
std::max(arc_offset, to_update[tail_var]);
354 if (to_update.size() > tail_map.size() + 1) {
355 is_interesting.insert(
arc.head_var);
357 is_interesting.erase(
arc.head_var);
365 if (!is_interesting.contains(tail_var))
continue;
366 if (tail_map.size() == 1)
continue;
371 for (
int i = 0; i < vars.size(); ++i) {
372 const auto offset_it = tail_map.find(vars[i]);
373 if (offset_it == tail_map.end())
continue;
375 data.
offsets.push_back(offset_it->second);
378 output->push_back(std::move(data));
383 int arc_index, IntegerValue min_offset,
384 std::vector<Literal>* literal_reason,
385 std::vector<IntegerLiteral>* integer_reason)
const {
387 for (
const Literal l :
arc.presence_literals) {
393 arc.offset_var, min_offset -
arc.offset));
397 void PrecedencesPropagator::AdjustSizeFor(IntegerVariable i) {
412 void PrecedencesPropagator::AddArc(
413 IntegerVariable
tail, IntegerVariable
head, IntegerValue offset,
414 IntegerVariable offset_var, absl::Span<const Literal> presence_literals) {
421 absl::InlinedVector<Literal, 6> enforcement_literals;
423 for (
const Literal l : presence_literals) {
424 enforcement_literals.push_back(l);
427 enforcement_literals.push_back(
431 enforcement_literals.push_back(
436 enforcement_literals.push_back(
441 for (
const Literal l : enforcement_literals) {
447 enforcement_literals[new_size++] = l;
449 enforcement_literals.resize(new_size);
456 VLOG(1) <<
"Self arc! This could be presolved. "
457 <<
"var:" <<
tail <<
" offset:" << offset
458 <<
" offset_var:" << offset_var
459 <<
" conditioned_by:" << presence_literals;
465 const IntegerValue lb = integer_trail_->
LowerBound(offset_var);
466 if (lb == integer_trail_->
UpperBound(offset_var)) {
473 if (!enforcement_literals.empty()) {
474 const OptionalArcIndex arc_index(potential_arcs_.
size());
476 {
tail,
head, offset, offset_var, enforcement_literals});
480 impacted_potential_arcs_[offset_var].
push_back(arc_index);
486 IntegerVariable tail_var;
487 IntegerVariable head_var;
488 IntegerVariable offset_var;
490 std::vector<InternalArc> to_add;
498 to_add.push_back({
tail,
head, offset_var});
499 to_add.push_back({offset_var,
head,
tail});
507 for (
const InternalArc
a : to_add) {
522 modified_vars_.
Set(
a.tail_var);
528 {
a.tail_var,
a.head_var, offset,
a.offset_var, enforcement_literals});
529 auto& presence_literals = arcs_.
back().presence_literals;
533 const Literal to_remove =
535 const auto it = std::find(presence_literals.begin(),
536 presence_literals.end(), to_remove);
537 if (it != presence_literals.end()) presence_literals.erase(it);
540 if (presence_literals.empty()) {
541 impacted_arcs_[
a.tail_var].
push_back(arc_index);
543 for (
const Literal l : presence_literals) {
544 if (l.Index() >= literal_to_new_impacted_arcs_.
size()) {
545 literal_to_new_impacted_arcs_.
resize(l.Index().value() + 1);
547 literal_to_new_impacted_arcs_[l.Index()].
push_back(arc_index);
550 arc_counts_.
push_back(presence_literals.size());
559 void PrecedencesPropagator::PropagateOptionalArcs(Trail* trail) {
562 if (
var >= impacted_potential_arcs_.
size())
continue;
566 for (
const OptionalArcIndex arc_index : impacted_potential_arcs_[
var]) {
567 const ArcInfo&
arc = potential_arcs_[arc_index];
568 int num_not_true = 0;
569 Literal to_propagate;
570 for (
const Literal l :
arc.presence_literals) {
571 if (!trail->Assignment().LiteralIsTrue(l)) {
576 if (num_not_true != 1)
continue;
577 if (trail->Assignment().LiteralIsFalse(to_propagate))
continue;
581 const IntegerValue tail_lb = integer_trail_->
LowerBound(
arc.tail_var);
582 const IntegerValue head_ub = integer_trail_->
UpperBound(
arc.head_var);
583 if (tail_lb + ArcOffset(
arc) > head_ub) {
584 integer_reason_.clear();
585 integer_reason_.push_back(
587 integer_reason_.push_back(
589 AppendLowerBoundReasonIfValid(
arc.offset_var, *integer_trail_,
591 literal_reason_.clear();
592 for (
const Literal l :
arc.presence_literals) {
593 if (l != to_propagate) literal_reason_.push_back(l.Negated());
595 ++num_enforcement_pushes_;
596 integer_trail_->
EnqueueLiteral(to_propagate.Negated(), literal_reason_,
603 IntegerValue PrecedencesPropagator::ArcOffset(
const ArcInfo&
arc)
const {
609 bool PrecedencesPropagator::EnqueueAndCheck(
const ArcInfo&
arc,
610 IntegerValue new_head_lb,
613 DCHECK_GT(new_head_lb, integer_trail_->
LowerBound(
arc.head_var));
620 literal_reason_.clear();
621 for (
const Literal l :
arc.presence_literals) {
622 literal_reason_.push_back(l.Negated());
625 integer_reason_.clear();
627 AppendLowerBoundReasonIfValid(
arc.offset_var, *integer_trail_,
638 if (new_head_lb > integer_trail_->
UpperBound(
arc.head_var)) {
639 const IntegerValue slack =
641 integer_reason_.push_back(
643 std::vector<IntegerValue> coeffs(integer_reason_.size(), IntegerValue(1));
647 return integer_trail_->
ReportConflict(literal_reason_, integer_reason_);
651 if (trail->Assignment().LiteralIsFalse(l)) {
652 literal_reason_.push_back(l);
653 return integer_trail_->
ReportConflict(literal_reason_, integer_reason_);
655 integer_trail_->
EnqueueLiteral(l, literal_reason_, integer_reason_);
661 return integer_trail_->
Enqueue(
663 literal_reason_, integer_reason_);
666 bool PrecedencesPropagator::NoPropagationLeft(
const Trail& trail)
const {
667 const int num_nodes = impacted_arcs_.
size();
668 for (IntegerVariable
var(0);
var < num_nodes; ++
var) {
669 for (
const ArcIndex arc_index : impacted_arcs_[
var]) {
670 const ArcInfo&
arc = arcs_[arc_index];
681 void PrecedencesPropagator::InitializeBFQueueWithModifiedNodes() {
684 const int num_nodes = impacted_arcs_.
size();
685 bf_in_queue_.resize(num_nodes,
false);
686 for (
const int node : bf_queue_) bf_in_queue_[node] =
false;
688 DCHECK(std::none_of(bf_in_queue_.begin(), bf_in_queue_.end(),
689 [](
bool v) { return v; }));
691 if (
var >= num_nodes)
continue;
692 bf_queue_.push_back(
var.value());
693 bf_in_queue_[
var.value()] =
true;
697 void PrecedencesPropagator::CleanUpMarkedArcsAndParents() {
700 const int num_nodes = impacted_arcs_.
size();
702 if (
var >= num_nodes)
continue;
703 const ArcIndex parent_arc_index = bf_parent_arc_of_[
var.value()];
704 if (parent_arc_index != -1) {
705 arcs_[parent_arc_index].is_marked =
false;
706 bf_parent_arc_of_[
var.value()] = -1;
707 bf_can_be_skipped_[
var.value()] =
false;
710 DCHECK(std::none_of(bf_parent_arc_of_.begin(), bf_parent_arc_of_.end(),
711 [](
ArcIndex v) { return v != -1; }));
712 DCHECK(std::none_of(bf_can_be_skipped_.begin(), bf_can_be_skipped_.end(),
713 [](
bool v) { return v; }));
716 bool PrecedencesPropagator::DisassembleSubtree(
717 int source,
int target, std::vector<bool>* can_be_skipped) {
721 tmp_vector_.push_back(source);
722 while (!tmp_vector_.empty()) {
723 const int tail = tmp_vector_.back();
724 tmp_vector_.pop_back();
725 for (
const ArcIndex arc_index : impacted_arcs_[IntegerVariable(
tail)]) {
726 const ArcInfo&
arc = arcs_[arc_index];
728 arc.is_marked =
false;
729 if (
arc.head_var.value() == target)
return true;
730 DCHECK(!(*can_be_skipped)[
arc.head_var.value()]);
731 (*can_be_skipped)[
arc.head_var.value()] =
true;
732 tmp_vector_.push_back(
arc.head_var.value());
739 void PrecedencesPropagator::AnalyzePositiveCycle(
740 ArcIndex first_arc, Trail* trail, std::vector<Literal>* must_be_all_true,
741 std::vector<Literal>* literal_reason,
742 std::vector<IntegerLiteral>* integer_reason) {
743 must_be_all_true->clear();
744 literal_reason->clear();
745 integer_reason->clear();
748 const IntegerVariable first_arc_head = arcs_[first_arc].head_var;
750 std::vector<ArcIndex> arc_on_cycle;
756 const int num_nodes = impacted_arcs_.
size();
757 while (arc_on_cycle.size() <= num_nodes) {
758 arc_on_cycle.push_back(arc_index);
759 const ArcInfo&
arc = arcs_[arc_index];
760 if (
arc.tail_var == first_arc_head)
break;
761 arc_index = bf_parent_arc_of_[
arc.tail_var.value()];
764 CHECK_NE(arc_on_cycle.size(), num_nodes + 1) <<
"Infinite loop.";
768 for (
const ArcIndex arc_index : arc_on_cycle) {
769 const ArcInfo&
arc = arcs_[arc_index];
770 sum += ArcOffset(
arc);
771 AppendLowerBoundReasonIfValid(
arc.offset_var, *integer_trail_,
773 for (
const Literal l :
arc.presence_literals) {
774 literal_reason->push_back(l.Negated());
783 must_be_all_true->push_back(
798 bool PrecedencesPropagator::BellmanFordTarjan(Trail* trail) {
799 const int num_nodes = impacted_arcs_.
size();
802 bf_can_be_skipped_.resize(num_nodes,
false);
803 bf_parent_arc_of_.resize(num_nodes,
ArcIndex(-1));
808 while (!bf_queue_.empty()) {
809 const int node = bf_queue_.front();
810 bf_queue_.pop_front();
811 bf_in_queue_[node] =
false;
821 if (bf_can_be_skipped_[node]) {
822 DCHECK_NE(bf_parent_arc_of_[node], -1);
823 DCHECK(!arcs_[bf_parent_arc_of_[node]].is_marked);
827 const IntegerValue tail_lb =
828 integer_trail_->
LowerBound(IntegerVariable(node));
829 for (
const ArcIndex arc_index : impacted_arcs_[IntegerVariable(node)]) {
830 const ArcInfo&
arc = arcs_[arc_index];
831 DCHECK_EQ(
arc.tail_var, node);
832 const IntegerValue candidate = tail_lb + ArcOffset(
arc);
835 if (!EnqueueAndCheck(
arc, candidate, trail))
return false;
843 if (DisassembleSubtree(
arc.head_var.value(),
arc.tail_var.value(),
844 &bf_can_be_skipped_)) {
845 std::vector<Literal> must_be_all_true;
846 AnalyzePositiveCycle(arc_index, trail, &must_be_all_true,
847 &literal_reason_, &integer_reason_);
848 if (must_be_all_true.empty()) {
854 for (
const Literal l : must_be_all_true) {
856 literal_reason_.push_back(l);
861 for (
const Literal l : must_be_all_true) {
876 if (bf_parent_arc_of_[
arc.head_var.value()] != -1) {
877 arcs_[bf_parent_arc_of_[
arc.head_var.value()]].is_marked =
false;
886 const IntegerValue new_bound = integer_trail_->
LowerBound(
arc.head_var);
887 if (new_bound == candidate) {
888 bf_parent_arc_of_[
arc.head_var.value()] = arc_index;
889 arcs_[arc_index].is_marked =
true;
893 bf_parent_arc_of_[
arc.head_var.value()] = -1;
898 bf_can_be_skipped_[
arc.head_var.value()] =
false;
899 if (!bf_in_queue_[
arc.head_var.value()] && new_bound >= candidate) {
900 bf_queue_.push_back(
arc.head_var.value());
901 bf_in_queue_[
arc.head_var.value()] =
true;
909 int PrecedencesPropagator::AddGreaterThanAtLeastOneOfConstraintsFromClause(
910 const absl::Span<const Literal> clause, Model*
model) {
911 CHECK_EQ(
model->GetOrCreate<Trail>()->CurrentDecisionLevel(), 0);
912 if (clause.size() < 2)
return 0;
915 std::vector<ArcInfo> infos;
916 for (
const Literal l : clause) {
917 if (l.Index() >= literal_to_new_impacted_arcs_.
size())
continue;
918 for (
const ArcIndex arc_index : literal_to_new_impacted_arcs_[l.Index()]) {
919 const ArcInfo&
arc = arcs_[arc_index];
920 if (
arc.presence_literals.size() != 1)
continue;
927 if (infos.size() <= 1)
return 0;
931 std::stable_sort(infos.begin(), infos.end(),
932 [](
const ArcInfo&
a,
const ArcInfo&
b) {
933 return a.head_var < b.head_var;
937 int num_added_constraints = 0;
938 auto* solver =
model->GetOrCreate<SatSolver>();
939 for (
int i = 0; i < infos.size();) {
941 const IntegerVariable head_var = infos[
start].head_var;
942 for (i++; i < infos.size() && infos[i].head_var == head_var; ++i) {
944 const absl::Span<ArcInfo> arcs(&infos[
start], i -
start);
947 if (arcs.size() < 2)
continue;
952 if (arcs.size() + 1 < clause.size())
continue;
954 std::vector<IntegerVariable> vars;
955 std::vector<IntegerValue> offsets;
956 std::vector<Literal> selectors;
957 std::vector<Literal> enforcements;
960 for (
const Literal l : clause) {
962 for (; j < arcs.size() && l == arcs[j].presence_literals.front(); ++j) {
964 vars.push_back(arcs[j].tail_var);
965 offsets.push_back(arcs[j].offset);
972 selectors.push_back(l);
975 enforcements.push_back(l.Negated());
981 if (enforcements.size() + 1 == clause.size())
continue;
983 ++num_added_constraints;
986 if (!solver->FinishPropagation())
return num_added_constraints;
988 return num_added_constraints;
991 int PrecedencesPropagator::
992 AddGreaterThanAtLeastOneOfConstraintsWithClauseAutoDetection(Model*
model) {
994 auto* solver =
model->GetOrCreate<SatSolver>();
998 for (
ArcIndex arc_index(0); arc_index < arcs_.
size(); ++arc_index) {
999 const ArcInfo&
arc = arcs_[arc_index];
1003 if (
arc.tail_var ==
arc.head_var)
continue;
1004 if (
arc.presence_literals.size() != 1)
continue;
1006 if (
arc.head_var >= incoming_arcs_.size()) {
1007 incoming_arcs_.
resize(
arc.head_var.value() + 1);
1009 incoming_arcs_[
arc.head_var].push_back(arc_index);
1012 int num_added_constraints = 0;
1013 for (IntegerVariable target(0); target < incoming_arcs_.size(); ++target) {
1014 if (incoming_arcs_[target].size() <= 1)
continue;
1015 if (
time_limit->LimitReached())
return num_added_constraints;
1020 solver->Backtrack(0);
1021 if (solver->ModelIsUnsat())
return num_added_constraints;
1022 std::vector<Literal> clause;
1023 for (
const ArcIndex arc_index : incoming_arcs_[target]) {
1024 const Literal
literal = arcs_[arc_index].presence_literals.
front();
1025 if (solver->Assignment().LiteralIsFalse(
literal))
continue;
1027 solver->EnqueueDecisionAndBacktrackOnConflict(
literal.Negated());
1030 clause = solver->GetLastIncompatibleDecisions();
1034 solver->Backtrack(0);
1036 if (clause.size() > 1) {
1038 const absl::btree_set<Literal> clause_set(clause.begin(), clause.end());
1039 std::vector<ArcIndex> arcs_in_clause;
1040 for (
const ArcIndex arc_index : incoming_arcs_[target]) {
1041 const Literal
literal(arcs_[arc_index].presence_literals.front());
1042 if (clause_set.contains(
literal.Negated())) {
1043 arcs_in_clause.push_back(arc_index);
1047 VLOG(2) << arcs_in_clause.size() <<
"/" << incoming_arcs_[target].size();
1049 ++num_added_constraints;
1050 std::vector<IntegerVariable> vars;
1051 std::vector<IntegerValue> offsets;
1052 std::vector<Literal> selectors;
1053 for (
const ArcIndex a : arcs_in_clause) {
1054 vars.push_back(arcs_[
a].tail_var);
1055 offsets.push_back(arcs_[
a].offset);
1056 selectors.push_back(Literal(arcs_[
a].presence_literals.front()));
1059 if (!solver->FinishPropagation())
return num_added_constraints;
1063 return num_added_constraints;
1067 VLOG(1) <<
"Detecting GreaterThanAtLeastOneOf() constraints...";
1071 int num_added_constraints = 0;
1079 if (
clauses->AllClausesInCreationOrder().size() < 1e6) {
1088 if (
time_limit->LimitReached())
return num_added_constraints;
1089 if (solver->ModelIsUnsat())
return num_added_constraints;
1090 num_added_constraints += AddGreaterThanAtLeastOneOfConstraintsFromClause(
1091 clause->AsSpan(),
model);
1098 const int num_booleans = solver->NumVariables();
1099 if (num_booleans < 1e6) {
1100 for (
int i = 0; i < num_booleans; ++i) {
1101 if (
time_limit->LimitReached())
return num_added_constraints;
1102 if (solver->ModelIsUnsat())
return num_added_constraints;
1103 num_added_constraints +=
1104 AddGreaterThanAtLeastOneOfConstraintsFromClause(
1105 {
Literal(BooleanVariable(i),
true),
1106 Literal(BooleanVariable(i),
false)},
1112 num_added_constraints +=
1113 AddGreaterThanAtLeastOneOfConstraintsWithClauseAutoDetection(
model);
1116 VLOG(1) <<
"Added " << num_added_constraints
1117 <<
" GreaterThanAtLeastOneOf() constraints.";
1118 return num_added_constraints;
void resize(size_type new_size)
void push_back(const value_type &x)
const std::vector< IntegerType > & PositionsSetAtLeastOnce() const
void Set(IntegerType index)
void ClearAndResize(IntegerType size)
A simple class to enforce both an elapsed time limit and a deterministic time limit in the same threa...
void WatchLowerBound(IntegerVariable var, int id, int watch_index=-1)
ABSL_MUST_USE_RESULT bool Enqueue(IntegerLiteral i_lit, absl::Span< const Literal > literal_reason, absl::Span< const IntegerLiteral > integer_reason)
bool IsCurrentlyIgnored(IntegerVariable i) const
IntegerLiteral LowerBoundAsLiteral(IntegerVariable i) const
bool ReportConflict(absl::Span< const Literal > literal_reason, absl::Span< const IntegerLiteral > integer_reason)
void EnqueueLiteral(Literal literal, absl::Span< const Literal > literal_reason, absl::Span< const IntegerLiteral > integer_reason)
IntegerValue UpperBound(IntegerVariable i) const
void RelaxLinearReason(IntegerValue slack, absl::Span< const IntegerValue > coeffs, std::vector< IntegerLiteral > *reason) const
IntegerValue LowerBound(IntegerVariable i) const
IntegerLiteral UpperBoundAsLiteral(IntegerVariable i) const
Literal IsIgnoredLiteral(IntegerVariable i) const
bool IsOptional(IntegerVariable i) const
IntegerVariable NumIntegerVariables() const
Class that owns everything related to a particular optimization model.
void AddPrecedenceReason(int arc_index, IntegerValue min_offset, std::vector< Literal > *literal_reason, std::vector< IntegerLiteral > *integer_reason) const
void ComputeFullPrecedences(bool call_compute_precedences, const std::vector< IntegerVariable > &vars, std::vector< FullIntegerPrecedence > *output)
~PrecedencesPropagator() override
void ComputePrecedences(const std::vector< IntegerVariable > &vars, std::vector< IntegerPrecedences > *output)
int AddGreaterThanAtLeastOneOfConstraints(Model *model)
void Untrail(const Trail &trail, int trail_index) final
bool PropagateOutgoingArcs(IntegerVariable var)
int propagation_trail_index_
void AddStats(absl::Span< const std::pair< std::string, int64_t >> stats)
const VariablesAssignment & Assignment() const
int CurrentDecisionLevel() const
bool LiteralIsTrue(Literal literal) const
bool LiteralIsFalse(Literal literal) const
void AddEdge(int from, int to)
bool GetNext(int *next_node_index, bool *cyclic, std::vector< int > *output_cycle_nodes=nullptr)
SharedClausesManager * clauses
ModelSharedTimeLimit * time_limit
absl::Cleanup< absl::decay_t< Callback > > MakeCleanup(Callback &&callback)
void STLSortAndRemoveDuplicates(T *v, const LessFunc &less_func)
constexpr IntegerValue kMaxIntegerValue(std::numeric_limits< IntegerValue::ValueType >::max() - 1)
std::function< void(Model *)> GreaterThanAtLeastOneOf(IntegerVariable target_var, const absl::Span< const IntegerVariable > vars, const absl::Span< const IntegerValue > offsets, const absl::Span< const Literal > selectors)
const IntegerVariable kNoIntegerVariable(-1)
std::vector< IntegerVariable > NegationOf(const std::vector< IntegerVariable > &vars)
std::function< int64_t(const Model &)> LowerBound(IntegerVariable v)
Collection of objects used to extend the Constraint Solver library.
static IntegerLiteral GreaterOrEqual(IntegerVariable i, IntegerValue bound)
std::vector< int > indices
std::vector< IntegerValue > offsets
#define VLOG(verboselevel)
#define VLOG_IS_ON(verboselevel)