28 CHECK_GE(n, pos_.size());
29 CHECK_LE(left_, right_);
31 tmp_positions_.resize(n, 0);
34 queue_.resize(n + 1, 0);
39 const int id = queue_[left_];
42 if (left_ == queue_.size()) left_ = 0;
48 DCHECK_LE(
id, pos_.size());
53 if (right_ == queue_.size()) right_ = 0;
57 if (order.size() <= 1)
return;
60 const int size = left_ < right_ ? right_ - left_ : left_ +
capacity - right_;
61 if (order.size() > size / 8) {
66 for (
const int id : order) {
67 const int p = pos_[id];
71 std::sort(&tmp_positions_[0], &tmp_positions_[
index]);
72 DCHECK(std::unique(&tmp_positions_[0], &tmp_positions_[
index]) ==
73 &tmp_positions_[
index]);
76 for (
const int id : order) {
77 int p = tmp_positions_[
index++];
85 for (
const int id : order) {
86 DCHECK_GE(pos_[
id], 0);
87 queue_[pos_[id]] = -1;
90 if (left_ <= right_) {
91 for (
int i = left_; i < right_; ++i) {
92 if (queue_[i] == -1) {
93 queue_[i] = order[order_index++];
98 const int size = queue_.size();
99 for (
int i = left_; i < size; ++i) {
100 if (queue_[i] == -1) {
101 queue_[i] = order[order_index++];
105 for (
int i = 0; i < left_; ++i) {
106 if (queue_[i] == -1) {
107 queue_[i] = order[order_index++];
112 DCHECK_EQ(order_index, order.size());
116 std::sort(elements.begin(), elements.end(),
117 [
this](
const int id1,
const int id2) {
118 const int p1 = pos_[id1];
119 const int p2 = pos_[id2];
121 if (p2 >= left_) return p1 < p2;
125 if (p2 < left_) return p1 < p2;
137 os <<
"CANNOT_PROPAGATE";
140 os <<
"CAN_PROPAGATE";
167 if (
literal.Index() >=
static_cast<int>(watcher_.
size()))
continue;
170 auto& watch_list = watcher_[
literal.Index()];
171 for (
const EnforcementId
id : watch_list) {
172 const LiteralIndex
index = ProcessIdOnTrue(
literal,
id);
175 watch_list[new_size++] = id;
182 watch_list.resize(new_size);
185 for (
const EnforcementId
id : watcher_[
literal.NegatedIndex()]) {
189 rev_stack_size_ =
static_cast<int>(untrail_stack_.size());
195 const int size =
static_cast<int>(untrail_stack_.size());
196 for (
int i = size - 1; i >= rev_stack_size_; --i) {
197 const auto [id,
status] = untrail_stack_[i];
199 if (callbacks_[
id] !=
nullptr) callbacks_[id](
status);
201 untrail_stack_.resize(rev_stack_size_);
211 absl::Span<const Literal> enforcement,
216 temp_literals_.clear();
217 for (
const Literal l : enforcement) {
219 const int size =
std::max(l.Index().value(), l.NegatedIndex().value()) + 1;
220 if (size >
static_cast<int>(watcher_.
size())) {
231 temp_literals_.push_back(l);
238 return EnforcementId(-1);
240 if (num_true == enforcement.size()) {
242 return EnforcementId(-1);
245 const EnforcementId id(
static_cast<int>(callbacks_.
size()));
248 CHECK(!temp_literals_.empty());
249 buffer_.insert(buffer_.end(), temp_literals_.begin(), temp_literals_.end());
253 if (temp_literals_.size() == 1) {
254 watcher_[temp_literals_[0].Index()].
push_back(
id);
257 watcher_[temp_literals_[0].Index()].
push_back(
id);
258 watcher_[temp_literals_[1].Index()].
push_back(
id);
265 EnforcementId
id, std::vector<Literal>* reason)
const {
266 for (
const Literal l : GetSpan(
id)) {
267 reason->push_back(l.Negated());
274 EnforcementId
id, absl::Span<const Literal> literal_reason,
275 absl::Span<const IntegerLiteral> integer_reason) {
276 temp_reason_.clear();
278 for (
const Literal l : GetSpan(
id)) {
281 temp_reason_.push_back(l.Negated());
285 unique_unassigned = l.Index();
288 temp_reason_.insert(temp_reason_.end(), literal_reason.begin(),
289 literal_reason.end());
291 return integer_trail_->
ReportConflict(temp_reason_, integer_reason);
295 temp_reason_, integer_reason);
299 absl::Span<Literal> EnforcementPropagator::GetSpan(EnforcementId
id) {
300 if (
id < 0)
return {};
301 DCHECK_LE(
id + 1, starts_.
size());
302 const int size = starts_[
id + 1] - starts_[id];
304 return absl::MakeSpan(&buffer_[starts_[
id]], size);
307 absl::Span<const Literal> EnforcementPropagator::GetSpan(
308 EnforcementId
id)
const {
309 if (
id < 0)
return {};
310 DCHECK_LE(
id + 1, starts_.
size());
311 const int size = starts_[
id + 1] - starts_[id];
313 return absl::MakeSpan(&buffer_[starts_[
id]], size);
316 LiteralIndex EnforcementPropagator::ProcessIdOnTrue(Literal watched,
321 const auto span = GetSpan(
id);
322 if (span.size() == 1) {
328 const int watched_pos = (span[0] == watched) ? 0 : 1;
329 CHECK_EQ(span[watched_pos], watched);
335 for (
int i = 2; i < span.size(); ++i) {
336 const Literal l = span[i];
345 return span[watched_pos].Index();
362 void EnforcementPropagator::ChangeStatus(EnforcementId
id,
365 if (old_status == new_status)
return;
367 untrail_stack_.push_back({id, old_status});
369 statuses_[id] = new_status;
370 if (callbacks_[
id] !=
nullptr) callbacks_[id](new_status);
380 rev_integer_value_repository_(
383 watcher_id_(watcher_->Register(this)) {
396 if (shared_stats_ ==
nullptr)
return;
397 std::vector<std::pair<std::string, int64_t>> stats;
398 stats.push_back({
"linear_propag/num_pushes", num_pushes_});
400 {
"linear_propag/num_enforcement_pushes", num_enforcement_pushes_});
401 stats.push_back({
"linear_propag/num_simple_cycles", num_simple_cycles_});
402 stats.push_back({
"linear_propag/num_complex_cycles", num_complex_cycles_});
403 stats.push_back({
"linear_propag/num_scanned", num_scanned_});
404 stats.push_back({
"linear_propag/num_extra_scan", num_extra_scans_});
405 stats.push_back({
"linear_propag/num_explored_in_disassemble",
406 num_explored_in_disassemble_});
407 stats.push_back({
"linear_propag/num_bool_aborts", num_bool_aborts_});
408 stats.push_back({
"linear_propag/num_ignored", num_ignored_});
409 stats.push_back({
"linear_propag/num_reordered", num_reordered_});
414 if (level < previous_level_) {
418 while (!propagation_queue_.
empty()) {
419 in_queue_[propagation_queue_.
Pop()] =
false;
421 for (
int i = rev_at_false_size_; i < in_queue_and_at_false_.size(); ++i) {
422 in_queue_[in_queue_and_at_false_[i]] =
false;
424 in_queue_and_at_false_.resize(rev_at_false_size_);
425 }
else if (level > previous_level_) {
426 rev_at_false_size_ = in_queue_and_at_false_.size();
427 rev_int_repository_->
SaveState(&rev_at_false_size_);
429 previous_level_ = level;
435 if (!propagation_queue_.
empty()) {
446 if (
var >= var_to_constraint_ids_.
size())
continue;
447 SetPropagatedBy(
var, -1);
448 AddWatchedToQueue(
var);
459 const int saved_index = trail_->
Index();
460 while (!propagation_queue_.
empty()) {
461 const int id = propagation_queue_.
Pop();
462 in_queue_[id] =
false;
463 if (!PropagateOneConstraint(
id)) {
468 if (trail_->
Index() > saved_index) {
481 absl::Span<const Literal> enforcement_literals,
482 absl::Span<const IntegerVariable> vars,
483 absl::Span<const IntegerValue> coeffs, IntegerValue
upper_bound) {
484 if (vars.empty())
return;
485 for (
const Literal l : enforcement_literals) {
491 CHECK_LT(vars.size(), 1 << 29);
492 if (vars.size() > max_variations_.size()) {
493 max_variations_.resize(vars.size(), 0);
494 buffer_of_ones_.resize(vars.size(), IntegerValue(1));
498 CHECK_EQ(vars.size(), coeffs.size());
499 const int id = infos_.size();
502 info.all_coeffs_are_one =
false;
503 info.start = variables_buffer_.size();
504 info.initial_size = vars.size();
506 info.rev_size = vars.size();
507 infos_.push_back(std::move(info));
510 id_to_propagation_count_.push_back(0);
511 variables_buffer_.insert(variables_buffer_.end(), vars.begin(), vars.end());
512 coeffs_buffer_.insert(coeffs_buffer_.end(), coeffs.begin(), coeffs.end());
513 CanonicalizeConstraint(
id);
515 bool all_at_one =
true;
516 for (
const IntegerValue coeff : GetCoeffs(infos_.back())) {
525 infos_.back().all_coeffs_are_one =
true;
530 in_queue_.push_back(
false);
533 if (!enforcement_literals.empty()) {
535 infos_.back().enf_id = enforcement_propagator_->
Register(
537 infos_[id].enf_status =
status;
543 AddToQueueIfNeeded(
id);
548 AddToQueueIfNeeded(
id);
549 infos_.back().enf_id = -1;
553 for (
const IntegerVariable
var : GetVariables(infos_[
id])) {
555 if (
var >= var_to_constraint_ids_.
size()) {
558 var_to_constraint_ids_.
resize(size);
559 propagated_by_.
resize(size, -1);
560 propagated_by_was_set_.
Resize(IntegerVariable(size));
561 is_watched_.
resize(size,
false);
571 if (!is_watched_[
var]) {
572 is_watched_[
var] =
true;
578 absl::Span<IntegerValue> LinearPropagator::GetCoeffs(
579 const ConstraintInfo& info) {
580 if (info.all_coeffs_are_one) {
581 return absl::MakeSpan(&buffer_of_ones_[0], info.initial_size);
583 return absl::MakeSpan(&coeffs_buffer_[info.start], info.initial_size);
586 absl::Span<IntegerVariable> LinearPropagator::GetVariables(
587 const ConstraintInfo& info) {
588 return absl::MakeSpan(&variables_buffer_[info.start], info.initial_size);
591 void LinearPropagator::CanonicalizeConstraint(
int id) {
592 const ConstraintInfo& info = infos_[id];
593 auto coeffs = GetCoeffs(info);
594 auto vars = GetVariables(info);
595 for (
int i = 0; i < vars.size(); ++i) {
597 coeffs[i] = -coeffs[i];
604 bool LinearPropagator::PropagateOneConstraint(
int id) {
609 if (id_scanned_at_least_once_[
id]) {
612 id_scanned_at_least_once_.
Set(
id);
617 ConstraintInfo& info = infos_[id];
620 DCHECK(!in_queue_[
id]);
624 in_queue_[id] =
true;
625 in_queue_and_at_false_.push_back(
id);
633 IntegerValue implied_lb(0);
634 auto vars = GetVariables(info);
635 auto coeffs = GetCoeffs(info);
636 IntegerValue max_variation(0);
637 bool first_change =
true;
640 for (
int i = 0; i < info.rev_size;) {
641 const IntegerVariable
var = vars[i];
642 const IntegerValue coeff = coeffs[i];
649 rev_int_repository_->
SaveState(&info.rev_size);
650 rev_integer_value_repository_->
SaveState(&info.rev_rhs);
651 first_change =
false;
655 std::swap(coeffs[i], coeffs[info.rev_size]);
656 info.rev_rhs -= coeff * lb;
658 implied_lb += coeff * lb;
659 max_variations_[i] = (ub - lb) * coeff;
660 max_variation =
std::max(max_variation, max_variations_[i]);
664 const IntegerValue slack = info.rev_rhs - implied_lb;
667 if (max_variation <= slack)
return true;
670 integer_reason_.clear();
671 reason_coeffs_.clear();
672 for (
int i = 0; i < info.initial_size; ++i) {
673 const IntegerVariable
var = vars[i];
676 reason_coeffs_.push_back(coeffs[i]);
683 ++num_enforcement_pushes_;
694 for (
int i = 0; i < info.rev_size; ++i) {
695 if (max_variations_[i] <= slack)
continue;
700 const IntegerVariable
var = vars[i];
701 const IntegerValue coeff = coeffs[i];
702 const IntegerValue div = slack / coeff;
703 const IntegerValue new_ub = integer_trail_->
LowerBound(
var) + div;
704 const IntegerValue propagation_slack = (div + 1) * coeff - slack - 1;
707 [
this, info, propagation_slack](
708 IntegerLiteral i_lit,
int trail_index,
709 std::vector<Literal>* literal_reason,
710 std::vector<int>* trail_indices_reason) {
711 literal_reason->clear();
712 trail_indices_reason->clear();
713 enforcement_propagator_->AddEnforcementReason(info.enf_id,
715 reason_coeffs_.clear();
717 auto coeffs = GetCoeffs(info);
718 auto vars = GetVariables(info);
719 for (int i = 0; i < info.initial_size; ++i) {
720 const IntegerVariable var = vars[i];
721 if (PositiveVariable(var) == PositiveVariable(i_lit.var)) {
725 integer_trail_->FindTrailIndexOfVarBefore(var, trail_index);
727 trail_indices_reason->push_back(index);
728 if (propagation_slack > 0) {
729 reason_coeffs_.push_back(coeffs[i]);
733 if (propagation_slack > 0) {
735 propagation_slack, reason_coeffs_, trail_indices_reason);
742 const IntegerValue actual_ub = integer_trail_->
UpperBound(
var);
744 if (actual_ub < new_ub) {
746 SetPropagatedBy(next_var, -1);
747 AddWatchedToQueue(next_var);
748 }
else if (actual_ub == new_ub) {
749 SetPropagatedBy(next_var,
id);
750 AddWatchedToQueue(next_var);
754 std::swap(coeffs[i], coeffs[num_pushed]);
760 if (num_pushed > 0) {
761 if (!DisassembleSubtree(
id, num_pushed)) {
770 std::string LinearPropagator::ConstraintDebugString(
int id) {
772 const ConstraintInfo& info = infos_[id];
773 auto coeffs = GetCoeffs(info);
774 auto vars = GetVariables(info);
775 IntegerValue implied_lb(0);
776 IntegerValue rhs_correction(0);
777 for (
int i = 0; i < info.initial_size; ++i) {
778 const IntegerValue term = coeffs[i] * integer_trail_->LowerBound(vars[i]);
779 if (i >= info.rev_size) {
780 rhs_correction += term;
783 absl::StrAppend(&result,
" +", coeffs[i].
value(),
"*X", vars[i].
value());
785 const IntegerValue original_rhs = info.rev_rhs + rhs_correction;
786 absl::StrAppend(&result,
" <= ", original_rhs.value(),
787 " slack=", original_rhs.value() - implied_lb.value());
788 absl::StrAppend(&result,
" enf=", info.enf_status);
792 bool LinearPropagator::ReportConflictingCycle() {
800 literal_reason_.clear();
801 integer_reason_.clear();
802 absl::int128 rhs_sum = 0;
803 absl::flat_hash_map<IntegerVariable, absl::int128> map_sum;
804 for (
const auto [
id, next_var] : disassemble_branch_) {
805 const ConstraintInfo& info = infos_[id];
806 enforcement_propagator_->AddEnforcementReason(info.enf_id,
808 auto coeffs = GetCoeffs(info);
809 auto vars = GetVariables(info);
810 IntegerValue rhs_correction(0);
811 for (
int i = 0; i < info.initial_size; ++i) {
812 if (i >= info.rev_size) {
813 rhs_correction += coeffs[i] * integer_trail_->LowerBound(vars[i]);
816 map_sum[vars[i]] += coeffs[i].value();
821 rhs_sum += (info.rev_rhs + rhs_correction).
value();
826 absl::int128 implied_lb = 0;
827 for (
const auto [
var, coeff] : map_sum) {
829 if (!integer_trail_->VariableLowerBoundIsFromLevelZero(
var)) {
830 integer_reason_.push_back(integer_trail_->LowerBoundAsLiteral(
var));
833 coeff * absl::int128{integer_trail_->LowerBound(
var).value()};
834 }
else if (coeff < 0) {
835 if (!integer_trail_->VariableLowerBoundIsFromLevelZero(
837 integer_reason_.push_back(integer_trail_->UpperBoundAsLiteral(
var));
840 coeff * absl::int128{integer_trail_->UpperBound(
var).value()};
843 if (implied_lb > rhs_sum) {
845 std::sort(integer_reason_.begin(), integer_reason_.end(),
846 [](
const IntegerLiteral&
a,
const IntegerLiteral&
b) {
847 return a.var < b.var;
852 const absl::int128 slack = implied_lb - rhs_sum;
854 reason_coeffs_.clear();
856 for (
const IntegerLiteral i_lit : integer_reason_) {
863 reason_coeffs_.push_back(
static_cast<int64_t
>(c));
866 const IntegerValue slack64(
867 static_cast<int64_t
>(
std::min(limit, slack)));
868 integer_trail_->RelaxLinearReason(slack64 - 1, reason_coeffs_,
873 ++num_simple_cycles_;
874 VLOG(2) <<
"Simplified " << integer_reason_.size() <<
" slack "
875 << implied_lb - rhs_sum;
876 return integer_trail_->ReportConflict(literal_reason_, integer_reason_);
885 literal_reason_.clear();
886 integer_reason_.clear();
888 for (
const auto [
id, next_var] : disassemble_branch_) {
889 const ConstraintInfo& info = infos_[id];
890 enforcement_propagator_->AddEnforcementReason(info.enf_id,
892 for (
const IntegerVariable
var : GetVariables(infos_[
id])) {
895 if (
var == previous_var)
continue;
900 if (!integer_trail_->VariableLowerBoundIsFromLevelZero(
var)) {
901 integer_reason_.push_back(integer_trail_->LowerBoundAsLiteral(
var));
904 previous_var = next_var;
906 VLOG(2) << next_var <<
" [" << integer_trail_->LowerBound(next_var) <<
","
907 << integer_trail_->UpperBound(next_var)
908 <<
"] : " << ConstraintDebugString(
id);
910 ++num_complex_cycles_;
911 return integer_trail_->ReportConflict(literal_reason_, integer_reason_);
920 bool LinearPropagator::DisassembleSubtree(
int root_id,
int num_pushed) {
921 disassemble_to_reorder_.ClearAndResize(in_queue_.size());
922 disassemble_reverse_topo_order_.clear();
929 disassemble_queue_.clear();
930 disassemble_branch_.clear();
932 const ConstraintInfo& info = infos_[root_id];
933 auto vars = GetVariables(info);
934 for (
int i = 0; i < num_pushed; ++i) {
935 disassemble_queue_.push_back({root_id,
NegationOf(vars[i])});
941 while (!disassemble_queue_.empty()) {
942 const auto [prev_id,
var] = disassemble_queue_.back();
943 if (!disassemble_branch_.empty() &&
944 disassemble_branch_.back().first == prev_id &&
945 disassemble_branch_.back().second ==
var) {
946 disassemble_branch_.pop_back();
947 disassemble_reverse_topo_order_.push_back(prev_id);
948 disassemble_queue_.pop_back();
952 disassemble_branch_.push_back({prev_id,
var});
953 time_limit_->AdvanceDeterministicTime(
954 static_cast<double>(var_to_constraint_ids_[
var].size()) * 1e-9);
955 for (
const int id : var_to_constraint_ids_[
var]) {
956 if (prev_id == root_id) {
959 DCHECK_NE(
id, root_id);
960 if (disassemble_to_reorder_[
id])
continue;
961 disassemble_to_reorder_.Set(
id);
962 }
else if (
id == root_id) {
966 CHECK(!disassemble_branch_.empty());
969 const IntegerVariable root_var = disassemble_branch_[0].second;
970 CHECK_EQ(disassemble_branch_[0].first, root_id);
971 CHECK_NE(
var, root_var);
980 const ConstraintInfo& info = infos_[id];
981 auto coeffs = GetCoeffs(info);
982 auto vars = GetVariables(info);
983 IntegerValue root_coeff(0);
984 IntegerValue var_coeff(0);
985 for (
int i = 0; i < info.initial_size; ++i) {
986 if (vars[i] ==
var) var_coeff = coeffs[i];
987 if (vars[i] ==
NegationOf(root_var)) root_coeff = coeffs[i];
989 CHECK_NE(root_coeff, 0);
990 CHECK_NE(var_coeff, 0);
991 if (var_coeff >= root_coeff) {
992 return ReportConflictingCycle();
999 if (id_to_propagation_count_[
id] == 0)
continue;
1000 disassemble_to_reorder_.Set(
id);
1005 const ConstraintInfo& info = infos_[id];
1006 auto coeffs = GetCoeffs(info);
1007 auto vars = GetVariables(info);
1008 IntegerValue var_coeff(0);
1009 disassemble_candidates_.clear();
1010 ++num_explored_in_disassemble_;
1011 time_limit_->AdvanceDeterministicTime(
static_cast<double>(info.rev_size) *
1013 for (
int i = 0; i < info.rev_size; ++i) {
1014 if (vars[i] ==
var) {
1015 var_coeff = coeffs[i];
1018 const IntegerVariable next_var =
NegationOf(vars[i]);
1019 if (propagated_by_[next_var] ==
id) {
1020 disassemble_candidates_.push_back({next_var, coeffs[i]});
1023 propagated_by_[next_var] = -1;
1024 id_to_propagation_count_[id]--;
1027 for (
const auto [next_var, coeff] : disassemble_candidates_) {
1028 if (coeff <= var_coeff) {
1034 disassemble_queue_.push_back({id, next_var});
1040 CHECK(!disassemble_to_reorder_[root_id]);
1041 tmp_to_reorder_.clear();
1042 std::reverse(disassemble_reverse_topo_order_.begin(),
1043 disassemble_reverse_topo_order_.end());
1044 for (
const int id : disassemble_reverse_topo_order_) {
1045 if (!disassemble_to_reorder_[
id])
continue;
1046 disassemble_to_reorder_.Clear(
id);
1047 AddToQueueIfNeeded(
id);
1048 if (!propagation_queue_.Contains(
id))
continue;
1049 tmp_to_reorder_.push_back(
id);
1055 if (tmp_to_reorder_.empty())
return true;
1056 const int important_size =
static_cast<int>(tmp_to_reorder_.size());
1058 for (
const int id : disassemble_to_reorder_.PositionsSetAtLeastOnce()) {
1059 if (!disassemble_to_reorder_[
id])
continue;
1060 disassemble_to_reorder_.Clear(
id);
1061 if (!propagation_queue_.Contains(
id))
continue;
1062 tmp_to_reorder_.push_back(
id);
1064 disassemble_to_reorder_.NotifyAllClear();
1068 propagation_queue_.SortByPos(
1069 absl::MakeSpan(&tmp_to_reorder_[important_size],
1070 tmp_to_reorder_.size() - important_size));
1072 num_reordered_ += tmp_to_reorder_.size();
1073 propagation_queue_.Reorder(tmp_to_reorder_);
1077 void LinearPropagator::AddToQueueIfNeeded(
int id) {
1078 DCHECK_LT(
id, in_queue_.size());
1079 DCHECK_LT(
id, infos_.size());
1081 if (in_queue_[
id])
return;
1082 in_queue_[id] =
true;
1083 propagation_queue_.Push(
id);
1086 void LinearPropagator::AddWatchedToQueue(IntegerVariable
var) {
1087 if (
var >=
static_cast<int>(var_to_constraint_ids_.size()))
return;
1088 time_limit_->AdvanceDeterministicTime(
1089 static_cast<double>(var_to_constraint_ids_[
var].size()) * 1e-9);
1090 for (
const int id : var_to_constraint_ids_[
var]) {
1091 AddToQueueIfNeeded(
id);
1095 void LinearPropagator::SetPropagatedBy(IntegerVariable
var,
int id) {
1096 int& ref_id = propagated_by_[
var];
1097 if (ref_id ==
id)
return;
1099 propagated_by_was_set_.Set(
var);
1102 DCHECK_LT(
var, propagated_by_.size());
1104 DCHECK_GE(ref_id, 0);
1105 DCHECK_LT(ref_id, id_to_propagation_count_.size());
1106 id_to_propagation_count_[ref_id]--;
1109 if (
id != -1) id_to_propagation_count_[id]++;
1112 void LinearPropagator::ClearPropagatedBy() {
1115 for (
const IntegerVariable
var :
1116 propagated_by_was_set_.PositionsSetAtLeastOnce()) {
1117 int&
id = propagated_by_[
var];
1118 if (
id != -1) --id_to_propagation_count_[id];
1119 propagated_by_[
var] = -1;
1121 propagated_by_was_set_.ClearAndResize(propagated_by_was_set_.size());
1122 DCHECK(std::all_of(propagated_by_.begin(), propagated_by_.end(),
1123 [](
int id) { return id == -1; }));
1124 DCHECK(std::all_of(id_to_propagation_count_.begin(),
1125 id_to_propagation_count_.end(),
1126 [](
int count) { return count == 0; }));
void resize(size_type new_size)
void push_back(const value_type &x)
An Assignment is a variable -> domains mapping, used to report solutions to the user.
void SaveState(T *object)
void SaveStateWithStamp(T *object, int64_t *stamp)
const std::vector< IntegerType > & PositionsSetAtLeastOnce() const
void Set(IntegerType index)
void Resize(IntegerType size)
void ClearAndResize(IntegerType size)
A simple class to enforce both an elapsed time limit and a deterministic time limit in the same threa...
void AdvanceDeterministicTime(double deterministic_duration)
Advances the deterministic time.
void ReorderDense(absl::Span< const int > order)
void SortByPos(absl::Span< int > elements)
void Reorder(absl::Span< const int > order)
bool Contains(int id) const
bool Propagate(Trail *trail) final
EnforcementId Register(absl::Span< const Literal > enforcement, std::function< void(EnforcementStatus)> callback=nullptr)
ABSL_MUST_USE_RESULT bool PropagateWhenFalse(EnforcementId id, absl::Span< const Literal > literal_reason, absl::Span< const IntegerLiteral > integer_reason)
void AddEnforcementReason(EnforcementId id, std::vector< Literal > *reason) const
void Untrail(const Trail &trail, int trail_index) final
void CallOnNextPropagate(int id)
void WatchLowerBound(IntegerVariable var, int id, int watch_index=-1)
void SetPropagatorPriority(int id, int priority)
ABSL_MUST_USE_RESULT bool Enqueue(IntegerLiteral i_lit, absl::Span< const Literal > literal_reason, absl::Span< const IntegerLiteral > integer_reason)
void RegisterWatcher(SparseBitset< IntegerVariable > *p)
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
bool VariableLowerBoundIsFromLevelZero(IntegerVariable var) const
void RelaxLinearReason(IntegerValue slack, absl::Span< const IntegerValue > coeffs, std::vector< IntegerLiteral > *reason) const
IntegerValue LowerBound(IntegerVariable i) const
void RegisterReversibleClass(ReversibleInterface *rev)
IntegerVariable NumIntegerVariables() const
void SetLevel(int level) final
~LinearPropagator() override
void AddConstraint(absl::Span< const Literal > enforcement_literals, absl::Span< const IntegerVariable > vars, absl::Span< const IntegerValue > coeffs, IntegerValue upper_bound)
LinearPropagator(Model *model)
Class that owns everything related to a particular optimization model.
int propagation_trail_index_
void AddStats(absl::Span< const std::pair< std::string, int64_t >> stats)
const VariablesAssignment & Assignment() const
int CurrentDecisionLevel() const
bool LiteralIsAssigned(Literal literal) const
bool LiteralIsTrue(Literal literal) const
bool LiteralIsFalse(Literal literal) const
void STLSortAndRemoveDuplicates(T *v, const LessFunc &less_func)
void swap(IdMap< K, V > &a, IdMap< K, V > &b)
const LiteralIndex kNoLiteralIndex(-1)
const IntegerVariable kNoIntegerVariable(-1)
IntegerVariable PositiveVariable(IntegerVariable i)
std::vector< IntegerVariable > NegationOf(const std::vector< IntegerVariable > &vars)
bool VariableIsPositive(IntegerVariable i)
Collection of objects used to extend the Constraint Solver library.
std::ostream & operator<<(std::ostream &out, const Assignment &assignment)
static IntegerLiteral LowerOrEqual(IntegerVariable i, IntegerValue bound)
#define VLOG(verboselevel)
#define VLOG_IS_ON(verboselevel)