26#include "absl/base/attributes.h"
27#include "absl/cleanup/cleanup.h"
28#include "absl/container/btree_map.h"
29#include "absl/container/flat_hash_map.h"
30#include "absl/container/inlined_vector.h"
31#include "absl/log/check.h"
32#include "absl/meta/type_traits.h"
33#include "absl/strings/str_cat.h"
34#include "absl/types/span.h"
39#include "ortools/sat/sat_parameters.pb.h"
52 const std::vector<IntegerVariable>& vars) {
53 std::vector<IntegerVariable> result(vars.size());
54 for (
int i = 0;
i < vars.size(); ++
i) {
62 ", value = ",
value.value(),
")");
74 encoding_by_var_.reserve(num_vars);
75 equality_to_associated_literal_.reserve(num_vars);
76 equality_by_var_.reserve(num_vars);
85 CHECK(!domains_[
index].IsEmpty());
86 CHECK_LT(domains_[
index].Size(), 100000)
87 <<
"Domain too large for full encoding.";
98 for (
const int64_t v : domains_[
index].Values()) {
99 tmp_values_.push_back(IntegerValue(v));
101 for (
const IntegerValue v : tmp_values_) {
112 if (
index >= is_fully_encoded_.size())
return false;
115 if (is_fully_encoded_[
index])
return true;
122 const int64_t initial_domain_size = domains_[
index].Size();
123 if (equality_by_var_[
index].
size() < initial_domain_size)
return false;
132 const auto& ref = equality_by_var_[
index];
134 for (
const int64_t v : domains_[
index].Values()) {
135 if (
i < ref.size() && v == ref[
i].value) {
139 if (
i == ref.size()) {
140 is_fully_encoded_[
index] =
true;
142 return is_fully_encoded_[
index];
146 IntegerVariable
var)
const {
152 IntegerVariable
var)
const {
154 if (
index >= equality_by_var_.size()) {
155 partial_encoding_.clear();
156 return partial_encoding_;
160 partial_encoding_.assign(equality_by_var_[
index].begin(),
162 for (
int i = 0;
i < partial_encoding_.size(); ++
i) {
166 partial_encoding_.clear();
167 partial_encoding_.push_back(pair);
171 partial_encoding_[new_size++] = pair;
173 partial_encoding_.resize(new_size);
174 std::sort(partial_encoding_.begin(), partial_encoding_.end(),
179 equality_by_var_[
index].assign(partial_encoding_.begin(),
180 partial_encoding_.end());
184 std::reverse(partial_encoding_.begin(), partial_encoding_.end());
187 return partial_encoding_;
193void IntegerEncoder::AddImplications(
194 const absl::btree_map<IntegerValue, Literal>& map,
195 absl::btree_map<IntegerValue, Literal>::const_iterator it,
197 if (!add_implications_)
return;
198 DCHECK_EQ(it->second, associated_lit);
203 if (it != map.begin()) {
206 before_index = before_it->second.Index();
212 if (after_it != map.end()) after_index = after_it->second.Index();
218 {Literal(after_index).Negated(), associated_lit});
222 {associated_lit.
Negated(), Literal(before_index)});
228 add_implications_ =
true;
232 const int num_vars = encoding_by_var_.size();
235 const IntegerVariable
var(2 *
index.value());
249 if (!positive) i_lit = i_lit.
Negated();
251 const IntegerVariable
var(i_lit.
var);
253 IntegerValue after(i_lit.
bound);
254 IntegerValue before(i_lit.
bound - 1);
255 DCHECK_GE(before, domains_[
index].Min());
256 DCHECK_LE(after, domains_[
index].Max());
257 int64_t previous = std::numeric_limits<int64_t>::min();
259 if (before > previous && before <
interval.start) before = previous;
297 ++num_created_variables_;
304 VLOG(1) <<
"Created a fixed literal for no reason!";
310std::pair<PositiveOnlyIndex, IntegerValue> PositiveVarKey(IntegerVariable
var,
311 IntegerValue
value) {
318 IntegerVariable
var, IntegerValue
value)
const {
320 equality_to_associated_literal_.find(PositiveVarKey(
var,
value));
321 if (it != equality_to_associated_literal_.end()) {
322 return it->second.Index();
328 IntegerVariable
var, IntegerValue
value) {
331 equality_to_associated_literal_.find(PositiveVarKey(
var,
value));
332 if (it != equality_to_associated_literal_.end()) {
349 ++num_created_variables_;
359 VLOG(1) <<
"Created a fixed literal for no reason!";
374 const IntegerValue
min(domain.
Min());
375 const IntegerValue
max(domain.
Max());
383 if (
index >= encoding_by_var_.size()) {
384 encoding_by_var_.resize(
index.value() + 1);
386 auto& var_encoding = encoding_by_var_[
index];
391 const auto [it, inserted] =
392 var_encoding.insert({canonical_pair.first.bound,
literal});
394 const Literal associated(it->second);
402 AddImplications(var_encoding, it,
literal);
416 1 + std::max(
literal.Index().value(),
literal.NegatedIndex().value());
417 if (new_size > reverse_encoding_.size()) {
418 reverse_encoding_.
resize(new_size);
426 if (canonical_pair.first.bound ==
max) {
429 if (-canonical_pair.second.bound ==
min) {
436 IntegerValue
value) {
448 if (
value == 1 && domain.
Min() >= 0 && domain.
Max() <= 1) {
449 if (
literal.Index() >= literal_view_.size()) {
456 if (
value == -1 && domain.
Min() >= -1 && domain.
Max() <= 0) {
457 if (
literal.Index() >= literal_view_.size()) {
467 const auto insert_result = equality_to_associated_literal_.insert(
469 if (!insert_result.second) {
487 if (
index >= equality_by_var_.size()) {
488 equality_by_var_.resize(
index.value() + 1);
524 const int new_size = 1 +
literal.Index().value();
525 if (new_size > reverse_equality_encoding_.size()) {
526 reverse_equality_encoding_.
resize(new_size);
534 if (i_lit.
bound <= domains_[
index].Min())
return true;
535 if (i_lit.
bound > domains_[
index].Max())
return true;
543 const LiteralIndex result =
558 const auto& encoding = encoding_by_var_[
index];
563 auto after_it = encoding.upper_bound(i_lit.
bound);
566 *
bound = after_it->first;
567 return after_it->second.Index();
571 auto after_it = encoding.upper_bound(-i_lit.
bound);
578 return after_it->second.NegatedIndex();
583 Literal lit, IntegerVariable* view,
bool* view_is_direct)
const {
590 if (view !=
nullptr) *view = direct_var;
591 if (view_is_direct !=
nullptr) *view_is_direct =
true;
595 if (view !=
nullptr) *view = opposite_var;
596 if (view_is_direct !=
nullptr) *view_is_direct =
false;
603 IntegerVariable
var)
const {
604 std::vector<ValueLiteralPair> result;
606 if (
index >= encoding_by_var_.size())
return result;
616 if (domain.
IsEmpty())
return result;
622 previous = domain[
i].
end;
624 if (
i == num_intervals)
break;
626 if (
i == num_intervals)
break;
628 if (
i == 0)
continue;
629 result.push_back({-previous,
literal.Negated()});
634 std::reverse(result.begin(), result.end());
642 if (
index >= encoding_by_var_.size())
return true;
648 tmp_encoding_.clear();
669 tmp_encoding_.push_back(
672 encoding_by_var_[
index].clear();
691 VLOG(1) <<
"Domain intersection fixed " << num_fixed
692 <<
" encoding literals";
699 if (parameters_.log_search_progress() && num_decisions_to_break_loop_ > 0) {
700 VLOG(1) <<
"Num decisions to break propagation loop: "
701 << num_decisions_to_break_loop_;
712 if (level > integer_search_levels_.size()) {
713 integer_search_levels_.push_back(integer_trail_.size());
714 lazy_reason_decision_levels_.push_back(lazy_reasons_.size());
715 reason_decision_levels_.push_back(literals_reason_starts_.size());
716 CHECK_EQ(level, integer_search_levels_.size());
732 const IntegerValue lb =
759 if (!EnqueueAssociatedIntegerLiteral(i_lit,
literal)) {
770 conditional_lbs_.clear();
775 if (level < first_level_without_full_propagation_) {
776 first_level_without_full_propagation_ = -1;
781 if (level >= integer_search_levels_.size())
return;
782 const int target = integer_search_levels_[level];
783 integer_search_levels_.resize(level);
784 CHECK_GE(target, var_lbs_.size());
785 CHECK_LE(target, integer_trail_.size());
787 for (
int index = integer_trail_.size() - 1;
index >= target; --
index) {
788 const TrailEntry& entry = integer_trail_[
index];
789 if (entry.var < 0)
continue;
790 var_trail_index_[entry.var] = entry.prev_trail_index;
791 var_lbs_[entry.var] = integer_trail_[entry.prev_trail_index].bound;
793 integer_trail_.resize(target);
796 lazy_reasons_.resize(lazy_reason_decision_levels_[level]);
797 lazy_reason_decision_levels_.resize(level);
800 const int old_size = reason_decision_levels_[level];
801 reason_decision_levels_.resize(level);
802 if (old_size < literals_reason_starts_.size()) {
803 literals_reason_buffer_.resize(literals_reason_starts_[old_size]);
805 const int bound_start = bounds_reason_starts_[old_size];
806 bounds_reason_buffer_.resize(bound_start);
807 if (bound_start < trail_index_reason_buffer_.size()) {
808 trail_index_reason_buffer_.resize(bound_start);
811 literals_reason_starts_.resize(old_size);
812 bounds_reason_starts_.resize(old_size);
813 cached_sizes_.resize(old_size);
827 const int size = 2 * num_vars;
830 integer_trail_.reserve(
size);
844 DCHECK(integer_search_levels_.empty());
845 DCHECK_EQ(var_lbs_.size(), integer_trail_.size());
847 const IntegerVariable
i(var_lbs_.size());
849 var_trail_index_.
push_back(integer_trail_.size());
855 var_trail_index_.
push_back(integer_trail_.size());
858 var_trail_index_cache_.
resize(var_lbs_.size(), integer_trail_.size());
859 tmp_var_to_trail_index_in_queue_.
resize(var_lbs_.size(), 0);
860 var_to_trail_index_at_lower_level_.
resize(var_lbs_.size(), 0);
871 IntegerValue(domain.
Max()));
896 if (old_domain == domain)
return true;
898 if (domain.
IsEmpty())
return false;
899 const bool lb_changed = domain.
Min() > old_domain.
Min();
900 const bool ub_changed = domain.
Max() < old_domain.
Max();
901 (*domains_)[
index] = domain;
910 var_lbs_[
var] = domain.
Min();
911 integer_trail_[
var.value()].bound = domain.
Min();
917 if (lb_changed) bitset->Set(
var);
926 IntegerValue
value) {
930 insert.first->second = new_var;
937 return insert.first->second;
943 return (constant_map_.size() + 1) / 2;
947 int threshold)
const {
955 const int index_in_queue = tmp_var_to_trail_index_in_queue_[
var];
956 if (threshold <= index_in_queue) {
959 const int last_decision_index =
960 integer_search_levels_.empty() ? 0 : integer_search_levels_.back();
961 if (index_in_queue >= last_decision_index) {
962 info_is_valid_on_subsequent_last_level_expansion_ =
false;
967 DCHECK_GE(threshold, var_lbs_.size());
968 int trail_index = var_trail_index_[
var];
971 if (trail_index > threshold) {
972 const int cached_index = var_trail_index_cache_[
var];
973 if (cached_index >= threshold && cached_index < trail_index &&
974 integer_trail_[cached_index].
var ==
var) {
975 trail_index = cached_index;
979 while (trail_index >= threshold) {
980 trail_index = integer_trail_[trail_index].prev_trail_index;
981 if (trail_index >= var_trail_index_cache_threshold_) {
982 var_trail_index_cache_[
var] = trail_index;
986 const int num_vars = var_lbs_.size();
987 return trail_index < num_vars ? -1 : trail_index;
990int IntegerTrail::FindLowestTrailIndexThatExplainBound(
992 DCHECK_LE(i_lit.
bound, var_lbs_[i_lit.
var]);
994 int trail_index = var_trail_index_[i_lit.
var];
1002 const int cached_index = var_trail_index_cache_[i_lit.
var];
1003 if (cached_index < trail_index) {
1004 const TrailEntry& entry = integer_trail_[cached_index];
1005 if (entry.var == i_lit.
var && entry.bound >= i_lit.
bound) {
1006 trail_index = cached_index;
1011 int prev_trail_index = trail_index;
1013 if (trail_index >= var_trail_index_cache_threshold_) {
1014 var_trail_index_cache_[i_lit.
var] = trail_index;
1016 const TrailEntry& entry = integer_trail_[trail_index];
1017 if (entry.bound == i_lit.
bound)
return trail_index;
1018 if (entry.bound < i_lit.
bound)
return prev_trail_index;
1019 prev_trail_index = trail_index;
1020 trail_index = entry.prev_trail_index;
1026 IntegerValue slack, absl::Span<const IntegerValue> coeffs,
1027 std::vector<IntegerLiteral>* reason)
const {
1029 if (slack == 0)
return;
1030 const int size = reason->size();
1031 tmp_indices_.resize(
size);
1032 for (
int i = 0;
i <
size; ++
i) {
1034 CHECK_GE(coeffs[
i], 0);
1035 tmp_indices_[
i] = var_trail_index_[(*reason)[
i].var];
1041 for (
const int i : tmp_indices_) {
1043 integer_trail_[
i].
bound));
1048 IntegerValue slack, absl::Span<const IntegerValue> coeffs,
1049 absl::Span<const IntegerVariable> vars,
1050 std::vector<IntegerLiteral>* reason)
const {
1051 tmp_indices_.clear();
1052 for (
const IntegerVariable
var : vars) {
1053 tmp_indices_.push_back(var_trail_index_[
var]);
1056 for (
const int i : tmp_indices_) {
1058 integer_trail_[
i].
bound));
1063 absl::Span<const IntegerValue> coeffs,
1064 std::vector<int>* trail_indices)
const {
1065 DCHECK_GT(slack, 0);
1066 DCHECK(relax_heap_.empty());
1073 const int size = coeffs.size();
1074 const int num_vars = var_lbs_.size();
1075 for (
int i = 0;
i <
size; ++
i) {
1076 const int index = (*trail_indices)[
i];
1079 if (
index < num_vars)
continue;
1082 const IntegerValue coeff = coeffs[
i];
1083 if (coeff > slack) {
1084 (*trail_indices)[new_size++] =
index;
1091 const TrailEntry& entry = integer_trail_[
index];
1093 index <= tmp_var_to_trail_index_in_queue_[entry.var]) {
1094 (*trail_indices)[new_size++] =
index;
1099 const TrailEntry& previous_entry = integer_trail_[entry.prev_trail_index];
1100 const int64_t diff =
1101 CapProd(coeff.value(), (entry.bound - previous_entry.bound).value());
1103 (*trail_indices)[new_size++] =
index;
1107 relax_heap_.push_back({
index, coeff, diff});
1109 trail_indices->resize(new_size);
1110 std::make_heap(relax_heap_.begin(), relax_heap_.end());
1112 while (slack > 0 && !relax_heap_.empty()) {
1113 const RelaxHeapEntry heap_entry = relax_heap_.front();
1114 std::pop_heap(relax_heap_.begin(), relax_heap_.end());
1115 relax_heap_.pop_back();
1118 if (heap_entry.diff > slack) {
1119 trail_indices->push_back(heap_entry.index);
1124 slack -= heap_entry.diff;
1125 const int index = integer_trail_[heap_entry.index].prev_trail_index;
1128 if (
index < num_vars)
continue;
1129 if (heap_entry.coeff > slack) {
1130 trail_indices->push_back(
index);
1133 const TrailEntry& entry = integer_trail_[
index];
1135 index <= tmp_var_to_trail_index_in_queue_[entry.var]) {
1136 trail_indices->push_back(
index);
1140 const TrailEntry& previous_entry = integer_trail_[entry.prev_trail_index];
1141 const int64_t diff =
CapProd(heap_entry.coeff.value(),
1142 (entry.bound - previous_entry.bound).value());
1144 trail_indices->push_back(
index);
1147 relax_heap_.push_back({
index, heap_entry.coeff, diff});
1148 std::push_heap(relax_heap_.begin(), relax_heap_.end());
1153 for (
const RelaxHeapEntry& entry : relax_heap_) {
1154 trail_indices->push_back(entry.index);
1156 relax_heap_.clear();
1160 std::vector<IntegerLiteral>* reason)
const {
1164 (*reason)[new_size++] =
literal;
1166 reason->resize(new_size);
1169std::vector<Literal>* IntegerTrail::InitializeConflict(
1171 absl::Span<const Literal> literals_reason,
1172 absl::Span<const IntegerLiteral> bounds_reason) {
1173 DCHECK(tmp_queue_.empty());
1175 if (use_lazy_reason) {
1178 lazy_reasons_.back().Explain(conflict, &tmp_queue_);
1180 conflict->assign(literals_reason.begin(), literals_reason.end());
1181 const int num_vars = var_lbs_.size();
1182 for (
const IntegerLiteral&
literal : bounds_reason) {
1183 const int trail_index = FindLowestTrailIndexThatExplainBound(
literal);
1184 if (trail_index >= num_vars) tmp_queue_.push_back(trail_index);
1192std::string ReasonDebugString(absl::Span<const Literal> literal_reason,
1193 absl::Span<const IntegerLiteral> integer_reason) {
1194 std::string result =
"literals:{";
1195 for (
const Literal l : literal_reason) {
1196 if (result.back() !=
'{') result +=
",";
1197 result += l.DebugString();
1199 result +=
"} bounds:{";
1200 for (
const IntegerLiteral l : integer_reason) {
1201 if (result.back() !=
'{') result +=
",";
1202 result += l.DebugString();
1210std::string IntegerTrail::DebugString() {
1211 std::string result =
"trail:{";
1212 const int num_vars = var_lbs_.size();
1214 std::min(num_vars + 30,
static_cast<int>(integer_trail_.size()));
1215 for (
int i = num_vars;
i < limit; ++
i) {
1216 if (result.back() !=
'{') result +=
",";
1222 if (limit < integer_trail_.size()) {
1230 DCHECK(ReasonIsValid(i_lit, {}, {}));
1237 if (!
Enqueue(i_lit, {}, {})) {
1247 integer_trail_[i_lit.
var.value()].bound = i_lit.
bound;
1253 IntegerLiteral i_lit, absl::Span<const IntegerLiteral> integer_reason) {
1260 tmp_cleaned_reason_.clear();
1262 DCHECK(!
lit.IsAlwaysFalse());
1263 if (
lit.IsAlwaysTrue())
continue;
1264 tmp_cleaned_reason_.push_back(
lit);
1266 return Enqueue(i_lit, {}, tmp_cleaned_reason_);
1271 std::vector<IntegerLiteral>* integer_reason) {
1276 literal_reason->push_back(
lit.Negated());
1277 return Enqueue(i_lit, *literal_reason, *integer_reason);
1281 integer_reason->push_back(
1297 const auto [it, inserted] =
1298 conditional_lbs_.insert({{
lit.Index(), i_lit.
var}, i_lit.
bound});
1300 it->second = std::max(it->second, i_lit.
bound);
1306bool IntegerTrail::ReasonIsValid(
1307 absl::Span<const Literal> literal_reason,
1308 absl::Span<const IntegerLiteral> integer_reason) {
1313 for (
const IntegerLiteral i_lit : integer_reason) {
1316 LOG(INFO) <<
"Reason has a constant false literal!";
1319 if (i_lit.
bound > var_lbs_[i_lit.
var]) {
1320 LOG(INFO) <<
"Reason " << i_lit <<
" is not true!"
1321 <<
" non-optional variable:" << i_lit.
var
1322 <<
" current_lb:" << var_lbs_[i_lit.
var];
1329 if (!integer_search_levels_.empty()) {
1330 int num_literal_assigned_after_root_node = 0;
1331 for (
const Literal
lit : literal_reason) {
1333 num_literal_assigned_after_root_node++;
1336 for (
const IntegerLiteral i_lit : integer_reason) {
1339 num_literal_assigned_after_root_node++;
1342 if (num_literal_assigned_after_root_node == 0) {
1343 VLOG(2) <<
"Propagating a literal with no reason at a positive level!\n"
1344 <<
"level:" << integer_search_levels_.size() <<
" "
1345 << ReasonDebugString(literal_reason, integer_reason) <<
"\n"
1353bool IntegerTrail::ReasonIsValid(
1354 IntegerLiteral i_lit, absl::Span<const Literal> literal_reason,
1355 absl::Span<const IntegerLiteral> integer_reason) {
1356 if (!ReasonIsValid(literal_reason, integer_reason))
return false;
1357 if (debug_checker_ ==
nullptr)
return true;
1359 std::vector<Literal> clause;
1360 clause.assign(literal_reason.begin(), literal_reason.end());
1361 std::vector<IntegerLiteral> lits;
1362 lits.assign(integer_reason.begin(), integer_reason.end());
1364 if (!debug_checker_(clause, {i_lit})) {
1365 LOG(INFO) <<
"Invalid reason for loaded solution: " << i_lit <<
" "
1366 << literal_reason <<
" " << integer_reason;
1372bool IntegerTrail::ReasonIsValid(
1373 Literal
lit, absl::Span<const Literal> literal_reason,
1374 absl::Span<const IntegerLiteral> integer_reason) {
1375 if (!ReasonIsValid(literal_reason, integer_reason))
return false;
1376 if (debug_checker_ ==
nullptr)
return true;
1378 std::vector<Literal> clause;
1379 clause.assign(literal_reason.begin(), literal_reason.end());
1380 clause.push_back(
lit);
1381 std::vector<IntegerLiteral> lits;
1382 lits.assign(integer_reason.begin(), integer_reason.end());
1384 if (!debug_checker_(clause, {})) {
1385 LOG(INFO) <<
"Invalid reason for loaded solution: " <<
lit <<
" "
1386 << literal_reason <<
" " << integer_reason;
1394 absl::Span<const IntegerLiteral> integer_reason) {
1395 EnqueueLiteralInternal(
literal,
false, literal_reason, integer_reason);
1398void IntegerTrail::EnqueueLiteralInternal(
1400 absl::Span<const Literal> literal_reason,
1401 absl::Span<const IntegerLiteral> integer_reason) {
1403 DCHECK(!use_lazy_reason ||
1404 ReasonIsValid(
literal, literal_reason, integer_reason));
1405 if (integer_search_levels_.empty()) {
1412 if (!integer_search_levels_.empty() && integer_reason.empty() &&
1413 literal_reason.empty() && !use_lazy_reason) {
1417 const int trail_index = trail_->
Index();
1418 if (trail_index >= boolean_trail_index_to_reason_index_.size()) {
1419 boolean_trail_index_to_reason_index_.resize(trail_index + 1);
1422 const int reason_index =
1424 ? -
static_cast<int>(lazy_reasons_.size())
1425 : AppendReasonToInternalBuffers(literal_reason, integer_reason);
1426 boolean_trail_index_to_reason_index_[trail_index] = reason_index;
1435 if (parameters_.propagation_loop_detection_factor() == 0.0)
return false;
1437 !integer_search_levels_.empty() &&
1438 integer_trail_.size() - integer_search_levels_.back() >
1439 std::max(10000.0, parameters_.propagation_loop_detection_factor() *
1440 static_cast<double>(var_lbs_.size())) &&
1441 parameters_.search_branching() != SatParameters::FIXED_SEARCH);
1445 if (first_level_without_full_propagation_ == -1) {
1454 ++num_decisions_to_break_loop_;
1455 std::vector<IntegerVariable> vars;
1456 for (
int i = integer_search_levels_.back();
i < integer_trail_.size(); ++
i) {
1457 const IntegerVariable
var = integer_trail_[
i].var;
1460 vars.push_back(
var);
1463 std::sort(vars.begin(), vars.end());
1464 IntegerVariable best_var = vars[0];
1467 for (
int i = 1;
i < vars.size(); ++
i) {
1468 if (vars[
i] != vars[
i - 1]) {
1472 if (count > best_count) {
1482 return first_level_without_full_propagation_ != -1;
1486 for (IntegerVariable
var(0);
var < var_lbs_.size();
var += 2) {
1492void IntegerTrail::CanonicalizeLiteralIfNeeded(
IntegerLiteral* i_lit) {
1503int IntegerTrail::AppendReasonToInternalBuffers(
1504 absl::Span<const Literal> literal_reason,
1505 absl::Span<const IntegerLiteral> integer_reason) {
1506 const int reason_index = literals_reason_starts_.size();
1507 DCHECK_EQ(reason_index, bounds_reason_starts_.size());
1508 DCHECK_EQ(reason_index, cached_sizes_.size());
1510 literals_reason_starts_.push_back(literals_reason_buffer_.size());
1511 if (!literal_reason.empty()) {
1512 literals_reason_buffer_.insert(literals_reason_buffer_.end(),
1513 literal_reason.begin(),
1514 literal_reason.end());
1517 cached_sizes_.push_back(-1);
1518 bounds_reason_starts_.push_back(bounds_reason_buffer_.size());
1519 if (!integer_reason.empty()) {
1520 bounds_reason_buffer_.insert(bounds_reason_buffer_.end(),
1521 integer_reason.begin(), integer_reason.end());
1524 return reason_index;
1527int64_t IntegerTrail::NextConflictId() {
1531bool IntegerTrail::EnqueueInternal(
1532 IntegerLiteral i_lit,
bool use_lazy_reason,
1533 absl::Span<const Literal> literal_reason,
1534 absl::Span<const IntegerLiteral> integer_reason,
1535 int trail_index_with_same_reason) {
1536 DCHECK(use_lazy_reason ||
1537 ReasonIsValid(i_lit, literal_reason, integer_reason));
1538 const IntegerVariable
var(i_lit.var);
1543 if (i_lit.bound <= var_lbs_[
var])
return true;
1552 CanonicalizeLiteralIfNeeded(&i_lit);
1561 auto* conflict = InitializeConflict(i_lit, use_lazy_reason, literal_reason,
1564 const int trail_index = FindLowestTrailIndexThatExplainBound(ub_reason);
1565 if (trail_index >= 0) tmp_queue_.push_back(trail_index);
1567 MergeReasonIntoInternal(conflict, NextConflictId());
1583 const IntegerValue lb =
LowerBound(i_lit.var);
1584 const IntegerValue ub =
UpperBound(i_lit.var);
1585 if (i_lit.bound - lb < (ub - lb) / 2) {
1586 if (first_level_without_full_propagation_ == -1) {
1594 for (SparseBitset<IntegerVariable>* bitset : watchers_) {
1595 bitset->Set(i_lit.var);
1611 const LiteralIndex literal_index =
1613 int bool_index = -1;
1615 const Literal to_enqueue = Literal(literal_index);
1617 auto* conflict = InitializeConflict(i_lit, use_lazy_reason,
1618 literal_reason, integer_reason);
1619 conflict->push_back(to_enqueue);
1620 MergeReasonIntoInternal(conflict, NextConflictId());
1628 if (
bound >= i_lit.bound) {
1629 DCHECK_EQ(
bound, i_lit.bound);
1631 EnqueueLiteralInternal(to_enqueue, use_lazy_reason, literal_reason,
1634 return EnqueueAssociatedIntegerLiteral(i_lit, to_enqueue);
1638 if (integer_search_levels_.empty()) {
1644 bool_index = trail_->
Index();
1651 if (integer_search_levels_.empty()) {
1652 ++num_level_zero_enqueues_;
1653 var_lbs_[i_lit.var] = i_lit.bound;
1654 integer_trail_[i_lit.var.value()].bound = i_lit.bound;
1667 if (!integer_search_levels_.empty() && integer_reason.empty() &&
1668 literal_reason.empty() && !use_lazy_reason) {
1673 if (use_lazy_reason) {
1674 reason_index = -
static_cast<int>(lazy_reasons_.size());
1675 }
else if (trail_index_with_same_reason >= integer_trail_.size()) {
1677 AppendReasonToInternalBuffers(literal_reason, integer_reason);
1679 reason_index = integer_trail_[trail_index_with_same_reason].reason_index;
1681 if (bool_index >= 0) {
1682 if (bool_index >= boolean_trail_index_to_reason_index_.size()) {
1683 boolean_trail_index_to_reason_index_.resize(bool_index + 1);
1685 boolean_trail_index_to_reason_index_[bool_index] = reason_index;
1688 const int prev_trail_index = var_trail_index_[i_lit.var];
1689 integer_trail_.push_back({i_lit.bound,
1694 var_lbs_[i_lit.var] = i_lit.bound;
1695 var_trail_index_[i_lit.var] = integer_trail_.size() - 1;
1699bool IntegerTrail::EnqueueAssociatedIntegerLiteral(IntegerLiteral i_lit,
1700 Literal literal_reason) {
1701 DCHECK(ReasonIsValid(i_lit, {literal_reason.Negated()}, {}));
1704 if (i_lit.bound <= var_lbs_[i_lit.var])
return true;
1708 CanonicalizeLiteralIfNeeded(&i_lit);
1715 return Enqueue(i_lit, {literal_reason.Negated()}, {});
1719 for (SparseBitset<IntegerVariable>* bitset : watchers_) {
1720 bitset->Set(i_lit.var);
1724 if (integer_search_levels_.empty()) {
1725 var_lbs_[i_lit.var] = i_lit.bound;
1726 integer_trail_[i_lit.var.value()].bound = i_lit.bound;
1737 const int reason_index =
1738 AppendReasonToInternalBuffers({literal_reason.Negated()}, {});
1739 const int prev_trail_index = var_trail_index_[i_lit.var];
1740 integer_trail_.push_back({i_lit.bound,
1745 var_lbs_[i_lit.var] = i_lit.bound;
1746 var_trail_index_[i_lit.var] = integer_trail_.size() - 1;
1750void IntegerTrail::ComputeLazyReasonIfNeeded(
int reason_index)
const {
1751 if (reason_index < 0) {
1752 lazy_reasons_[-reason_index - 1].Explain(&lazy_reason_literals_,
1753 &lazy_reason_trail_indices_);
1757absl::Span<const int> IntegerTrail::Dependencies(
int reason_index)
const {
1758 if (reason_index < 0) {
1759 return absl::Span<const int>(lazy_reason_trail_indices_);
1762 const int cached_size = cached_sizes_[reason_index];
1763 if (cached_size == 0)
return {};
1765 const int start = bounds_reason_starts_[reason_index];
1766 if (cached_size > 0) {
1767 return absl::MakeSpan(&trail_index_reason_buffer_[
start], cached_size);
1771 DCHECK_EQ(cached_size, -1);
1772 const int end = reason_index + 1 < bounds_reason_starts_.size()
1773 ? bounds_reason_starts_[reason_index + 1]
1774 : bounds_reason_buffer_.size();
1775 if (
end > trail_index_reason_buffer_.size()) {
1776 trail_index_reason_buffer_.resize(
end);
1780 int* data = trail_index_reason_buffer_.data() +
start;
1781 const int num_vars = var_lbs_.size();
1784 FindLowestTrailIndexThatExplainBound(bounds_reason_buffer_[
i]);
1785 if (dep >= num_vars) {
1786 data[new_size++] = dep;
1789 cached_sizes_[reason_index] = new_size;
1790 if (new_size == 0)
return {};
1791 return absl::MakeSpan(data, new_size);
1794void IntegerTrail::AppendLiteralsReason(
int reason_index,
1795 std::vector<Literal>* output)
const {
1796 if (reason_index < 0) {
1797 for (
const Literal l : lazy_reason_literals_) {
1798 if (!added_variables_[l.Variable()]) {
1799 added_variables_.
Set(l.Variable());
1800 output->push_back(l);
1806 const int start = literals_reason_starts_[reason_index];
1807 const int end = reason_index + 1 < literals_reason_starts_.size()
1808 ? literals_reason_starts_[reason_index + 1]
1809 : literals_reason_buffer_.size();
1811 const Literal l = literals_reason_buffer_[
i];
1812 if (!added_variables_[l.Variable()]) {
1813 added_variables_.
Set(l.Variable());
1814 output->push_back(l);
1820 std::vector<Literal> reason;
1826 std::vector<Literal>* output)
const {
1827 DCHECK(tmp_queue_.empty());
1828 const int num_vars = var_lbs_.size();
1830 if (
literal.IsAlwaysTrue())
continue;
1831 const int trail_index = FindLowestTrailIndexThatExplainBound(
literal);
1835 if (trail_index >= num_vars) tmp_queue_.push_back(trail_index);
1837 return MergeReasonIntoInternal(output, -1);
1842void IntegerTrail::MergeReasonIntoInternal(std::vector<Literal>* output,
1843 int64_t conflict_id)
const {
1846 DCHECK(std::all_of(tmp_var_to_trail_index_in_queue_.begin(),
1847 tmp_var_to_trail_index_in_queue_.end(),
1848 [](
int v) { return v == 0; }));
1849 DCHECK(tmp_to_clear_.empty());
1851 info_is_valid_on_subsequent_last_level_expansion_ =
true;
1852 if (conflict_id == -1 || last_conflict_id_ != conflict_id) {
1855 last_conflict_id_ = conflict_id;
1856 for (
const IntegerVariable
var : to_clear_for_lower_level_) {
1857 var_to_trail_index_at_lower_level_[
var] = 0;
1859 to_clear_for_lower_level_.clear();
1862 const int last_decision_index =
1863 integer_search_levels_.empty() || conflict_id == -1
1865 : integer_search_levels_.back();
1868 for (
const Literal l : *output) {
1869 added_variables_.
Set(l.Variable());
1874 for (
const int trail_index : tmp_queue_) {
1875 DCHECK_GE(trail_index, var_lbs_.size());
1876 DCHECK_LT(trail_index, integer_trail_.size());
1877 const TrailEntry& entry = integer_trail_[trail_index];
1878 tmp_var_to_trail_index_in_queue_[entry.var] =
1879 std::max(tmp_var_to_trail_index_in_queue_[entry.var], trail_index);
1884 std::make_heap(tmp_queue_.begin(), tmp_queue_.end());
1889 int64_t work_done = 0;
1890 while (!tmp_queue_.empty()) {
1892 const int trail_index = tmp_queue_.front();
1893 const TrailEntry& entry = integer_trail_[trail_index];
1894 std::pop_heap(tmp_queue_.begin(), tmp_queue_.end());
1895 tmp_queue_.pop_back();
1900 if (tmp_var_to_trail_index_in_queue_[entry.var] != trail_index) {
1915 tmp_var_to_trail_index_in_queue_[entry.var] = 0;
1916 has_dependency_ =
false;
1920 if (var_to_trail_index_at_lower_level_[entry.var] >= trail_index) {
1929 if (trail_index < last_decision_index) {
1930 tmp_seen_.push_back(trail_index);
1936 var_trail_index_cache_threshold_ = trail_index;
1941 const LiteralIndex associated_lit =
1943 IntegerVariable(entry.var), entry.bound));
1946 const int reason_index = integer_trail_[trail_index].reason_index;
1947 CHECK_GE(reason_index, 0);
1949 const int start = literals_reason_starts_[reason_index];
1950 const int end = reason_index + 1 < literals_reason_starts_.size()
1951 ? literals_reason_starts_[reason_index + 1]
1952 : literals_reason_buffer_.size();
1960 CHECK_EQ(literals_reason_buffer_[
start],
1961 Literal(associated_lit).Negated());
1965 const int start = bounds_reason_starts_[reason_index];
1966 const int end = reason_index + 1 < bounds_reason_starts_.size()
1967 ? bounds_reason_starts_[reason_index + 1]
1968 : bounds_reason_buffer_.size();
1974 ComputeLazyReasonIfNeeded(entry.reason_index);
1975 AppendLiteralsReason(entry.reason_index, output);
1976 const auto dependencies = Dependencies(entry.reason_index);
1977 work_done += dependencies.size();
1978 for (
const int next_trail_index : dependencies) {
1979 DCHECK_LT(next_trail_index, trail_index);
1980 const TrailEntry& next_entry = integer_trail_[next_trail_index];
1986 const int index_in_queue =
1987 tmp_var_to_trail_index_in_queue_[next_entry.var];
1991 if (index_in_queue >= trail_index) {
1994 if (index_in_queue >= last_decision_index) {
1995 info_is_valid_on_subsequent_last_level_expansion_ =
false;
2000 if (next_trail_index <=
2001 var_to_trail_index_at_lower_level_[next_entry.var]) {
2005 has_dependency_ =
true;
2006 if (next_trail_index > index_in_queue) {
2007 tmp_var_to_trail_index_in_queue_[next_entry.var] = next_trail_index;
2009 std::push_heap(tmp_queue_.begin(), tmp_queue_.end());
2015 if (!has_dependency_) {
2016 tmp_to_clear_.push_back(entry.var);
2017 tmp_var_to_trail_index_in_queue_[entry.var] = trail_index;
2022 if (info_is_valid_on_subsequent_last_level_expansion_) {
2023 for (
const int trail_index : tmp_seen_) {
2024 if (trail_index == 0)
continue;
2025 const TrailEntry& entry = integer_trail_[trail_index];
2026 const int old = var_to_trail_index_at_lower_level_[entry.var];
2028 to_clear_for_lower_level_.push_back(entry.var);
2030 var_to_trail_index_at_lower_level_[entry.var] =
2031 std::max(old, trail_index);
2037 for (
const IntegerVariable
var : tmp_to_clear_) {
2038 tmp_var_to_trail_index_in_queue_[
var] = 0;
2040 tmp_to_clear_.clear();
2049 int64_t conflict_id)
const {
2053 const int reason_index = boolean_trail_index_to_reason_index_[trail_index];
2054 ComputeLazyReasonIfNeeded(reason_index);
2055 AppendLiteralsReason(reason_index, reason);
2056 DCHECK(tmp_queue_.empty());
2057 for (
const int prev_trail_index : Dependencies(reason_index)) {
2058 DCHECK_GE(prev_trail_index, var_lbs_.size());
2059 tmp_queue_.push_back(prev_trail_index);
2061 MergeReasonIntoInternal(reason, conflict_id);
2072 int base_index, std::vector<IntegerLiteral>* output)
const {
2076 CHECK_GE(base_index, var_lbs_.size());
2077 for (
int i = integer_trail_.size(); --
i >= base_index;) {
2078 const TrailEntry& entry = integer_trail_[
i];
2080 if (tmp_marked_[entry.var])
continue;
2082 tmp_marked_.
Set(entry.var);
2099 &id_to_greatest_common_level_since_last_call_);
2101 queue_by_priority_.resize(2);
2105 var_to_watcher_.
reserve(2 * num_vars);
2109 if (in_queue_[
id])
return;
2110 in_queue_[id] =
true;
2111 queue_by_priority_[id_to_priority_[id]].push_back(
id);
2114void GenericLiteralWatcher::UpdateCallingNeeds(
Trail* trail) {
2118 if (
literal.Index() >= literal_to_watcher_.size())
continue;
2119 for (
const auto entry : literal_to_watcher_[
literal]) {
2120 if (!in_queue_[entry.id]) {
2121 in_queue_[entry.id] =
true;
2122 queue_by_priority_[id_to_priority_[entry.id]].push_back(entry.id);
2124 if (entry.watch_index >= 0) {
2125 id_to_watch_indices_[entry.id].push_back(entry.watch_index);
2132 if (
var.value() >= var_to_watcher_.size())
continue;
2133 for (
const auto entry : var_to_watcher_[
var]) {
2134 if (!in_queue_[entry.id]) {
2135 in_queue_[entry.id] =
true;
2136 queue_by_priority_[id_to_priority_[entry.id]].push_back(entry.id);
2138 if (entry.watch_index >= 0) {
2139 id_to_watch_indices_[entry.id].push_back(entry.watch_index);
2145 !level_zero_modified_variable_callback_.empty()) {
2146 modified_vars_for_callback_.
Resize(modified_vars_.
size());
2148 modified_vars_for_callback_.
Set(
var);
2160 for (
const int id : propagator_ids_to_call_at_level_zero_) {
2161 if (in_queue_[
id])
continue;
2162 in_queue_[id] =
true;
2163 queue_by_priority_[id_to_priority_[id]].push_back(
id);
2167 UpdateCallingNeeds(trail);
2171 int64_t num_propagate_calls = 0;
2172 const int64_t old_enqueue = integer_trail_->
num_enqueues();
2174 ::absl::MakeCleanup([&num_propagate_calls, old_enqueue,
this]() {
2175 const int64_t diff = integer_trail_->
num_enqueues() - old_enqueue;
2183 for (
int priority = 0; priority < queue_by_priority_.size(); ++priority) {
2191 if (test_limit > 100) {
2195 if (stop_propagation_callback_ !=
nullptr && stop_propagation_callback_()) {
2200 std::deque<int>& queue = queue_by_priority_[priority];
2201 while (!queue.empty()) {
2202 const int id = queue.front();
2208 if (id_need_reversible_support_[
id]) {
2210 id_to_greatest_common_level_since_last_call_[IdType(
id)];
2211 const int high = id_to_level_at_last_call_[id];
2212 if (low < high || level > low) {
2213 id_to_level_at_last_call_[id] = level;
2214 id_to_greatest_common_level_since_last_call_.
MutableRef(IdType(
id)) =
2217 if (low < high) rev->SetLevel(low);
2218 if (level > low) rev->SetLevel(level);
2220 for (
int* rev_int : id_to_reversible_ints_[
id]) {
2221 rev_int_repository_->
SaveState(rev_int);
2227 const int64_t old_integer_timestamp = integer_trail_->
num_enqueues();
2228 const int64_t old_boolean_timestamp = trail->
Index();
2231 ++num_propagate_calls;
2233 id_to_watch_indices_[id].empty()
2234 ? watchers_[id]->Propagate()
2235 : watchers_[id]->IncrementalPropagate(id_to_watch_indices_[
id]);
2237 id_to_watch_indices_[id].clear();
2238 in_queue_[id] =
false;
2244 if (id_to_idempotence_[
id]) {
2248 UpdateCallingNeeds(trail);
2249 id_to_watch_indices_[id].clear();
2250 in_queue_[id] =
false;
2255 id_to_watch_indices_[id].clear();
2256 in_queue_[id] =
false;
2257 UpdateCallingNeeds(trail);
2263 if (trail->
Index() > old_boolean_timestamp) {
2275 if (integer_trail_->
num_enqueues() > old_integer_timestamp) {
2285 const std::vector<IntegerVariable>& modified_vars =
2287 for (
const auto&
callback : level_zero_modified_variable_callback_) {
2312 for (
bool* to_reset : bool_to_reset_on_backtrack_) *to_reset =
false;
2313 bool_to_reset_on_backtrack_.clear();
2316 for (std::deque<int>& queue : queue_by_priority_) {
2317 for (
const int id : queue) {
2318 id_to_watch_indices_[id].clear();
2328 in_queue_.assign(watchers_.size(),
false);
2333 const int id = watchers_.size();
2334 watchers_.push_back(propagator);
2336 id_need_reversible_support_.push_back(
false);
2337 id_to_level_at_last_call_.push_back(0);
2338 id_to_greatest_common_level_since_last_call_.
GrowByOne();
2339 id_to_reversible_classes_.push_back(std::vector<ReversibleInterface*>());
2340 id_to_reversible_ints_.push_back(std::vector<int*>());
2342 id_to_watch_indices_.push_back(std::vector<int>());
2343 id_to_priority_.push_back(1);
2344 id_to_idempotence_.push_back(
true);
2353 in_queue_.push_back(
true);
2354 queue_by_priority_[1].push_back(
id);
2359 id_to_priority_[id] = priority;
2360 if (priority >= queue_by_priority_.size()) {
2361 queue_by_priority_.resize(priority + 1);
2367 id_to_idempotence_[id] =
false;
2371 propagator_ids_to_call_at_level_zero_.push_back(
id);
2376 id_need_reversible_support_[id] =
true;
2377 id_to_reversible_classes_[id].push_back(rev);
2381 id_need_reversible_support_[id] =
true;
2382 id_to_reversible_ints_[id].push_back(rev);
int64_t ValueAtOrAfter(int64_t input) const
Domain IntersectionWith(const Domain &domain) const
bool Contains(int64_t value) const
absl::InlinedVector< ClosedInterval, 1 >::const_iterator end() const
int64_t ValueAtOrBefore(int64_t input) const
void SaveState(T *object)
T & MutableRef(IndexType index)
void ClearAndResize(IntegerType size)
const std::vector< IntegerType > & PositionsSetAtLeastOnce() const
void Set(IntegerType index)
void Resize(IntegerType size)
void AdvanceDeterministicTime(double deterministic_duration)
bool Propagate(Trail *trail) final
void RegisterReversibleInt(int id, int *rev)
void NotifyThatPropagatorMayNotReachFixedPointInOnePass(int id)
void Untrail(const Trail &trail, int literal_trail_index) final
void SetPropagatorPriority(int id, int priority)
void RegisterReversibleClass(int id, ReversibleInterface *rev)
void ReserveSpaceForNumVariables(int num_vars)
Memory optimization: you can call this before registering watchers.
int Register(PropagatorInterface *propagator)
Registers a propagator and returns its unique ids.
void CallOnNextPropagate(int id)
Add the given propagator to its queue.
GenericLiteralWatcher(Model *model)
void AlwaysCallAtLevelZero(int id)
const std::vector< ValueLiteralPair > & FullDomainEncoding(IntegerVariable var) const
std::pair< IntegerLiteral, IntegerLiteral > Canonicalize(IntegerLiteral i_lit) const
void AssociateToIntegerLiteral(Literal literal, IntegerLiteral i_lit)
IntegerVariable GetLiteralView(Literal lit) const
void AddAllImplicationsBetweenAssociatedLiterals()
Literal GetFalseLiteral()
void FullyEncodeVariable(IntegerVariable var)
Literal GetTrueLiteral()
Gets the literal always set to true, make it if it does not exist.
bool VariableIsFullyEncoded(IntegerVariable var) const
bool IsFixedOrHasAssociatedLiteral(IntegerLiteral i_lit) const
const std::vector< ValueLiteralPair > & PartialDomainEncoding(IntegerVariable var) const
LiteralIndex GetAssociatedEqualityLiteral(IntegerVariable var, IntegerValue value) const
const InlinedIntegerLiteralVector & GetIntegerLiterals(Literal lit) const
Returns the IntegerLiterals that were associated with the given Literal.
LiteralIndex SearchForLiteralAtOrBefore(IntegerLiteral i_lit, IntegerValue *bound) const
void ReserveSpaceForNumVariables(int num_vars)
Memory optimization: you can call this before encoding variables.
Literal GetOrCreateAssociatedLiteral(IntegerLiteral i_lit)
void AssociateToIntegerEqualValue(Literal literal, IntegerVariable var, IntegerValue value)
ABSL_MUST_USE_RESULT bool LiteralOrNegationHasView(Literal lit, IntegerVariable *view=nullptr, bool *view_is_direct=nullptr) const
std::vector< ValueLiteralPair > PartialGreaterThanEncoding(IntegerVariable var) const
LiteralIndex GetAssociatedLiteral(IntegerLiteral i_lit) const
bool UpdateEncodingOnInitialDomainChange(IntegerVariable var, Domain domain)
Literal GetOrCreateLiteralAssociatedToEquality(IntegerVariable var, IntegerValue value)
void NotifyThatPropagationWasAborted()
ABSL_MUST_USE_RESULT bool ConditionalEnqueue(Literal lit, IntegerLiteral i_lit, std::vector< Literal > *literal_reason, std::vector< IntegerLiteral > *integer_reason)
absl::Span< const Literal > Reason(const Trail &trail, int trail_index, int64_t conflict_id) const final
IntegerValue LowerBound(IntegerVariable i) const
Returns the current lower/upper bound of the given integer variable.
void RemoveLevelZeroBounds(std::vector< IntegerLiteral > *reason) const
int FindTrailIndexOfVarBefore(IntegerVariable var, int threshold) const
int NumConstantVariables() const
int64_t num_enqueues() const
void RegisterWatcher(SparseBitset< IntegerVariable > *p)
ABSL_MUST_USE_RESULT bool SafeEnqueue(IntegerLiteral i_lit, absl::Span< const IntegerLiteral > integer_reason)
void RelaxLinearReason(IntegerValue slack, absl::Span< const IntegerValue > coeffs, std::vector< IntegerLiteral > *reason) const
IntegerValue UpperBound(IntegerVariable i) const
void AppendNewBoundsFrom(int base_index, std::vector< IntegerLiteral > *output) const
bool IntegerLiteralIsFalse(IntegerLiteral l) const
IntegerVariable AddIntegerVariable()
void RegisterReversibleClass(ReversibleInterface *rev)
bool ReportConflict(absl::Span< const Literal > literal_reason, absl::Span< const IntegerLiteral > integer_reason)
void AppendRelaxedLinearReason(IntegerValue slack, absl::Span< const IntegerValue > coeffs, absl::Span< const IntegerVariable > vars, std::vector< IntegerLiteral > *reason) const
Same as above but take in IntegerVariables instead of IntegerLiterals.
void AppendNewBounds(std::vector< IntegerLiteral > *output) const
bool InPropagationLoop() const
bool UpdateInitialDomain(IntegerVariable var, Domain domain)
bool IsFixed(IntegerVariable i) const
Checks if the variable is fixed.
IntegerVariable NumIntegerVariables() const
IntegerVariable NextVariableToBranchOnInPropagationLoop() const
ABSL_MUST_USE_RESULT bool RootLevelEnqueue(IntegerLiteral i_lit)
IntegerValue LevelZeroUpperBound(IntegerVariable var) const
void MergeReasonInto(absl::Span< const IntegerLiteral > literals, std::vector< Literal > *output) const
void EnqueueLiteral(Literal literal, absl::Span< const Literal > literal_reason, absl::Span< const IntegerLiteral > integer_reason)
const Domain & InitialVariableDomain(IntegerVariable var) const
IntegerValue LevelZeroLowerBound(IntegerVariable var) const
Returns globally valid lower/upper bound on the given integer variable.
void Untrail(const Trail &trail, int literal_trail_index) final
ABSL_MUST_USE_RESULT bool Enqueue(IntegerLiteral i_lit)
IntegerVariable FirstUnassignedVariable() const
void ReserveSpaceForNumVariables(int num_vars)
bool Propagate(Trail *trail) final
IntegerVariable GetOrCreateConstantIntegerVariable(IntegerValue value)
std::vector< Literal > ReasonFor(IntegerLiteral literal) const
bool CurrentBranchHadAnIncompletePropagation()
std::string DebugString() const
Base class for CP like propagators.
Base class for all the SAT constraints.
int propagation_trail_index_
BooleanVariable NewBooleanVariable()
void NotifyThatModelIsUnsat()
bool AddBinaryClause(Literal a, Literal b)
Same as AddProblemClause() below, but for small clauses.
int64_t num_failures() const
bool AddClauseDuringSearch(absl::Span< const Literal > literals)
ABSL_MUST_USE_RESULT bool AddUnitClause(Literal true_literal)
const VariablesAssignment & Assignment() const
int CurrentDecisionLevel() const
void AddLastPropagator(SatPropagator *propagator)
int NumVariables() const
Getters.
std::vector< Literal > * MutableConflict()
void Enqueue(Literal true_literal, int propagator_id)
void EnqueueWithUnitReason(Literal true_literal)
Specific Enqueue() version for a fixed variable.
int CurrentDecisionLevel() const
const AssignmentInfo & Info(BooleanVariable var) const
std::vector< Literal > * GetEmptyVectorToStoreReason(int trail_index) const
const VariablesAssignment & Assignment() const
bool LiteralIsAssigned(Literal literal) const
bool LiteralIsFalse(Literal literal) const
bool LiteralIsTrue(Literal literal) const
void push_back(const value_type &val)
void reserve(size_type n)
void resize(size_type new_size)
constexpr IntegerValue kMaxIntegerValue(std::numeric_limits< IntegerValue::ValueType >::max() - 1)
const LiteralIndex kNoLiteralIndex(-1)
std::vector< IntegerVariable > NegationOf(const std::vector< IntegerVariable > &vars)
Returns the vector of the negated variables.
constexpr IntegerValue kMinIntegerValue(-kMaxIntegerValue.value())
const IntegerVariable kNoIntegerVariable(-1)
IntegerVariable PositiveVariable(IntegerVariable i)
std::ostream & operator<<(std::ostream &os, const BoolVar &var)
PositiveOnlyIndex GetPositiveOnlyIndex(IntegerVariable var)
bool VariableIsPositive(IntegerVariable i)
In SWIG mode, we don't want anything besides these top-level includes.
int64_t CapProd(int64_t x, int64_t y)
trees with all degrees equal w the current value of w
std::optional< int64_t > end
std::vector< IntegerLiteral > integer_literal_to_fix
std::vector< Literal > literal_to_fix
bool IsAlwaysFalse() const
static IntegerLiteral GreaterOrEqual(IntegerVariable i, IntegerValue bound)
IntegerLiteral Negated() const
The negation of x >= bound is x <= bound - 1.
std::string DebugString() const
static IntegerLiteral LowerOrEqual(IntegerVariable i, IntegerValue bound)
bool IsAlwaysTrue() const
std::string DebugString() const