18 #include <type_traits>
43 const std::vector<IntegerVariable>& vars) {
44 std::vector<IntegerVariable> result(vars.size());
45 for (
int i = 0; i < vars.size(); ++i) {
55 CHECK(!(*domains_)[
var].IsEmpty());
56 CHECK_LT((*domains_)[
var].Size(), 100000)
57 <<
"Domain too large for full encoding.";
70 tmp_values_.push_back(v);
73 for (
const IntegerValue v : tmp_values_) {
85 if (
index >= is_fully_encoded_.
size())
return false;
88 if (is_fully_encoded_[
index])
return true;
95 const int64 initial_domain_size = (*domains_)[
var].Size();
96 if (equality_by_var_[
index].size() < initial_domain_size)
return false;
105 const auto& ref = equality_by_var_[
index];
109 if (i < ref.size() && v == ref[i].value) {
114 if (i == ref.size()) {
115 is_fully_encoded_[
index] =
true;
117 return is_fully_encoded_[
index];
120 std::vector<IntegerEncoder::ValueLiteralPair>
126 std::vector<IntegerEncoder::ValueLiteralPair>
130 if (
index >= equality_by_var_.size())
return {};
133 std::vector<ValueLiteralPair>& ref = equality_by_var_[
index];
134 for (
int i = 0; i < ref.size(); ++i) {
143 ref[new_size++] = pair;
145 ref.resize(new_size);
146 std::sort(ref.begin(), ref.end());
148 std::vector<IntegerEncoder::ValueLiteralPair> result = ref;
150 std::reverse(result.begin(), result.end());
159 void IntegerEncoder::AddImplications(
160 const std::map<IntegerValue, Literal>& map,
161 std::map<IntegerValue, Literal>::const_iterator it,
163 if (!add_implications_)
return;
164 DCHECK_EQ(it->second, associated_lit);
169 if (after_it != map.end()) {
171 {after_it->second.Negated(), associated_lit});
175 if (it != map.begin()) {
179 {associated_lit.
Negated(), before_it->second});
185 add_implications_ =
true;
186 for (
const std::map<IntegerValue, Literal>& encoding : encoding_by_var_) {
188 for (
const auto value_literal : encoding) {
189 const Literal lit = value_literal.second;
194 previous = lit.
Index();
201 const IntegerVariable
var(i_lit.
var);
202 IntegerValue after(i_lit.
bound);
203 IntegerValue before(i_lit.
bound - 1);
204 CHECK_GE(before, (*domains_)[
var].Min());
205 CHECK_LE(after, (*domains_)[
var].Max());
208 if (before > previous && before <
interval.start) before = previous;
218 if (i_lit.
bound <= (*domains_)[i_lit.
var].Min()) {
221 if (i_lit.
bound > (*domains_)[i_lit.
var].Max()) {
233 ++num_created_variables_;
240 VLOG(1) <<
"Created a fixed literal for no reason!";
246 std::pair<PositiveOnlyIndex, IntegerValue> PositiveVarKey(IntegerVariable
var,
247 IntegerValue
value) {
254 IntegerVariable
var, IntegerValue
value)
const {
256 equality_to_associated_literal_.find(PositiveVarKey(
var,
value));
257 if (it != equality_to_associated_literal_.end()) {
258 return it->second.Index();
264 IntegerVariable
var, IntegerValue
value) {
267 equality_to_associated_literal_.find(PositiveVarKey(
var,
value));
268 if (it != equality_to_associated_literal_.end()) {
282 ++num_created_variables_;
292 VLOG(1) <<
"Created a fixed literal for no reason!";
299 const auto& domain = (*domains_)[i_lit.
var];
300 const IntegerValue
min(domain.Min());
301 const IntegerValue
max(domain.Max());
308 HalfAssociateGivenLiteral(pair.first,
literal);
309 HalfAssociateGivenLiteral(pair.second,
literal.Negated());
314 if (pair.first.bound ==
max) {
317 if (-pair.second.bound ==
min) {
325 IntegerValue
value) {
330 if (
value == 1 && domain.
Min() >= 0 && domain.
Max() <= 1) {
338 if (
value == -1 && domain.
Min() >= -1 && domain.
Max() <= 0) {
349 const auto insert_result = equality_to_associated_literal_.insert(
351 if (!insert_result.second) {
372 if (
index >= equality_by_var_.size()) {
373 equality_by_var_.resize(
index.value() + 1);
376 equality_by_var_[
index].push_back(
411 const int new_size = 1 +
literal.Index().value();
412 if (new_size > full_reverse_encoding_.
size()) {
413 full_reverse_encoding_.
resize(new_size);
423 void IntegerEncoder::HalfAssociateGivenLiteral(
IntegerLiteral i_lit,
426 const int new_size = 1 +
literal.Index().value();
427 if (new_size > reverse_encoding_.
size()) {
428 reverse_encoding_.
resize(new_size);
430 if (new_size > full_reverse_encoding_.
size()) {
431 full_reverse_encoding_.
resize(new_size);
435 if (i_lit.
var >= encoding_by_var_.size()) {
436 encoding_by_var_.resize(i_lit.
var.value() + 1);
438 auto& var_encoding = encoding_by_var_[i_lit.
var];
439 auto insert_result = var_encoding.insert({i_lit.
bound,
literal});
440 if (insert_result.second) {
441 AddImplications(var_encoding, insert_result.first,
literal);
444 newly_fixed_integer_literals_.push_back(i_lit);
452 const Literal associated(insert_result.first->second);
462 if (i.
var >= encoding_by_var_.size())
return false;
463 const std::map<IntegerValue, Literal>& encoding = encoding_by_var_[i.
var];
464 return encoding.find(i.
bound) != encoding.end();
469 const std::map<IntegerValue, Literal>& encoding = encoding_by_var_[i.
var];
470 const auto result = encoding.find(i.
bound);
472 return result->second.Index();
480 const std::map<IntegerValue, Literal>& encoding = encoding_by_var_[i.
var];
481 auto after_it = encoding.upper_bound(i.
bound);
484 *
bound = after_it->first;
485 return after_it->second.Index();
489 if (parameters_.log_search_progress() && num_decisions_to_break_loop_ > 0) {
490 LOG(INFO) <<
"Num decisions to break propagation loop: "
491 << num_decisions_to_break_loop_;
502 if (level > integer_search_levels_.size()) {
503 integer_search_levels_.push_back(integer_trail_.size());
504 reason_decision_levels_.push_back(literals_reason_starts_.size());
510 var_to_current_lb_interval_index_.
SetLevel(level);
523 if (!
Enqueue(i_lit, {}, {}))
return false;
530 while (propagation_trail_index_ < trail->
Index()) {
536 if (!EnqueueAssociatedIntegerLiteral(i_lit,
literal)) {
549 var_to_current_lb_interval_index_.
SetLevel(level);
553 if (level < first_level_without_full_propagation_) {
554 first_level_without_full_propagation_ = -1;
559 if (level >= integer_search_levels_.size())
return;
560 const int target = integer_search_levels_[level];
561 integer_search_levels_.resize(level);
562 CHECK_GE(target, vars_.
size());
563 CHECK_LE(target, integer_trail_.size());
565 for (
int index = integer_trail_.size() - 1;
index >= target; --
index) {
566 const TrailEntry& entry = integer_trail_[
index];
567 if (entry.var < 0)
continue;
568 vars_[entry.var].current_trail_index = entry.prev_trail_index;
569 vars_[entry.var].current_bound =
570 integer_trail_[entry.prev_trail_index].bound;
572 integer_trail_.resize(target);
575 const int old_size = reason_decision_levels_[level];
576 reason_decision_levels_.resize(level);
577 if (old_size < literals_reason_starts_.size()) {
578 literals_reason_buffer_.resize(literals_reason_starts_[old_size]);
580 const int bound_start = bounds_reason_starts_[old_size];
581 bounds_reason_buffer_.resize(bound_start);
582 if (bound_start < trail_index_reason_buffer_.size()) {
583 trail_index_reason_buffer_.resize(bound_start);
586 literals_reason_starts_.resize(old_size);
587 bounds_reason_starts_.resize(old_size);
593 const int size = 2 * num_vars;
595 is_ignored_literals_.
reserve(size);
596 integer_trail_.reserve(size);
598 var_trail_index_cache_.
reserve(size);
599 tmp_var_to_trail_index_in_queue_.
reserve(size);
603 IntegerValue upper_bound) {
605 DCHECK_LE(lower_bound, upper_bound);
607 DCHECK(lower_bound >= 0 || lower_bound +
kint64max >= upper_bound);
608 DCHECK(integer_search_levels_.empty());
609 DCHECK_EQ(vars_.
size(), integer_trail_.size());
611 const IntegerVariable i(vars_.
size());
613 vars_.
push_back({lower_bound,
static_cast<int>(integer_trail_.size())});
614 integer_trail_.push_back({lower_bound, i});
622 vars_.
push_back({-upper_bound,
static_cast<int>(integer_trail_.size())});
623 integer_trail_.push_back({-upper_bound,
NegationOf(i)});
624 domains_->
push_back(
Domain(-upper_bound.value(), -lower_bound.value()));
626 var_trail_index_cache_.
resize(vars_.
size(), integer_trail_.size());
627 tmp_var_to_trail_index_in_queue_.
resize(vars_.
size(), 0);
638 IntegerValue(domain.
Max()));
644 return (*domains_)[
var];
652 if (old_domain == domain)
return true;
654 if (domain.
IsEmpty())
return false;
655 (*domains_)[
var] = domain;
658 var_to_current_lb_interval_index_.
Set(
var, 0);
677 if (i == domain.
NumIntervals() || pair.value < domain[i].start) {
687 <<
"Domain intersection fixed " << num_fixed
688 <<
" equality literal corresponding to values outside the new domain.";
695 IntegerValue
value) {
699 insert.first->second = new_var;
706 return insert.first->second;
712 return (constant_map_.size() + 1) / 2;
716 int threshold)
const {
720 const int index_in_queue = tmp_var_to_trail_index_in_queue_[
var];
721 if (threshold <= index_in_queue) {
722 if (index_in_queue !=
kint32max) has_dependency_ =
true;
726 DCHECK_GE(threshold, vars_.
size());
727 int trail_index = vars_[
var].current_trail_index;
730 if (trail_index > threshold) {
731 const int cached_index = var_trail_index_cache_[
var];
732 if (cached_index >= threshold && cached_index < trail_index &&
733 integer_trail_[cached_index].
var ==
var) {
734 trail_index = cached_index;
738 while (trail_index >= threshold) {
739 trail_index = integer_trail_[trail_index].prev_trail_index;
740 if (trail_index >= var_trail_index_cache_threshold_) {
741 var_trail_index_cache_[
var] = trail_index;
745 const int num_vars = vars_.
size();
746 return trail_index < num_vars ? -1 : trail_index;
749 int IntegerTrail::FindLowestTrailIndexThatExplainBound(
751 DCHECK_LE(i_lit.
bound, vars_[i_lit.
var].current_bound);
753 int trail_index = vars_[i_lit.
var].current_trail_index;
761 const int cached_index = var_trail_index_cache_[i_lit.
var];
762 if (cached_index < trail_index) {
763 const TrailEntry& entry = integer_trail_[cached_index];
764 if (entry.var == i_lit.
var && entry.bound >= i_lit.
bound) {
765 trail_index = cached_index;
770 int prev_trail_index = trail_index;
772 if (trail_index >= var_trail_index_cache_threshold_) {
773 var_trail_index_cache_[i_lit.
var] = trail_index;
775 const TrailEntry& entry = integer_trail_[trail_index];
776 if (entry.bound == i_lit.
bound)
return trail_index;
777 if (entry.bound < i_lit.
bound)
return prev_trail_index;
778 prev_trail_index = trail_index;
779 trail_index = entry.prev_trail_index;
785 IntegerValue slack, absl::Span<const IntegerValue> coeffs,
786 std::vector<IntegerLiteral>* reason)
const {
788 if (slack == 0)
return;
789 const int size = reason->size();
790 tmp_indices_.resize(size);
791 for (
int i = 0; i < size; ++i) {
793 CHECK_GE(coeffs[i], 0);
794 tmp_indices_[i] = vars_[(*reason)[i].var].current_trail_index;
800 for (
const int i : tmp_indices_) {
802 integer_trail_[i].
bound));
807 IntegerValue slack, absl::Span<const IntegerValue> coeffs,
808 absl::Span<const IntegerVariable> vars,
809 std::vector<IntegerLiteral>* reason)
const {
810 tmp_indices_.clear();
811 for (
const IntegerVariable
var : vars) {
812 tmp_indices_.push_back(vars_[
var].current_trail_index);
815 for (
const int i : tmp_indices_) {
817 integer_trail_[i].
bound));
822 absl::Span<const IntegerValue> coeffs,
823 std::vector<int>* trail_indices)
const {
825 DCHECK(relax_heap_.empty());
832 const int size = coeffs.size();
833 const int num_vars = vars_.
size();
834 for (
int i = 0; i < size; ++i) {
835 const int index = (*trail_indices)[i];
838 if (
index < num_vars)
continue;
841 const IntegerValue coeff = coeffs[i];
843 (*trail_indices)[new_size++] =
index;
850 const TrailEntry& entry = integer_trail_[
index];
852 index <= tmp_var_to_trail_index_in_queue_[entry.var]) {
853 (*trail_indices)[new_size++] =
index;
858 const TrailEntry& previous_entry = integer_trail_[entry.prev_trail_index];
860 CapProd(coeff.value(), (entry.bound - previous_entry.bound).value());
862 (*trail_indices)[new_size++] =
index;
866 relax_heap_.push_back({
index, coeff, diff});
868 trail_indices->resize(new_size);
869 std::make_heap(relax_heap_.begin(), relax_heap_.end());
871 while (slack > 0 && !relax_heap_.empty()) {
872 const RelaxHeapEntry heap_entry = relax_heap_.front();
873 std::pop_heap(relax_heap_.begin(), relax_heap_.end());
874 relax_heap_.pop_back();
877 if (heap_entry.diff > slack) {
878 trail_indices->push_back(heap_entry.index);
883 slack -= heap_entry.diff;
884 const int index = integer_trail_[heap_entry.index].prev_trail_index;
887 if (
index < num_vars)
continue;
888 if (heap_entry.coeff > slack) {
889 trail_indices->push_back(
index);
892 const TrailEntry& entry = integer_trail_[
index];
894 index <= tmp_var_to_trail_index_in_queue_[entry.var]) {
895 trail_indices->push_back(
index);
899 const TrailEntry& previous_entry = integer_trail_[entry.prev_trail_index];
901 (entry.bound - previous_entry.bound).value());
903 trail_indices->push_back(
index);
906 relax_heap_.push_back({
index, heap_entry.coeff, diff});
907 std::push_heap(relax_heap_.begin(), relax_heap_.end());
912 for (
const RelaxHeapEntry& entry : relax_heap_) {
913 trail_indices->push_back(entry.index);
919 std::vector<IntegerLiteral>* reason)
const {
923 (*reason)[new_size++] =
literal;
925 reason->resize(new_size);
928 std::vector<Literal>* IntegerTrail::InitializeConflict(
929 IntegerLiteral integer_literal,
const LazyReasonFunction& lazy_reason,
930 absl::Span<const Literal> literals_reason,
931 absl::Span<const IntegerLiteral> bounds_reason) {
932 DCHECK(tmp_queue_.empty());
934 if (lazy_reason ==
nullptr) {
935 conflict->assign(literals_reason.begin(), literals_reason.end());
936 const int num_vars = vars_.
size();
938 const int trail_index = FindLowestTrailIndexThatExplainBound(
literal);
939 if (trail_index >= num_vars) tmp_queue_.push_back(trail_index);
944 lazy_reason(integer_literal, integer_trail_.size(), conflict, &tmp_queue_);
951 std::string ReasonDebugString(absl::Span<const Literal> literal_reason,
952 absl::Span<const IntegerLiteral> integer_reason) {
953 std::string result =
"literals:{";
954 for (
const Literal l : literal_reason) {
955 if (result.back() !=
'{') result +=
",";
956 result += l.DebugString();
958 result +=
"} bounds:{";
959 for (
const IntegerLiteral l : integer_reason) {
960 if (result.back() !=
'{') result +=
",";
961 result += l.DebugString();
969 std::string IntegerTrail::DebugString() {
970 std::string result =
"trail:{";
971 const int num_vars = vars_.
size();
973 std::min(num_vars + 30,
static_cast<int>(integer_trail_.size()));
974 for (
int i = num_vars; i < limit; ++i) {
975 if (result.back() !=
'{') result +=
",";
978 integer_trail_[i].
bound)
981 if (limit < integer_trail_.size()) {
989 absl::Span<const Literal> literal_reason,
990 absl::Span<const IntegerLiteral> integer_reason) {
991 return EnqueueInternal(i_lit,
nullptr, literal_reason, integer_reason,
992 integer_trail_.size());
996 absl::Span<const Literal> literal_reason,
997 absl::Span<const IntegerLiteral> integer_reason,
998 int trail_index_with_same_reason) {
999 return EnqueueInternal(i_lit,
nullptr, literal_reason, integer_reason,
1000 trail_index_with_same_reason);
1005 return EnqueueInternal(i_lit, lazy_reason, {}, {}, integer_trail_.size());
1008 bool IntegerTrail::ReasonIsValid(
1009 absl::Span<const Literal> literal_reason,
1010 absl::Span<const IntegerLiteral> integer_reason) {
1012 for (
const Literal lit : literal_reason) {
1015 for (
const IntegerLiteral i_lit : integer_reason) {
1016 if (i_lit.
bound > vars_[i_lit.
var].current_bound) {
1019 LOG(INFO) <<
"Reason " << i_lit <<
" is not true!"
1020 <<
" optional variable:" << i_lit.
var
1023 <<
" current_lb:" << vars_[i_lit.
var].current_bound;
1025 LOG(INFO) <<
"Reason " << i_lit <<
" is not true!"
1026 <<
" non-optional variable:" << i_lit.
var
1027 <<
" current_lb:" << vars_[i_lit.
var].current_bound;
1035 if (!integer_search_levels_.empty()) {
1036 int num_literal_assigned_after_root_node = 0;
1037 for (
const Literal lit : literal_reason) {
1038 if (trail_->
Info(lit.Variable()).
level > 0) {
1039 num_literal_assigned_after_root_node++;
1042 for (
const IntegerLiteral i_lit : integer_reason) {
1044 num_literal_assigned_after_root_node++;
1047 DLOG_IF(INFO, num_literal_assigned_after_root_node == 0)
1048 <<
"Propagating a literal with no reason at a positive level!\n"
1049 <<
"level:" << integer_search_levels_.size() <<
" "
1050 << ReasonDebugString(literal_reason, integer_reason) <<
"\n"
1059 absl::Span<const IntegerLiteral> integer_reason) {
1060 EnqueueLiteralInternal(
literal,
nullptr, literal_reason, integer_reason);
1063 void IntegerTrail::EnqueueLiteralInternal(
1065 absl::Span<const Literal> literal_reason,
1066 absl::Span<const IntegerLiteral> integer_reason) {
1068 DCHECK(lazy_reason !=
nullptr ||
1069 ReasonIsValid(literal_reason, integer_reason));
1070 if (integer_search_levels_.empty()) {
1076 const int trail_index = trail_->
Index();
1077 if (trail_index >= boolean_trail_index_to_integer_one_.size()) {
1078 boolean_trail_index_to_integer_one_.resize(trail_index + 1);
1080 boolean_trail_index_to_integer_one_[trail_index] = integer_trail_.size();
1082 int reason_index = literals_reason_starts_.size();
1083 if (lazy_reason !=
nullptr) {
1084 if (integer_trail_.size() >= lazy_reasons_.size()) {
1085 lazy_reasons_.resize(integer_trail_.size() + 1,
nullptr);
1087 lazy_reasons_[integer_trail_.size()] = lazy_reason;
1091 literals_reason_starts_.push_back(literals_reason_buffer_.size());
1092 literals_reason_buffer_.insert(literals_reason_buffer_.end(),
1093 literal_reason.begin(),
1094 literal_reason.end());
1095 bounds_reason_starts_.push_back(bounds_reason_buffer_.size());
1096 bounds_reason_buffer_.insert(bounds_reason_buffer_.end(),
1097 integer_reason.begin(), integer_reason.end());
1100 integer_trail_.push_back({IntegerValue(0),
1112 const int num_vars = vars_.
size();
1113 return (!integer_search_levels_.empty() &&
1114 integer_trail_.size() - integer_search_levels_.back() >
1116 parameters_.search_branching() != SatParameters::FIXED_SEARCH);
1123 ++num_decisions_to_break_loop_;
1124 std::vector<IntegerVariable> vars;
1125 for (
int i = integer_search_levels_.back(); i < integer_trail_.size(); ++i) {
1126 const IntegerVariable
var = integer_trail_[i].var;
1129 vars.push_back(
var);
1132 std::sort(vars.begin(), vars.end());
1133 IntegerVariable best_var = vars[0];
1136 for (
int i = 1; i < vars.size(); ++i) {
1137 if (vars[i] != vars[i - 1]) {
1141 if (count > best_count) {
1151 return first_level_without_full_propagation_ != -1;
1155 for (IntegerVariable
var(0);
var < vars_.
size();
var += 2) {
1162 bool IntegerTrail::EnqueueInternal(
1164 absl::Span<const Literal> literal_reason,
1165 absl::Span<const IntegerLiteral> integer_reason,
1166 int trail_index_with_same_reason) {
1167 DCHECK(lazy_reason !=
nullptr ||
1168 ReasonIsValid(literal_reason, integer_reason));
1170 const IntegerVariable
var(i_lit.
var);
1178 if (i_lit.
bound <= vars_[
var].current_bound)
return true;
1187 if ((*domains_)[
var].NumIntervals() > 1) {
1188 const auto& domain = (*domains_)[
var];
1190 const int size = domain.NumIntervals();
1191 while (index < size && i_lit.bound > domain[
index].end) {
1194 if (
index == size) {
1197 var_to_current_lb_interval_index_.
Set(
var,
index);
1208 Literal(is_ignored_literals_[
var]))) {
1211 auto* conflict = InitializeConflict(i_lit, lazy_reason, literal_reason,
1214 conflict->push_back(Literal(is_ignored_literals_[
var]));
1217 const int trail_index = FindLowestTrailIndexThatExplainBound(ub_reason);
1218 const int num_vars = vars_.
size();
1219 if (trail_index >= num_vars) tmp_queue_.push_back(trail_index);
1221 MergeReasonIntoInternal(conflict);
1228 const Literal is_ignored = Literal(is_ignored_literals_[
var]);
1229 if (integer_search_levels_.empty()) {
1236 if (lazy_reason !=
nullptr) {
1237 lazy_reason(i_lit, integer_trail_.size(), &lazy_reason_literals_,
1238 &lazy_reason_trail_indices_);
1239 std::vector<IntegerLiteral> temp;
1240 for (
const int trail_index : lazy_reason_trail_indices_) {
1241 const TrailEntry& entry = integer_trail_[trail_index];
1242 temp.push_back(IntegerLiteral(entry.var, entry.bound));
1250 bounds_reason_buffer_.push_back(ub_reason);
1270 if (i_lit.
bound - lb < (ub - lb) / 2) {
1271 if (first_level_without_full_propagation_ == -1) {
1279 for (SparseBitset<IntegerVariable>* bitset : watchers_) {
1280 bitset->Set(i_lit.
var);
1296 const LiteralIndex literal_index =
1299 const Literal to_enqueue = Literal(literal_index);
1301 auto* conflict = InitializeConflict(i_lit, lazy_reason, literal_reason,
1303 conflict->push_back(to_enqueue);
1304 MergeReasonIntoInternal(conflict);
1314 EnqueueLiteralInternal(to_enqueue, lazy_reason, literal_reason,
1317 return EnqueueAssociatedIntegerLiteral(i_lit, to_enqueue);
1321 if (integer_search_levels_.empty()) {
1327 const int trail_index = trail_->
Index();
1328 if (trail_index >= boolean_trail_index_to_integer_one_.size()) {
1329 boolean_trail_index_to_integer_one_.resize(trail_index + 1);
1331 boolean_trail_index_to_integer_one_[trail_index] =
1332 trail_index_with_same_reason;
1339 if (integer_search_levels_.empty()) {
1340 ++num_level_zero_enqueues_;
1341 vars_[i_lit.
var].current_bound = i_lit.
bound;
1342 integer_trail_[i_lit.
var.value()].bound = i_lit.
bound;
1353 int reason_index = literals_reason_starts_.size();
1354 if (lazy_reason !=
nullptr) {
1355 if (integer_trail_.size() >= lazy_reasons_.size()) {
1356 lazy_reasons_.resize(integer_trail_.size() + 1,
nullptr);
1358 lazy_reasons_[integer_trail_.size()] = lazy_reason;
1360 }
else if (trail_index_with_same_reason >= integer_trail_.size()) {
1362 literals_reason_starts_.push_back(literals_reason_buffer_.size());
1363 if (!literal_reason.empty()) {
1364 literals_reason_buffer_.insert(literals_reason_buffer_.end(),
1365 literal_reason.begin(),
1366 literal_reason.end());
1368 bounds_reason_starts_.push_back(bounds_reason_buffer_.size());
1369 if (!integer_reason.empty()) {
1370 bounds_reason_buffer_.insert(bounds_reason_buffer_.end(),
1371 integer_reason.begin(),
1372 integer_reason.end());
1375 reason_index = integer_trail_[trail_index_with_same_reason].reason_index;
1378 const int prev_trail_index = vars_[i_lit.
var].current_trail_index;
1379 integer_trail_.push_back({i_lit.
bound,
1384 vars_[i_lit.
var].current_bound = i_lit.
bound;
1385 vars_[i_lit.
var].current_trail_index = integer_trail_.size() - 1;
1389 bool IntegerTrail::EnqueueAssociatedIntegerLiteral(IntegerLiteral i_lit,
1390 Literal literal_reason) {
1391 DCHECK(ReasonIsValid({literal_reason.Negated()}, {}));
1395 if (i_lit.bound <= vars_[i_lit.var].current_bound)
return true;
1403 return Enqueue(i_lit, {literal_reason.Negated()}, {});
1407 for (SparseBitset<IntegerVariable>* bitset : watchers_) {
1408 bitset->Set(i_lit.var);
1412 if (integer_search_levels_.empty()) {
1413 vars_[i_lit.var].current_bound = i_lit.bound;
1414 integer_trail_[i_lit.var.value()].bound = i_lit.bound;
1425 const int reason_index = literals_reason_starts_.size();
1426 CHECK_EQ(reason_index, bounds_reason_starts_.size());
1427 literals_reason_starts_.push_back(literals_reason_buffer_.size());
1428 bounds_reason_starts_.push_back(bounds_reason_buffer_.size());
1429 literals_reason_buffer_.push_back(literal_reason.Negated());
1431 const int prev_trail_index = vars_[i_lit.var].current_trail_index;
1432 integer_trail_.push_back({i_lit.bound,
1437 vars_[i_lit.var].current_bound = i_lit.bound;
1438 vars_[i_lit.var].current_trail_index = integer_trail_.size() - 1;
1442 void IntegerTrail::ComputeLazyReasonIfNeeded(
int trail_index)
const {
1443 const int reason_index = integer_trail_[trail_index].reason_index;
1444 if (reason_index == -1) {
1445 const TrailEntry& entry = integer_trail_[trail_index];
1446 const IntegerLiteral
literal(entry.var, entry.bound);
1447 lazy_reasons_[trail_index](
literal, trail_index, &lazy_reason_literals_,
1448 &lazy_reason_trail_indices_);
1452 absl::Span<const int> IntegerTrail::Dependencies(
int trail_index)
const {
1453 const int reason_index = integer_trail_[trail_index].reason_index;
1454 if (reason_index == -1) {
1455 return absl::Span<const int>(lazy_reason_trail_indices_);
1458 const int start = bounds_reason_starts_[reason_index];
1459 const int end = reason_index + 1 < bounds_reason_starts_.size()
1460 ? bounds_reason_starts_[reason_index + 1]
1461 : bounds_reason_buffer_.size();
1462 if (start == end)
return {};
1469 if (end > trail_index_reason_buffer_.size()) {
1470 trail_index_reason_buffer_.resize(end, -1);
1472 if (trail_index_reason_buffer_[start] == -1) {
1473 int new_end = start;
1474 const int num_vars = vars_.
size();
1475 for (
int i = start; i < end; ++i) {
1477 FindLowestTrailIndexThatExplainBound(bounds_reason_buffer_[i]);
1478 if (dep >= num_vars) {
1479 trail_index_reason_buffer_[new_end++] = dep;
1482 return absl::Span<const int>(&trail_index_reason_buffer_[start],
1488 return absl::Span<const int>(&trail_index_reason_buffer_[start],
1493 void IntegerTrail::AppendLiteralsReason(
int trail_index,
1494 std::vector<Literal>* output)
const {
1495 CHECK_GE(trail_index, vars_.
size());
1496 const int reason_index = integer_trail_[trail_index].reason_index;
1497 if (reason_index == -1) {
1498 for (
const Literal l : lazy_reason_literals_) {
1499 if (!added_variables_[l.Variable()]) {
1500 added_variables_.
Set(l.Variable());
1501 output->push_back(l);
1507 const int start = literals_reason_starts_[reason_index];
1508 const int end = reason_index + 1 < literals_reason_starts_.size()
1509 ? literals_reason_starts_[reason_index + 1]
1510 : literals_reason_buffer_.size();
1511 for (
int i = start; i < end; ++i) {
1512 const Literal l = literals_reason_buffer_[i];
1513 if (!added_variables_[l.Variable()]) {
1514 added_variables_.
Set(l.Variable());
1515 output->push_back(l);
1521 std::vector<Literal> reason;
1529 std::vector<Literal>* output)
const {
1530 DCHECK(tmp_queue_.empty());
1531 const int num_vars = vars_.
size();
1533 const int trail_index = FindLowestTrailIndexThatExplainBound(
literal);
1537 if (trail_index >= num_vars) tmp_queue_.push_back(trail_index);
1539 return MergeReasonIntoInternal(output);
1544 void IntegerTrail::MergeReasonIntoInternal(std::vector<Literal>* output)
const {
1547 DCHECK(std::all_of(tmp_var_to_trail_index_in_queue_.
begin(),
1548 tmp_var_to_trail_index_in_queue_.
end(),
1549 [](
int v) { return v == 0; }));
1552 for (
const Literal l : *output) {
1553 added_variables_.
Set(l.Variable());
1558 for (
const int trail_index : tmp_queue_) {
1559 DCHECK_GE(trail_index, vars_.
size());
1560 DCHECK_LT(trail_index, integer_trail_.size());
1561 const TrailEntry& entry = integer_trail_[trail_index];
1562 tmp_var_to_trail_index_in_queue_[entry.var] =
1563 std::max(tmp_var_to_trail_index_in_queue_[entry.var], trail_index);
1568 std::make_heap(tmp_queue_.begin(), tmp_queue_.end());
1573 tmp_to_clear_.clear();
1574 while (!tmp_queue_.empty()) {
1575 const int trail_index = tmp_queue_.front();
1576 const TrailEntry& entry = integer_trail_[trail_index];
1577 std::pop_heap(tmp_queue_.begin(), tmp_queue_.end());
1578 tmp_queue_.pop_back();
1583 if (tmp_var_to_trail_index_in_queue_[entry.var] != trail_index) {
1590 var_trail_index_cache_threshold_ = trail_index;
1595 const LiteralIndex associated_lit =
1597 IntegerVariable(entry.var), entry.bound));
1600 const int reason_index = integer_trail_[trail_index].reason_index;
1601 CHECK_NE(reason_index, -1);
1603 const int start = literals_reason_starts_[reason_index];
1604 const int end = reason_index + 1 < literals_reason_starts_.size()
1605 ? literals_reason_starts_[reason_index + 1]
1606 : literals_reason_buffer_.size();
1607 CHECK_EQ(start + 1, end);
1608 CHECK_EQ(literals_reason_buffer_[start],
1609 Literal(associated_lit).Negated());
1612 const int start = bounds_reason_starts_[reason_index];
1613 const int end = reason_index + 1 < bounds_reason_starts_.size()
1614 ? bounds_reason_starts_[reason_index + 1]
1615 : bounds_reason_buffer_.size();
1616 CHECK_EQ(start, end);
1629 tmp_var_to_trail_index_in_queue_[entry.var] = 0;
1630 has_dependency_ =
false;
1632 ComputeLazyReasonIfNeeded(trail_index);
1633 AppendLiteralsReason(trail_index, output);
1634 for (
const int next_trail_index : Dependencies(trail_index)) {
1635 if (next_trail_index < 0)
break;
1636 DCHECK_LT(next_trail_index, trail_index);
1637 const TrailEntry& next_entry = integer_trail_[next_trail_index];
1643 const int index_in_queue =
1644 tmp_var_to_trail_index_in_queue_[next_entry.var];
1645 if (index_in_queue !=
kint32max) has_dependency_ =
true;
1646 if (next_trail_index > index_in_queue) {
1647 tmp_var_to_trail_index_in_queue_[next_entry.var] = next_trail_index;
1649 std::push_heap(tmp_queue_.begin(), tmp_queue_.end());
1654 if (!has_dependency_) {
1655 tmp_to_clear_.push_back(entry.var);
1656 tmp_var_to_trail_index_in_queue_[entry.var] =
kint32max;
1661 for (
const IntegerVariable
var : tmp_to_clear_) {
1662 tmp_var_to_trail_index_in_queue_[
var] = 0;
1667 int trail_index)
const {
1668 const int index = boolean_trail_index_to_integer_one_[trail_index];
1672 ComputeLazyReasonIfNeeded(
index);
1673 AppendLiteralsReason(
index, reason);
1674 DCHECK(tmp_queue_.empty());
1675 for (
const int prev_trail_index : Dependencies(
index)) {
1676 if (prev_trail_index < 0)
break;
1677 DCHECK_GE(prev_trail_index, vars_.
size());
1678 tmp_queue_.push_back(prev_trail_index);
1680 MergeReasonIntoInternal(reason);
1690 const int end = vars_.
size();
1691 for (
int i = integer_trail_.size(); --i >= end;) {
1692 const TrailEntry& entry = integer_trail_[i];
1694 if (tmp_marked_[entry.var])
continue;
1696 tmp_marked_.
Set(entry.var);
1713 &id_to_greatest_common_level_since_last_call_);
1715 queue_by_priority_.resize(2);
1718 void GenericLiteralWatcher::UpdateCallingNeeds(
Trail* trail) {
1720 while (propagation_trail_index_ < trail->
Index()) {
1722 if (
literal.Index() >= literal_to_watcher_.
size())
continue;
1723 for (
const auto entry : literal_to_watcher_[
literal.Index()]) {
1724 if (!in_queue_[entry.id]) {
1725 in_queue_[entry.id] =
true;
1726 queue_by_priority_[id_to_priority_[entry.id]].push_back(entry.id);
1728 if (entry.watch_index >= 0) {
1729 id_to_watch_indices_[entry.id].push_back(entry.watch_index);
1736 if (
var.value() >= var_to_watcher_.
size())
continue;
1737 for (
const auto entry : var_to_watcher_[
var]) {
1738 if (!in_queue_[entry.id]) {
1739 in_queue_[entry.id] =
true;
1740 queue_by_priority_[id_to_priority_[entry.id]].push_back(entry.id);
1742 if (entry.watch_index >= 0) {
1743 id_to_watch_indices_[entry.id].push_back(entry.watch_index);
1749 const std::vector<IntegerVariable>& modified_vars =
1751 for (
const auto&
callback : level_zero_modified_variable_callback_) {
1764 for (
const int id : propagator_ids_to_call_at_level_zero_) {
1765 if (in_queue_[
id])
continue;
1766 in_queue_[id] =
true;
1767 queue_by_priority_[id_to_priority_[id]].push_back(
id);
1771 UpdateCallingNeeds(trail);
1776 for (
int priority = 0; priority < queue_by_priority_.size(); ++priority) {
1783 if (test_limit > 100) {
1788 std::deque<int>& queue = queue_by_priority_[priority];
1789 while (!queue.empty()) {
1790 const int id = queue.front();
1798 id_to_greatest_common_level_since_last_call_[IdType(
id)];
1799 const int high = id_to_level_at_last_call_[id];
1800 if (low < high || level > low) {
1801 id_to_level_at_last_call_[id] = level;
1802 id_to_greatest_common_level_since_last_call_.
MutableRef(IdType(
id)) =
1805 if (low < high) rev->SetLevel(low);
1806 if (level > low) rev->SetLevel(level);
1808 for (
int* rev_int : id_to_reversible_ints_[
id]) {
1809 rev_int_repository_->
SaveState(rev_int);
1816 const int64 old_boolean_timestamp = trail->
Index();
1819 std::vector<int>& watch_indices_ref = id_to_watch_indices_[id];
1821 watch_indices_ref.empty()
1822 ? watchers_[id]->Propagate()
1823 : watchers_[id]->IncrementalPropagate(watch_indices_ref);
1825 watch_indices_ref.clear();
1826 in_queue_[id] =
false;
1832 if (id_to_idempotence_[
id]) {
1836 UpdateCallingNeeds(trail);
1837 watch_indices_ref.clear();
1838 in_queue_[id] =
false;
1843 watch_indices_ref.clear();
1844 in_queue_[id] =
false;
1845 UpdateCallingNeeds(trail);
1851 if (trail->
Index() > old_boolean_timestamp) {
1863 if (integer_trail_->
num_enqueues() > old_integer_timestamp) {
1881 for (std::deque<int>& queue : queue_by_priority_) {
1882 for (
const int id : queue) {
1883 id_to_watch_indices_[id].clear();
1893 in_queue_.assign(watchers_.size(),
false);
1898 const int id = watchers_.size();
1899 watchers_.push_back(propagator);
1900 id_to_level_at_last_call_.push_back(0);
1901 id_to_greatest_common_level_since_last_call_.
GrowByOne();
1902 id_to_reversible_classes_.push_back(std::vector<ReversibleInterface*>());
1903 id_to_reversible_ints_.push_back(std::vector<int*>());
1904 id_to_watch_indices_.push_back(std::vector<int>());
1905 id_to_priority_.push_back(1);
1906 id_to_idempotence_.push_back(
true);
1915 in_queue_.push_back(
true);
1916 queue_by_priority_[1].push_back(
id);
1921 id_to_priority_[id] = priority;
1922 if (priority >= queue_by_priority_.size()) {
1923 queue_by_priority_.resize(priority + 1);
1929 id_to_idempotence_[id] =
false;
1933 propagator_ids_to_call_at_level_zero_.push_back(
id);
1938 id_to_reversible_classes_[id].push_back(rev);
1942 id_to_reversible_ints_[id].push_back(rev);
1946 std::function<void(
Model*)>
1954 std::vector<Literal> clause_to_exclude_solution;
1955 clause_to_exclude_solution.reserve(current_level);
1956 for (
int i = 0; i < current_level; ++i) {
1957 bool include_decision =
true;
1963 encoder->GetIntegerLiterals(decision);
1965 if (integer_trail->IsCurrentlyIgnored(
bound.var)) {
1971 clause_to_exclude_solution.push_back(
1972 integer_trail->IsIgnoredLiteral(
bound.var).Negated());
1973 include_decision =
false;
1977 if (include_decision) {
1978 clause_to_exclude_solution.push_back(decision.
Negated());