18 #include <type_traits>
28 const std::vector<IntegerVariable>& vars) {
29 std::vector<IntegerVariable> result(vars.size());
30 for (
int i = 0; i < vars.size(); ++i) {
42 <<
"Domain too large for full encoding.";
55 tmp_values_.push_back(v);
58 for (
const IntegerValue v : tmp_values_) {
70 if (
index >= is_fully_encoded_.
size())
return false;
73 if (is_fully_encoded_[
index])
return true;
80 const int64 initial_domain_size = (*domains_)[
var].Size();
81 if (equality_by_var_[
index].size() < initial_domain_size)
return false;
90 const auto& ref = equality_by_var_[
index];
94 if (i < ref.size() && v == ref[i].value) {
99 if (i == ref.size()) {
100 is_fully_encoded_[
index] =
true;
102 return is_fully_encoded_[
index];
105 std::vector<IntegerEncoder::ValueLiteralPair>
111 std::vector<IntegerEncoder::ValueLiteralPair>
115 if (
index >= equality_by_var_.size())
return {};
118 std::vector<ValueLiteralPair>& ref = equality_by_var_[
index];
119 for (
int i = 0; i < ref.size(); ++i) {
128 ref[new_size++] = pair;
130 ref.resize(new_size);
131 std::sort(ref.begin(), ref.end());
133 std::vector<IntegerEncoder::ValueLiteralPair> result = ref;
135 std::reverse(result.begin(), result.end());
144 void IntegerEncoder::AddImplications(
145 const std::map<IntegerValue, Literal>& map,
146 std::map<IntegerValue, Literal>::const_iterator it,
148 if (!add_implications_)
return;
154 if (after_it != map.end()) {
156 {after_it->second.Negated(), associated_lit});
160 if (it != map.begin()) {
164 {associated_lit.
Negated(), before_it->second});
170 add_implications_ =
true;
171 for (
const std::map<IntegerValue, Literal>& encoding : encoding_by_var_) {
173 for (
const auto value_literal : encoding) {
174 const Literal lit = value_literal.second;
179 previous = lit.
Index();
186 const IntegerVariable
var(i_lit.
var);
187 IntegerValue after(i_lit.
bound);
188 IntegerValue before(i_lit.
bound - 1);
193 if (before > previous && before <
interval.start) before = previous;
203 if (i_lit.
bound <= (*domains_)[i_lit.
var].Min()) {
206 if (i_lit.
bound > (*domains_)[i_lit.
var].Max()) {
218 ++num_created_variables_;
225 VLOG(1) <<
"Created a fixed literal for no reason!";
231 std::pair<PositiveOnlyIndex, IntegerValue> PositiveVarKey(IntegerVariable
var,
232 IntegerValue
value) {
239 IntegerVariable
var, IntegerValue
value)
const {
241 equality_to_associated_literal_.find(PositiveVarKey(
var,
value));
242 if (it != equality_to_associated_literal_.end()) {
243 return it->second.Index();
249 IntegerVariable
var, IntegerValue
value) {
252 equality_to_associated_literal_.find(PositiveVarKey(
var,
value));
253 if (it != equality_to_associated_literal_.end()) {
267 ++num_created_variables_;
277 VLOG(1) <<
"Created a fixed literal for no reason!";
284 const auto& domain = (*domains_)[i_lit.
var];
285 const IntegerValue
min(domain.Min());
286 const IntegerValue
max(domain.Max());
293 HalfAssociateGivenLiteral(pair.first,
literal);
294 HalfAssociateGivenLiteral(pair.second,
literal.Negated());
299 if (pair.first.bound ==
max) {
302 if (-pair.second.bound ==
min) {
310 IntegerValue
value) {
315 if (
value == 1 && domain.
Min() >= 0 && domain.
Max() <= 1) {
323 if (
value == -1 && domain.
Min() >= -1 && domain.
Max() <= 0) {
334 const auto insert_result = equality_to_associated_literal_.insert(
336 if (!insert_result.second) {
357 if (
index >= equality_by_var_.size()) {
358 equality_by_var_.resize(
index.value() + 1);
361 equality_by_var_[
index].push_back(
396 const int new_size = 1 +
literal.Index().value();
397 if (new_size > full_reverse_encoding_.
size()) {
398 full_reverse_encoding_.
resize(new_size);
408 void IntegerEncoder::HalfAssociateGivenLiteral(
IntegerLiteral i_lit,
411 const int new_size = 1 +
literal.Index().value();
412 if (new_size > reverse_encoding_.
size()) {
413 reverse_encoding_.
resize(new_size);
415 if (new_size > full_reverse_encoding_.
size()) {
416 full_reverse_encoding_.
resize(new_size);
420 if (i_lit.
var >= encoding_by_var_.size()) {
421 encoding_by_var_.resize(i_lit.
var.value() + 1);
423 auto& var_encoding = encoding_by_var_[i_lit.
var];
424 auto insert_result = var_encoding.insert({i_lit.
bound,
literal});
425 if (insert_result.second) {
426 AddImplications(var_encoding, insert_result.first,
literal);
429 newly_fixed_integer_literals_.push_back(i_lit);
437 const Literal associated(insert_result.first->second);
447 if (i.
var >= encoding_by_var_.size())
return false;
448 const std::map<IntegerValue, Literal>& encoding = encoding_by_var_[i.
var];
449 return encoding.find(i.
bound) != encoding.end();
454 const std::map<IntegerValue, Literal>& encoding = encoding_by_var_[i.
var];
455 const auto result = encoding.find(i.
bound);
457 return result->second.Index();
465 const std::map<IntegerValue, Literal>& encoding = encoding_by_var_[i.
var];
466 auto after_it = encoding.upper_bound(i.
bound);
469 *
bound = after_it->first;
470 return after_it->second.Index();
474 if (parameters_.log_search_progress() && num_decisions_to_break_loop_ > 0) {
475 LOG(
INFO) <<
"Num decisions to break propagation loop: "
476 << num_decisions_to_break_loop_;
487 if (level > integer_search_levels_.size()) {
488 integer_search_levels_.push_back(integer_trail_.size());
489 reason_decision_levels_.push_back(literals_reason_starts_.size());
495 var_to_current_lb_interval_index_.
SetLevel(level);
508 if (!
Enqueue(i_lit, {}, {}))
return false;
514 if (!
Enqueue(i_lit, {}, {}))
return false;
516 integer_literal_to_fix_.clear();
518 for (
const Literal lit : literal_to_fix_) {
523 literal_to_fix_.clear();
528 while (propagation_trail_index_ < trail->
Index()) {
534 if (!EnqueueAssociatedIntegerLiteral(i_lit,
literal)) {
546 var_to_current_lb_interval_index_.
SetLevel(level);
550 if (level < first_level_without_full_propagation_) {
551 first_level_without_full_propagation_ = -1;
556 if (level >= integer_search_levels_.size())
return;
557 const int target = integer_search_levels_[level];
558 integer_search_levels_.resize(level);
560 CHECK_LE(target, integer_trail_.size());
562 for (
int index = integer_trail_.size() - 1;
index >= target; --
index) {
563 const TrailEntry& entry = integer_trail_[
index];
564 if (entry.var < 0)
continue;
565 vars_[entry.var].current_trail_index = entry.prev_trail_index;
566 vars_[entry.var].current_bound =
567 integer_trail_[entry.prev_trail_index].bound;
569 integer_trail_.resize(target);
572 const int old_size = reason_decision_levels_[level];
573 reason_decision_levels_.resize(level);
574 if (old_size < literals_reason_starts_.size()) {
575 literals_reason_buffer_.resize(literals_reason_starts_[old_size]);
577 const int bound_start = bounds_reason_starts_[old_size];
578 bounds_reason_buffer_.resize(bound_start);
579 if (bound_start < trail_index_reason_buffer_.size()) {
580 trail_index_reason_buffer_.resize(bound_start);
583 literals_reason_starts_.resize(old_size);
584 bounds_reason_starts_.resize(old_size);
594 const int size = 2 * num_vars;
596 is_ignored_literals_.
reserve(size);
597 integer_trail_.reserve(size);
599 var_trail_index_cache_.
reserve(size);
600 tmp_var_to_trail_index_in_queue_.
reserve(size);
604 IntegerValue upper_bound) {
609 DCHECK(integer_search_levels_.empty());
612 const IntegerVariable i(vars_.
size());
614 vars_.
push_back({lower_bound,
static_cast<int>(integer_trail_.size())});
615 integer_trail_.push_back({lower_bound, i});
623 vars_.
push_back({-upper_bound,
static_cast<int>(integer_trail_.size())});
624 integer_trail_.push_back({-upper_bound,
NegationOf(i)});
625 domains_->
push_back(
Domain(-upper_bound.value(), -lower_bound.value()));
627 var_trail_index_cache_.
resize(vars_.
size(), integer_trail_.size());
628 tmp_var_to_trail_index_in_queue_.
resize(vars_.
size(), 0);
639 IntegerValue(domain.
Max()));
645 return (*domains_)[
var];
653 if (old_domain == domain)
return true;
655 if (domain.
IsEmpty())
return false;
656 (*domains_)[
var] = domain;
659 var_to_current_lb_interval_index_.
Set(
var, 0);
678 if (i == domain.
NumIntervals() || pair.value < domain[i].start) {
688 <<
"Domain intersection fixed " << num_fixed
689 <<
" equality literal corresponding to values outside the new domain.";
696 IntegerValue
value) {
700 insert.first->second = new_var;
707 return insert.first->second;
713 return (constant_map_.size() + 1) / 2;
717 int threshold)
const {
721 const int index_in_queue = tmp_var_to_trail_index_in_queue_[
var];
722 if (threshold <= index_in_queue) {
723 if (index_in_queue !=
kint32max) has_dependency_ =
true;
728 int trail_index = vars_[
var].current_trail_index;
731 if (trail_index > threshold) {
732 const int cached_index = var_trail_index_cache_[
var];
733 if (cached_index >= threshold && cached_index < trail_index &&
734 integer_trail_[cached_index].
var ==
var) {
735 trail_index = cached_index;
739 while (trail_index >= threshold) {
740 trail_index = integer_trail_[trail_index].prev_trail_index;
741 if (trail_index >= var_trail_index_cache_threshold_) {
742 var_trail_index_cache_[
var] = trail_index;
746 const int num_vars = vars_.
size();
747 return trail_index < num_vars ? -1 : trail_index;
750 int IntegerTrail::FindLowestTrailIndexThatExplainBound(
754 int trail_index = vars_[i_lit.
var].current_trail_index;
762 const int cached_index = var_trail_index_cache_[i_lit.
var];
763 if (cached_index < trail_index) {
764 const TrailEntry& entry = integer_trail_[cached_index];
765 if (entry.var == i_lit.
var && entry.bound >= i_lit.
bound) {
766 trail_index = cached_index;
771 int prev_trail_index = trail_index;
773 if (trail_index >= var_trail_index_cache_threshold_) {
774 var_trail_index_cache_[i_lit.
var] = trail_index;
776 const TrailEntry& entry = integer_trail_[trail_index];
777 if (entry.bound == i_lit.
bound)
return trail_index;
778 if (entry.bound < i_lit.
bound)
return prev_trail_index;
779 prev_trail_index = trail_index;
780 trail_index = entry.prev_trail_index;
786 IntegerValue slack, absl::Span<const IntegerValue> coeffs,
787 std::vector<IntegerLiteral>* reason)
const {
789 if (slack == 0)
return;
790 const int size = reason->size();
791 tmp_indices_.resize(size);
792 for (
int i = 0; i < size; ++i) {
795 tmp_indices_[i] = vars_[(*reason)[i].var].current_trail_index;
801 for (
const int i : tmp_indices_) {
803 integer_trail_[i].
bound));
808 IntegerValue slack, absl::Span<const IntegerValue> coeffs,
809 absl::Span<const IntegerVariable> vars,
810 std::vector<IntegerLiteral>* reason)
const {
811 tmp_indices_.clear();
812 for (
const IntegerVariable
var : vars) {
813 tmp_indices_.push_back(vars_[
var].current_trail_index);
816 for (
const int i : tmp_indices_) {
818 integer_trail_[i].
bound));
823 absl::Span<const IntegerValue> coeffs,
824 std::vector<int>* trail_indices)
const {
826 DCHECK(relax_heap_.empty());
833 const int size = coeffs.size();
834 const int num_vars = vars_.
size();
835 for (
int i = 0; i < size; ++i) {
836 const int index = (*trail_indices)[i];
839 if (
index < num_vars)
continue;
842 const IntegerValue coeff = coeffs[i];
844 (*trail_indices)[new_size++] =
index;
851 const TrailEntry& entry = integer_trail_[
index];
853 index <= tmp_var_to_trail_index_in_queue_[entry.var]) {
854 (*trail_indices)[new_size++] =
index;
859 const TrailEntry& previous_entry = integer_trail_[entry.prev_trail_index];
861 CapProd(coeff.value(), (entry.bound - previous_entry.bound).value());
863 (*trail_indices)[new_size++] =
index;
867 relax_heap_.push_back({
index, coeff, diff});
869 trail_indices->resize(new_size);
870 std::make_heap(relax_heap_.begin(), relax_heap_.end());
872 while (slack > 0 && !relax_heap_.empty()) {
873 const RelaxHeapEntry heap_entry = relax_heap_.front();
874 std::pop_heap(relax_heap_.begin(), relax_heap_.end());
875 relax_heap_.pop_back();
878 if (heap_entry.diff > slack) {
879 trail_indices->push_back(heap_entry.index);
884 slack -= heap_entry.diff;
885 const int index = integer_trail_[heap_entry.index].prev_trail_index;
888 if (
index < num_vars)
continue;
889 if (heap_entry.coeff > slack) {
890 trail_indices->push_back(
index);
893 const TrailEntry& entry = integer_trail_[
index];
895 index <= tmp_var_to_trail_index_in_queue_[entry.var]) {
896 trail_indices->push_back(
index);
900 const TrailEntry& previous_entry = integer_trail_[entry.prev_trail_index];
902 (entry.bound - previous_entry.bound).value());
904 trail_indices->push_back(
index);
907 relax_heap_.push_back({
index, heap_entry.coeff, diff});
908 std::push_heap(relax_heap_.begin(), relax_heap_.end());
913 for (
const RelaxHeapEntry& entry : relax_heap_) {
914 trail_indices->push_back(entry.index);
920 std::vector<IntegerLiteral>* reason)
const {
924 (*reason)[new_size++] =
literal;
926 reason->resize(new_size);
929 std::vector<Literal>* IntegerTrail::InitializeConflict(
930 IntegerLiteral integer_literal,
const LazyReasonFunction& lazy_reason,
931 absl::Span<const Literal> literals_reason,
932 absl::Span<const IntegerLiteral> bounds_reason) {
933 DCHECK(tmp_queue_.empty());
935 if (lazy_reason ==
nullptr) {
936 conflict->assign(literals_reason.begin(), literals_reason.end());
937 const int num_vars = vars_.
size();
939 const int trail_index = FindLowestTrailIndexThatExplainBound(
literal);
940 if (trail_index >= num_vars) tmp_queue_.push_back(trail_index);
945 lazy_reason(integer_literal, integer_trail_.size(), conflict, &tmp_queue_);
952 std::string ReasonDebugString(absl::Span<const Literal> literal_reason,
953 absl::Span<const IntegerLiteral> integer_reason) {
954 std::string result =
"literals:{";
955 for (
const Literal l : literal_reason) {
956 if (result.back() !=
'{') result +=
",";
957 result += l.DebugString();
959 result +=
"} bounds:{";
960 for (
const IntegerLiteral l : integer_reason) {
961 if (result.back() !=
'{') result +=
",";
962 result += l.DebugString();
970 std::string IntegerTrail::DebugString() {
971 std::string result =
"trail:{";
972 const int num_vars = vars_.
size();
974 std::min(num_vars + 30,
static_cast<int>(integer_trail_.size()));
975 for (
int i = num_vars; i < limit; ++i) {
976 if (result.back() !=
'{') result +=
",";
979 integer_trail_[i].
bound)
982 if (limit < integer_trail_.size()) {
990 absl::Span<const Literal> literal_reason,
991 absl::Span<const IntegerLiteral> integer_reason) {
992 return EnqueueInternal(i_lit,
nullptr, literal_reason, integer_reason,
993 integer_trail_.size());
997 absl::Span<const Literal> literal_reason,
998 absl::Span<const IntegerLiteral> integer_reason,
999 int trail_index_with_same_reason) {
1000 return EnqueueInternal(i_lit,
nullptr, literal_reason, integer_reason,
1001 trail_index_with_same_reason);
1006 return EnqueueInternal(i_lit, lazy_reason, {}, {}, integer_trail_.size());
1009 bool IntegerTrail::ReasonIsValid(
1010 absl::Span<const Literal> literal_reason,
1011 absl::Span<const IntegerLiteral> integer_reason) {
1013 for (
const Literal lit : literal_reason) {
1016 for (
const IntegerLiteral i_lit : integer_reason) {
1017 if (i_lit.
bound > vars_[i_lit.
var].current_bound) {
1020 LOG(
INFO) <<
"Reason " << i_lit <<
" is not true!"
1021 <<
" optional variable:" << i_lit.
var
1024 <<
" current_lb:" << vars_[i_lit.
var].current_bound;
1026 LOG(
INFO) <<
"Reason " << i_lit <<
" is not true!"
1027 <<
" non-optional variable:" << i_lit.
var
1028 <<
" current_lb:" << vars_[i_lit.
var].current_bound;
1036 if (!integer_search_levels_.empty()) {
1037 int num_literal_assigned_after_root_node = 0;
1038 for (
const Literal lit : literal_reason) {
1039 if (trail_->
Info(lit.Variable()).
level > 0) {
1040 num_literal_assigned_after_root_node++;
1043 for (
const IntegerLiteral i_lit : integer_reason) {
1045 num_literal_assigned_after_root_node++;
1048 DLOG_IF(
INFO, num_literal_assigned_after_root_node == 0)
1049 <<
"Propagating a literal with no reason at a positive level!\n"
1050 <<
"level:" << integer_search_levels_.size() <<
" "
1051 << ReasonDebugString(literal_reason, integer_reason) <<
"\n"
1060 absl::Span<const IntegerLiteral> integer_reason) {
1061 EnqueueLiteralInternal(
literal,
nullptr, literal_reason, integer_reason);
1064 void IntegerTrail::EnqueueLiteralInternal(
1066 absl::Span<const Literal> literal_reason,
1067 absl::Span<const IntegerLiteral> integer_reason) {
1069 DCHECK(lazy_reason !=
nullptr ||
1070 ReasonIsValid(literal_reason, integer_reason));
1071 if (integer_search_levels_.empty()) {
1078 if (!integer_search_levels_.empty() && integer_reason.empty() &&
1079 literal_reason.empty() && lazy_reason ==
nullptr) {
1080 literal_to_fix_.push_back(
literal);
1083 const int trail_index = trail_->
Index();
1084 if (trail_index >= boolean_trail_index_to_integer_one_.size()) {
1085 boolean_trail_index_to_integer_one_.resize(trail_index + 1);
1087 boolean_trail_index_to_integer_one_[trail_index] = integer_trail_.size();
1089 int reason_index = literals_reason_starts_.size();
1090 if (lazy_reason !=
nullptr) {
1091 if (integer_trail_.size() >= lazy_reasons_.size()) {
1092 lazy_reasons_.resize(integer_trail_.size() + 1,
nullptr);
1094 lazy_reasons_[integer_trail_.size()] = lazy_reason;
1098 literals_reason_starts_.push_back(literals_reason_buffer_.size());
1099 literals_reason_buffer_.insert(literals_reason_buffer_.end(),
1100 literal_reason.begin(),
1101 literal_reason.end());
1102 bounds_reason_starts_.push_back(bounds_reason_buffer_.size());
1103 bounds_reason_buffer_.insert(bounds_reason_buffer_.end(),
1104 integer_reason.begin(), integer_reason.end());
1107 integer_trail_.push_back({IntegerValue(0),
1119 const int num_vars = vars_.
size();
1120 return (!integer_search_levels_.empty() &&
1121 integer_trail_.size() - integer_search_levels_.back() >
1123 parameters_.search_branching() != SatParameters::FIXED_SEARCH);
1130 ++num_decisions_to_break_loop_;
1131 std::vector<IntegerVariable> vars;
1132 for (
int i = integer_search_levels_.back(); i < integer_trail_.size(); ++i) {
1133 const IntegerVariable
var = integer_trail_[i].var;
1136 vars.push_back(
var);
1139 std::sort(vars.begin(), vars.end());
1140 IntegerVariable best_var = vars[0];
1143 for (
int i = 1; i < vars.size(); ++i) {
1144 if (vars[i] != vars[i - 1]) {
1148 if (count > best_count) {
1158 return first_level_without_full_propagation_ != -1;
1162 for (IntegerVariable
var(0);
var < vars_.
size();
var += 2) {
1169 bool IntegerTrail::EnqueueInternal(
1171 absl::Span<const Literal> literal_reason,
1172 absl::Span<const IntegerLiteral> integer_reason,
1173 int trail_index_with_same_reason) {
1174 DCHECK(lazy_reason !=
nullptr ||
1175 ReasonIsValid(literal_reason, integer_reason));
1177 const IntegerVariable
var(i_lit.
var);
1185 if (i_lit.
bound <= vars_[
var].current_bound)
return true;
1194 if ((*domains_)[
var].NumIntervals() > 1) {
1195 const auto& domain = (*domains_)[
var];
1197 const int size = domain.NumIntervals();
1198 while (index < size && i_lit.bound > domain[
index].end) {
1201 if (
index == size) {
1204 var_to_current_lb_interval_index_.
Set(
var,
index);
1215 Literal(is_ignored_literals_[
var]))) {
1218 auto* conflict = InitializeConflict(i_lit, lazy_reason, literal_reason,
1221 conflict->push_back(Literal(is_ignored_literals_[
var]));
1224 const int trail_index = FindLowestTrailIndexThatExplainBound(ub_reason);
1225 const int num_vars = vars_.
size();
1226 if (trail_index >= num_vars) tmp_queue_.push_back(trail_index);
1228 MergeReasonIntoInternal(conflict);
1235 const Literal is_ignored = Literal(is_ignored_literals_[
var]);
1236 if (integer_search_levels_.empty()) {
1243 if (lazy_reason !=
nullptr) {
1244 lazy_reason(i_lit, integer_trail_.size(), &lazy_reason_literals_,
1245 &lazy_reason_trail_indices_);
1246 std::vector<IntegerLiteral> temp;
1247 for (
const int trail_index : lazy_reason_trail_indices_) {
1248 const TrailEntry& entry = integer_trail_[trail_index];
1249 temp.push_back(IntegerLiteral(entry.var, entry.bound));
1257 bounds_reason_buffer_.push_back(ub_reason);
1277 if (i_lit.
bound - lb < (ub - lb) / 2) {
1278 if (first_level_without_full_propagation_ == -1) {
1286 for (SparseBitset<IntegerVariable>* bitset : watchers_) {
1287 bitset->Set(i_lit.
var);
1290 if (!integer_search_levels_.empty() && integer_reason.empty() &&
1291 literal_reason.empty() && lazy_reason ==
nullptr &&
1292 trail_index_with_same_reason >= integer_trail_.size()) {
1293 integer_literal_to_fix_.push_back(i_lit);
1309 const LiteralIndex literal_index =
1312 const Literal to_enqueue = Literal(literal_index);
1314 auto* conflict = InitializeConflict(i_lit, lazy_reason, literal_reason,
1316 conflict->push_back(to_enqueue);
1317 MergeReasonIntoInternal(conflict);
1327 EnqueueLiteralInternal(to_enqueue, lazy_reason, literal_reason,
1330 return EnqueueAssociatedIntegerLiteral(i_lit, to_enqueue);
1334 if (integer_search_levels_.empty()) {
1340 const int trail_index = trail_->
Index();
1341 if (trail_index >= boolean_trail_index_to_integer_one_.size()) {
1342 boolean_trail_index_to_integer_one_.resize(trail_index + 1);
1344 boolean_trail_index_to_integer_one_[trail_index] =
1345 trail_index_with_same_reason;
1352 if (integer_search_levels_.empty()) {
1353 ++num_level_zero_enqueues_;
1354 vars_[i_lit.
var].current_bound = i_lit.
bound;
1355 integer_trail_[i_lit.
var.value()].bound = i_lit.
bound;
1366 int reason_index = literals_reason_starts_.size();
1367 if (lazy_reason !=
nullptr) {
1368 if (integer_trail_.size() >= lazy_reasons_.size()) {
1369 lazy_reasons_.resize(integer_trail_.size() + 1,
nullptr);
1371 lazy_reasons_[integer_trail_.size()] = lazy_reason;
1373 }
else if (trail_index_with_same_reason >= integer_trail_.size()) {
1375 literals_reason_starts_.push_back(literals_reason_buffer_.size());
1376 if (!literal_reason.empty()) {
1377 literals_reason_buffer_.insert(literals_reason_buffer_.end(),
1378 literal_reason.begin(),
1379 literal_reason.end());
1381 bounds_reason_starts_.push_back(bounds_reason_buffer_.size());
1382 if (!integer_reason.empty()) {
1383 bounds_reason_buffer_.insert(bounds_reason_buffer_.end(),
1384 integer_reason.begin(),
1385 integer_reason.end());
1388 reason_index = integer_trail_[trail_index_with_same_reason].reason_index;
1391 const int prev_trail_index = vars_[i_lit.
var].current_trail_index;
1392 integer_trail_.push_back({i_lit.
bound,
1397 vars_[i_lit.
var].current_bound = i_lit.
bound;
1398 vars_[i_lit.
var].current_trail_index = integer_trail_.size() - 1;
1402 bool IntegerTrail::EnqueueAssociatedIntegerLiteral(IntegerLiteral i_lit,
1403 Literal literal_reason) {
1404 DCHECK(ReasonIsValid({literal_reason.Negated()}, {}));
1408 if (i_lit.bound <= vars_[i_lit.var].current_bound)
return true;
1416 return Enqueue(i_lit, {literal_reason.Negated()}, {});
1420 for (SparseBitset<IntegerVariable>* bitset : watchers_) {
1421 bitset->Set(i_lit.var);
1425 if (integer_search_levels_.empty()) {
1426 vars_[i_lit.var].current_bound = i_lit.bound;
1427 integer_trail_[i_lit.var.value()].bound = i_lit.bound;
1438 const int reason_index = literals_reason_starts_.size();
1439 CHECK_EQ(reason_index, bounds_reason_starts_.size());
1440 literals_reason_starts_.push_back(literals_reason_buffer_.size());
1441 bounds_reason_starts_.push_back(bounds_reason_buffer_.size());
1442 literals_reason_buffer_.push_back(literal_reason.Negated());
1444 const int prev_trail_index = vars_[i_lit.var].current_trail_index;
1445 integer_trail_.push_back({i_lit.bound,
1450 vars_[i_lit.var].current_bound = i_lit.bound;
1451 vars_[i_lit.var].current_trail_index = integer_trail_.size() - 1;
1455 void IntegerTrail::ComputeLazyReasonIfNeeded(
int trail_index)
const {
1456 const int reason_index = integer_trail_[trail_index].reason_index;
1457 if (reason_index == -1) {
1458 const TrailEntry& entry = integer_trail_[trail_index];
1459 const IntegerLiteral
literal(entry.var, entry.bound);
1460 lazy_reasons_[trail_index](
literal, trail_index, &lazy_reason_literals_,
1461 &lazy_reason_trail_indices_);
1465 absl::Span<const int> IntegerTrail::Dependencies(
int trail_index)
const {
1466 const int reason_index = integer_trail_[trail_index].reason_index;
1467 if (reason_index == -1) {
1468 return absl::Span<const int>(lazy_reason_trail_indices_);
1471 const int start = bounds_reason_starts_[reason_index];
1472 const int end = reason_index + 1 < bounds_reason_starts_.size()
1473 ? bounds_reason_starts_[reason_index + 1]
1474 : bounds_reason_buffer_.size();
1475 if (start == end)
return {};
1482 if (end > trail_index_reason_buffer_.size()) {
1483 trail_index_reason_buffer_.resize(end, -1);
1485 if (trail_index_reason_buffer_[start] == -1) {
1486 int new_end = start;
1487 const int num_vars = vars_.
size();
1488 for (
int i = start; i < end; ++i) {
1490 FindLowestTrailIndexThatExplainBound(bounds_reason_buffer_[i]);
1491 if (dep >= num_vars) {
1492 trail_index_reason_buffer_[new_end++] = dep;
1495 return absl::Span<const int>(&trail_index_reason_buffer_[start],
1501 return absl::Span<const int>(&trail_index_reason_buffer_[start],
1506 void IntegerTrail::AppendLiteralsReason(
int trail_index,
1507 std::vector<Literal>* output)
const {
1509 const int reason_index = integer_trail_[trail_index].reason_index;
1510 if (reason_index == -1) {
1511 for (
const Literal l : lazy_reason_literals_) {
1512 if (!added_variables_[l.Variable()]) {
1513 added_variables_.
Set(l.Variable());
1514 output->push_back(l);
1520 const int start = literals_reason_starts_[reason_index];
1521 const int end = reason_index + 1 < literals_reason_starts_.size()
1522 ? literals_reason_starts_[reason_index + 1]
1523 : literals_reason_buffer_.size();
1524 for (
int i = start; i < end; ++i) {
1525 const Literal l = literals_reason_buffer_[i];
1526 if (!added_variables_[l.Variable()]) {
1527 added_variables_.
Set(l.Variable());
1528 output->push_back(l);
1534 std::vector<Literal> reason;
1542 std::vector<Literal>* output)
const {
1543 DCHECK(tmp_queue_.empty());
1544 const int num_vars = vars_.
size();
1546 const int trail_index = FindLowestTrailIndexThatExplainBound(
literal);
1550 if (trail_index >= num_vars) tmp_queue_.push_back(trail_index);
1552 return MergeReasonIntoInternal(output);
1557 void IntegerTrail::MergeReasonIntoInternal(std::vector<Literal>* output)
const {
1560 DCHECK(std::all_of(tmp_var_to_trail_index_in_queue_.
begin(),
1561 tmp_var_to_trail_index_in_queue_.
end(),
1562 [](
int v) { return v == 0; }));
1565 for (
const Literal l : *output) {
1566 added_variables_.
Set(l.Variable());
1571 for (
const int trail_index : tmp_queue_) {
1573 DCHECK_LT(trail_index, integer_trail_.size());
1574 const TrailEntry& entry = integer_trail_[trail_index];
1575 tmp_var_to_trail_index_in_queue_[entry.var] =
1576 std::max(tmp_var_to_trail_index_in_queue_[entry.var], trail_index);
1581 std::make_heap(tmp_queue_.begin(), tmp_queue_.end());
1586 tmp_to_clear_.clear();
1587 while (!tmp_queue_.empty()) {
1588 const int trail_index = tmp_queue_.front();
1589 const TrailEntry& entry = integer_trail_[trail_index];
1590 std::pop_heap(tmp_queue_.begin(), tmp_queue_.end());
1591 tmp_queue_.pop_back();
1596 if (tmp_var_to_trail_index_in_queue_[entry.var] != trail_index) {
1603 var_trail_index_cache_threshold_ = trail_index;
1608 const LiteralIndex associated_lit =
1610 IntegerVariable(entry.var), entry.bound));
1613 const int reason_index = integer_trail_[trail_index].reason_index;
1616 const int start = literals_reason_starts_[reason_index];
1617 const int end = reason_index + 1 < literals_reason_starts_.size()
1618 ? literals_reason_starts_[reason_index + 1]
1619 : literals_reason_buffer_.size();
1621 CHECK_EQ(literals_reason_buffer_[start],
1622 Literal(associated_lit).Negated());
1625 const int start = bounds_reason_starts_[reason_index];
1626 const int end = reason_index + 1 < bounds_reason_starts_.size()
1627 ? bounds_reason_starts_[reason_index + 1]
1628 : bounds_reason_buffer_.size();
1642 tmp_var_to_trail_index_in_queue_[entry.var] = 0;
1643 has_dependency_ =
false;
1645 ComputeLazyReasonIfNeeded(trail_index);
1646 AppendLiteralsReason(trail_index, output);
1647 for (
const int next_trail_index : Dependencies(trail_index)) {
1648 if (next_trail_index < 0)
break;
1649 DCHECK_LT(next_trail_index, trail_index);
1650 const TrailEntry& next_entry = integer_trail_[next_trail_index];
1656 const int index_in_queue =
1657 tmp_var_to_trail_index_in_queue_[next_entry.var];
1658 if (index_in_queue !=
kint32max) has_dependency_ =
true;
1659 if (next_trail_index > index_in_queue) {
1660 tmp_var_to_trail_index_in_queue_[next_entry.var] = next_trail_index;
1662 std::push_heap(tmp_queue_.begin(), tmp_queue_.end());
1667 if (!has_dependency_) {
1668 tmp_to_clear_.push_back(entry.var);
1669 tmp_var_to_trail_index_in_queue_[entry.var] =
kint32max;
1674 for (
const IntegerVariable
var : tmp_to_clear_) {
1675 tmp_var_to_trail_index_in_queue_[
var] = 0;
1680 int trail_index)
const {
1681 const int index = boolean_trail_index_to_integer_one_[trail_index];
1685 ComputeLazyReasonIfNeeded(
index);
1686 AppendLiteralsReason(
index, reason);
1687 DCHECK(tmp_queue_.empty());
1688 for (
const int prev_trail_index : Dependencies(
index)) {
1689 if (prev_trail_index < 0)
break;
1691 tmp_queue_.push_back(prev_trail_index);
1693 MergeReasonIntoInternal(reason);
1703 const int end = vars_.
size();
1704 for (
int i = integer_trail_.size(); --i >= end;) {
1705 const TrailEntry& entry = integer_trail_[i];
1707 if (tmp_marked_[entry.var])
continue;
1709 tmp_marked_.
Set(entry.var);
1726 &id_to_greatest_common_level_since_last_call_);
1728 queue_by_priority_.resize(2);
1731 void GenericLiteralWatcher::UpdateCallingNeeds(
Trail* trail) {
1733 while (propagation_trail_index_ < trail->
Index()) {
1735 if (
literal.Index() >= literal_to_watcher_.
size())
continue;
1736 for (
const auto entry : literal_to_watcher_[
literal.Index()]) {
1737 if (!in_queue_[entry.id]) {
1738 in_queue_[entry.id] =
true;
1739 queue_by_priority_[id_to_priority_[entry.id]].push_back(entry.id);
1741 if (entry.watch_index >= 0) {
1742 id_to_watch_indices_[entry.id].push_back(entry.watch_index);
1749 if (
var.value() >= var_to_watcher_.
size())
continue;
1750 for (
const auto entry : var_to_watcher_[
var]) {
1751 if (!in_queue_[entry.id]) {
1752 in_queue_[entry.id] =
true;
1753 queue_by_priority_[id_to_priority_[entry.id]].push_back(entry.id);
1755 if (entry.watch_index >= 0) {
1756 id_to_watch_indices_[entry.id].push_back(entry.watch_index);
1762 const std::vector<IntegerVariable>& modified_vars =
1764 for (
const auto&
callback : level_zero_modified_variable_callback_) {
1777 for (
const int id : propagator_ids_to_call_at_level_zero_) {
1778 if (in_queue_[
id])
continue;
1779 in_queue_[id] =
true;
1780 queue_by_priority_[id_to_priority_[id]].push_back(
id);
1784 UpdateCallingNeeds(trail);
1789 for (
int priority = 0; priority < queue_by_priority_.size(); ++priority) {
1796 if (test_limit > 100) {
1801 std::deque<int>& queue = queue_by_priority_[priority];
1802 while (!queue.empty()) {
1803 const int id = queue.front();
1811 id_to_greatest_common_level_since_last_call_[IdType(
id)];
1812 const int high = id_to_level_at_last_call_[id];
1813 if (low < high || level > low) {
1814 id_to_level_at_last_call_[id] = level;
1815 id_to_greatest_common_level_since_last_call_.
MutableRef(IdType(
id)) =
1818 if (low < high) rev->SetLevel(low);
1819 if (level > low) rev->SetLevel(level);
1821 for (
int* rev_int : id_to_reversible_ints_[
id]) {
1822 rev_int_repository_->
SaveState(rev_int);
1829 const int64 old_boolean_timestamp = trail->
Index();
1832 std::vector<int>& watch_indices_ref = id_to_watch_indices_[id];
1834 watch_indices_ref.empty()
1835 ? watchers_[id]->Propagate()
1836 : watchers_[id]->IncrementalPropagate(watch_indices_ref);
1838 watch_indices_ref.clear();
1839 in_queue_[id] =
false;
1845 if (id_to_idempotence_[
id]) {
1849 UpdateCallingNeeds(trail);
1850 watch_indices_ref.clear();
1851 in_queue_[id] =
false;
1856 watch_indices_ref.clear();
1857 in_queue_[id] =
false;
1858 UpdateCallingNeeds(trail);
1864 if (trail->
Index() > old_boolean_timestamp) {
1876 if (integer_trail_->
num_enqueues() > old_integer_timestamp) {
1894 for (std::deque<int>& queue : queue_by_priority_) {
1895 for (
const int id : queue) {
1896 id_to_watch_indices_[id].clear();
1906 in_queue_.assign(watchers_.size(),
false);
1911 const int id = watchers_.size();
1912 watchers_.push_back(propagator);
1913 id_to_level_at_last_call_.push_back(0);
1914 id_to_greatest_common_level_since_last_call_.
GrowByOne();
1915 id_to_reversible_classes_.push_back(std::vector<ReversibleInterface*>());
1916 id_to_reversible_ints_.push_back(std::vector<int*>());
1917 id_to_watch_indices_.push_back(std::vector<int>());
1918 id_to_priority_.push_back(1);
1919 id_to_idempotence_.push_back(
true);
1928 in_queue_.push_back(
true);
1929 queue_by_priority_[1].push_back(
id);
1934 id_to_priority_[id] = priority;
1935 if (priority >= queue_by_priority_.size()) {
1936 queue_by_priority_.resize(priority + 1);
1942 id_to_idempotence_[id] =
false;
1946 propagator_ids_to_call_at_level_zero_.push_back(
id);
1951 id_to_reversible_classes_[id].push_back(rev);
1955 id_to_reversible_ints_[id].push_back(rev);
1959 std::function<void(
Model*)>
1967 std::vector<Literal> clause_to_exclude_solution;
1968 clause_to_exclude_solution.reserve(current_level);
1969 for (
int i = 0; i < current_level; ++i) {
1970 bool include_decision =
true;
1976 encoder->GetIntegerLiterals(decision);
1978 if (integer_trail->IsCurrentlyIgnored(
bound.var)) {
1984 clause_to_exclude_solution.push_back(
1985 integer_trail->IsIgnoredLiteral(
bound.var).Negated());
1986 include_decision =
false;
1990 if (include_decision) {
1991 clause_to_exclude_solution.push_back(decision.
Negated());