26 #include "absl/container/btree_map.h"
27 #include "absl/container/flat_hash_map.h"
28 #include "absl/strings/str_cat.h"
29 #include "absl/types/span.h"
34 #include "ortools/sat/sat_parameters.pb.h"
47 const std::vector<IntegerVariable>& vars) {
48 std::vector<IntegerVariable> result(vars.size());
49 for (
int i = 0; i < vars.size(); ++i) {
57 ", value = ",
value.value(),
")");
69 encoding_by_var_.reserve(num_vars);
70 equality_to_associated_literal_.reserve(num_vars);
71 equality_by_var_.reserve(num_vars);
80 CHECK(!domains_[
index].IsEmpty());
81 CHECK_LT(domains_[
index].Size(), 100000)
82 <<
"Domain too large for full encoding.";
93 for (
const int64_t v : domains_[
index].Values()) {
94 tmp_values_.push_back(IntegerValue(v));
96 for (
const IntegerValue v : tmp_values_) {
107 if (
index >= is_fully_encoded_.
size())
return false;
110 if (is_fully_encoded_[
index])
return true;
117 const int64_t initial_domain_size = domains_[
index].Size();
118 if (equality_by_var_[
index].size() < initial_domain_size)
return false;
127 const auto& ref = equality_by_var_[
index];
129 for (
const int64_t v : domains_[
index].Values()) {
130 if (i < ref.size() && v == ref[i].value) {
134 if (i == ref.size()) {
135 is_fully_encoded_[
index] =
true;
137 return is_fully_encoded_[
index];
141 IntegerVariable
var)
const {
147 IntegerVariable
var)
const {
149 if (
index >= equality_by_var_.size())
return {};
152 std::vector<ValueLiteralPair> result;
153 result.assign(equality_by_var_[
index].begin(), equality_by_var_[
index].
end());
154 for (
int i = 0; i < result.size(); ++i) {
159 result.push_back(pair);
163 result[new_size++] = pair;
165 result.resize(new_size);
170 equality_by_var_[
index].assign(result.begin(), result.end());
174 std::reverse(result.begin(), result.end());
183 void IntegerEncoder::AddImplications(
184 const absl::btree_map<IntegerValue, Literal>& map,
185 absl::btree_map<IntegerValue, Literal>::const_iterator it,
187 if (!add_implications_)
return;
188 DCHECK_EQ(it->second, associated_lit);
193 if (after_it != map.end()) {
195 {after_it->second.Negated(), associated_lit});
199 if (it != map.begin()) {
203 {associated_lit.
Negated(), before_it->second});
209 add_implications_ =
true;
213 const int num_vars = encoding_by_var_.size();
216 const IntegerVariable
var(2 *
index.value());
230 if (!positive) i_lit = i_lit.
Negated();
232 const IntegerVariable
var(i_lit.
var);
234 IntegerValue after(i_lit.
bound);
235 IntegerValue before(i_lit.
bound - 1);
236 DCHECK_GE(before, domains_[
index].Min());
237 DCHECK_LE(after, domains_[
index].Max());
240 if (before > previous && before <
interval.start) before = previous;
278 ++num_created_variables_;
285 VLOG(1) <<
"Created a fixed literal for no reason!";
291 std::pair<PositiveOnlyIndex, IntegerValue> PositiveVarKey(IntegerVariable
var,
292 IntegerValue
value) {
299 IntegerVariable
var, IntegerValue
value)
const {
301 equality_to_associated_literal_.find(PositiveVarKey(
var,
value));
302 if (it != equality_to_associated_literal_.end()) {
303 return it->second.Index();
309 IntegerVariable
var, IntegerValue
value) {
312 equality_to_associated_literal_.find(PositiveVarKey(
var,
value));
313 if (it != equality_to_associated_literal_.end()) {
330 ++num_created_variables_;
340 VLOG(1) <<
"Created a fixed literal for no reason!";
355 const IntegerValue
min(domain.
Min());
356 const IntegerValue
max(domain.
Max());
366 if (
index >= encoding_by_var_.size()) {
367 encoding_by_var_.resize(
index.value() + 1);
369 auto& var_encoding = encoding_by_var_[
index];
374 const auto [it, inserted] =
375 var_encoding.insert({canonical_pair.first.bound,
literal});
377 const Literal associated(it->second);
385 AddImplications(var_encoding, it,
literal);
400 if (new_size > reverse_encoding_.
size()) {
401 reverse_encoding_.
resize(new_size);
409 if (canonical_pair.first.bound ==
max) {
412 if (-canonical_pair.second.bound ==
min) {
419 IntegerValue
value) {
431 if (
value == 1 && domain.
Min() >= 0 && domain.
Max() <= 1) {
439 if (
value == -1 && domain.
Min() >= -1 && domain.
Max() <= 0) {
450 const auto insert_result = equality_to_associated_literal_.insert(
452 if (!insert_result.second) {
471 if (
index >= equality_by_var_.size()) {
472 equality_by_var_.resize(
index.value() + 1);
509 const int new_size = 1 +
literal.Index().value();
510 if (new_size > reverse_equality_encoding_.
size()) {
511 reverse_equality_encoding_.
resize(new_size);
520 const LiteralIndex result =
535 const auto& encoding = encoding_by_var_[
index];
540 auto after_it = encoding.upper_bound(i_lit.
bound);
543 *
bound = after_it->first;
544 return after_it->second.Index();
548 auto after_it = encoding.upper_bound(-i_lit.
bound);
555 return after_it->second.NegatedIndex();
560 Literal lit, IntegerVariable* view,
bool* view_is_direct)
const {
567 if (view !=
nullptr) *view = direct_var;
568 if (view_is_direct !=
nullptr) *view_is_direct =
true;
572 if (view !=
nullptr) *view = opposite_var;
573 if (view_is_direct !=
nullptr) *view_is_direct =
false;
580 IntegerVariable
var)
const {
581 std::vector<ValueLiteralPair> result;
583 if (
index >= encoding_by_var_.size())
return result;
593 if (domain.
IsEmpty())
return result;
599 previous = domain[i].
end;
601 if (i == num_intervals)
break;
603 if (i == num_intervals)
break;
605 if (i == 0)
continue;
606 result.push_back({-previous,
literal.Negated()});
611 std::reverse(result.begin(), result.end());
619 if (
index >= encoding_by_var_.size())
return true;
625 tmp_encoding_.clear();
646 tmp_encoding_.push_back(
649 encoding_by_var_[
index].clear();
659 if (i == domain.
NumIntervals() || pair.value < domain[i].start) {
668 VLOG(1) <<
"Domain intersection fixed " << num_fixed
669 <<
" encoding literals";
676 if (parameters_.log_search_progress() && num_decisions_to_break_loop_ > 0) {
677 VLOG(1) <<
"Num decisions to break propagation loop: "
678 << num_decisions_to_break_loop_;
689 if (level > integer_search_levels_.size()) {
690 integer_search_levels_.push_back(integer_trail_.size());
691 reason_decision_levels_.push_back(literals_reason_starts_.size());
710 const IntegerValue lb =
733 while (propagation_trail_index_ < trail->
Index()) {
739 if (!EnqueueAssociatedIntegerLiteral(i_lit,
literal)) {
750 conditional_lbs_.clear();
755 if (level < first_level_without_full_propagation_) {
756 first_level_without_full_propagation_ = -1;
761 if (level >= integer_search_levels_.size())
return;
762 const int target = integer_search_levels_[level];
763 integer_search_levels_.resize(level);
764 CHECK_GE(target, vars_.
size());
765 CHECK_LE(target, integer_trail_.size());
767 for (
int index = integer_trail_.size() - 1;
index >= target; --
index) {
768 const TrailEntry& entry = integer_trail_[
index];
769 if (entry.var < 0)
continue;
770 vars_[entry.var].current_trail_index = entry.prev_trail_index;
771 vars_[entry.var].current_bound =
772 integer_trail_[entry.prev_trail_index].bound;
774 integer_trail_.resize(target);
777 const int old_size = reason_decision_levels_[level];
778 reason_decision_levels_.resize(level);
779 if (old_size < literals_reason_starts_.size()) {
780 literals_reason_buffer_.resize(literals_reason_starts_[old_size]);
782 const int bound_start = bounds_reason_starts_[old_size];
783 bounds_reason_buffer_.resize(bound_start);
784 if (bound_start < trail_index_reason_buffer_.size()) {
785 trail_index_reason_buffer_.resize(bound_start);
788 literals_reason_starts_.resize(old_size);
789 bounds_reason_starts_.resize(old_size);
803 const int size = 2 * num_vars;
805 is_ignored_literals_.
reserve(size);
806 integer_trail_.reserve(size);
807 var_trail_index_cache_.
reserve(size);
808 tmp_var_to_trail_index_in_queue_.
reserve(size);
818 DCHECK(integer_search_levels_.empty());
819 DCHECK_EQ(vars_.
size(), integer_trail_.size());
821 const IntegerVariable i(vars_.
size());
835 var_trail_index_cache_.
resize(vars_.
size(), integer_trail_.size());
836 tmp_var_to_trail_index_in_queue_.
resize(vars_.
size(), 0);
847 IntegerValue(domain.
Max()));
872 if (old_domain == domain)
return true;
874 if (domain.
IsEmpty())
return false;
875 (*domains_)[
index] = domain;
884 vars_[
var].current_bound = domain.
Min();
885 integer_trail_[
var.value()].bound = domain.
Min();
894 IntegerValue
value) {
898 insert.first->second = new_var;
905 return insert.first->second;
911 return (constant_map_.size() + 1) / 2;
915 int threshold)
const {
919 const int index_in_queue = tmp_var_to_trail_index_in_queue_[
var];
920 if (threshold <= index_in_queue) {
922 has_dependency_ =
true;
926 DCHECK_GE(threshold, vars_.
size());
927 int trail_index = vars_[
var].current_trail_index;
930 if (trail_index > threshold) {
931 const int cached_index = var_trail_index_cache_[
var];
932 if (cached_index >= threshold && cached_index < trail_index &&
933 integer_trail_[cached_index].
var ==
var) {
934 trail_index = cached_index;
938 while (trail_index >= threshold) {
939 trail_index = integer_trail_[trail_index].prev_trail_index;
940 if (trail_index >= var_trail_index_cache_threshold_) {
941 var_trail_index_cache_[
var] = trail_index;
945 const int num_vars = vars_.
size();
946 return trail_index < num_vars ? -1 : trail_index;
949 int IntegerTrail::FindLowestTrailIndexThatExplainBound(
951 DCHECK_LE(i_lit.
bound, vars_[i_lit.
var].current_bound);
953 int trail_index = vars_[i_lit.
var].current_trail_index;
961 const int cached_index = var_trail_index_cache_[i_lit.
var];
962 if (cached_index < trail_index) {
963 const TrailEntry& entry = integer_trail_[cached_index];
964 if (entry.var == i_lit.
var && entry.bound >= i_lit.
bound) {
965 trail_index = cached_index;
970 int prev_trail_index = trail_index;
972 if (trail_index >= var_trail_index_cache_threshold_) {
973 var_trail_index_cache_[i_lit.
var] = trail_index;
975 const TrailEntry& entry = integer_trail_[trail_index];
976 if (entry.bound == i_lit.
bound)
return trail_index;
977 if (entry.bound < i_lit.
bound)
return prev_trail_index;
978 prev_trail_index = trail_index;
979 trail_index = entry.prev_trail_index;
985 IntegerValue slack, absl::Span<const IntegerValue> coeffs,
986 std::vector<IntegerLiteral>* reason)
const {
988 if (slack == 0)
return;
989 const int size = reason->size();
990 tmp_indices_.resize(size);
991 for (
int i = 0; i < size; ++i) {
993 CHECK_GE(coeffs[i], 0);
994 tmp_indices_[i] = vars_[(*reason)[i].var].current_trail_index;
1000 for (
const int i : tmp_indices_) {
1002 integer_trail_[i].
bound));
1007 IntegerValue slack, absl::Span<const IntegerValue> coeffs,
1008 absl::Span<const IntegerVariable> vars,
1009 std::vector<IntegerLiteral>* reason)
const {
1010 tmp_indices_.clear();
1011 for (
const IntegerVariable
var : vars) {
1012 tmp_indices_.push_back(vars_[
var].current_trail_index);
1015 for (
const int i : tmp_indices_) {
1017 integer_trail_[i].
bound));
1022 absl::Span<const IntegerValue> coeffs,
1023 std::vector<int>* trail_indices)
const {
1024 DCHECK_GT(slack, 0);
1025 DCHECK(relax_heap_.empty());
1032 const int size = coeffs.size();
1033 const int num_vars = vars_.
size();
1034 for (
int i = 0; i < size; ++i) {
1035 const int index = (*trail_indices)[i];
1038 if (
index < num_vars)
continue;
1041 const IntegerValue coeff = coeffs[i];
1042 if (coeff > slack) {
1043 (*trail_indices)[new_size++] =
index;
1050 const TrailEntry& entry = integer_trail_[
index];
1052 index <= tmp_var_to_trail_index_in_queue_[entry.var]) {
1053 (*trail_indices)[new_size++] =
index;
1058 const TrailEntry& previous_entry = integer_trail_[entry.prev_trail_index];
1059 const int64_t diff =
1060 CapProd(coeff.value(), (entry.bound - previous_entry.bound).value());
1062 (*trail_indices)[new_size++] =
index;
1066 relax_heap_.push_back({
index, coeff, diff});
1068 trail_indices->resize(new_size);
1069 std::make_heap(relax_heap_.begin(), relax_heap_.end());
1071 while (slack > 0 && !relax_heap_.empty()) {
1072 const RelaxHeapEntry heap_entry = relax_heap_.front();
1073 std::pop_heap(relax_heap_.begin(), relax_heap_.end());
1074 relax_heap_.pop_back();
1077 if (heap_entry.diff > slack) {
1078 trail_indices->push_back(heap_entry.index);
1083 slack -= heap_entry.diff;
1084 const int index = integer_trail_[heap_entry.index].prev_trail_index;
1087 if (
index < num_vars)
continue;
1088 if (heap_entry.coeff > slack) {
1089 trail_indices->push_back(
index);
1092 const TrailEntry& entry = integer_trail_[
index];
1094 index <= tmp_var_to_trail_index_in_queue_[entry.var]) {
1095 trail_indices->push_back(
index);
1099 const TrailEntry& previous_entry = integer_trail_[entry.prev_trail_index];
1100 const int64_t diff =
CapProd(heap_entry.coeff.value(),
1101 (entry.bound - previous_entry.bound).value());
1103 trail_indices->push_back(
index);
1106 relax_heap_.push_back({
index, heap_entry.coeff, diff});
1107 std::push_heap(relax_heap_.begin(), relax_heap_.end());
1112 for (
const RelaxHeapEntry& entry : relax_heap_) {
1113 trail_indices->push_back(entry.index);
1115 relax_heap_.clear();
1119 std::vector<IntegerLiteral>* reason)
const {
1123 (*reason)[new_size++] =
literal;
1125 reason->resize(new_size);
1128 std::vector<Literal>* IntegerTrail::InitializeConflict(
1129 IntegerLiteral integer_literal,
const LazyReasonFunction& lazy_reason,
1130 absl::Span<const Literal> literals_reason,
1131 absl::Span<const IntegerLiteral> bounds_reason) {
1132 DCHECK(tmp_queue_.empty());
1134 if (lazy_reason ==
nullptr) {
1135 conflict->assign(literals_reason.begin(), literals_reason.end());
1136 const int num_vars = vars_.
size();
1138 const int trail_index = FindLowestTrailIndexThatExplainBound(
literal);
1139 if (trail_index >= num_vars) tmp_queue_.push_back(trail_index);
1144 lazy_reason(integer_literal, integer_trail_.size(), conflict, &tmp_queue_);
1151 std::string ReasonDebugString(absl::Span<const Literal> literal_reason,
1152 absl::Span<const IntegerLiteral> integer_reason) {
1153 std::string result =
"literals:{";
1154 for (
const Literal l : literal_reason) {
1155 if (result.back() !=
'{') result +=
",";
1156 result += l.DebugString();
1158 result +=
"} bounds:{";
1159 for (
const IntegerLiteral l : integer_reason) {
1160 if (result.back() !=
'{') result +=
",";
1161 result += l.DebugString();
1169 std::string IntegerTrail::DebugString() {
1170 std::string result =
"trail:{";
1171 const int num_vars = vars_.
size();
1173 std::min(num_vars + 30,
static_cast<int>(integer_trail_.size()));
1174 for (
int i = num_vars; i < limit; ++i) {
1175 if (result.back() !=
'{') result +=
",";
1178 integer_trail_[i].
bound)
1181 if (limit < integer_trail_.size()) {
1189 DCHECK(ReasonIsValid(i_lit, {}, {}));
1196 if (!
Enqueue(i_lit, {}, {})) {
1206 integer_trail_[i_lit.
var.value()].bound = i_lit.
bound;
1212 IntegerLiteral i_lit, absl::Span<const IntegerLiteral> integer_reason) {
1219 tmp_cleaned_reason_.clear();
1221 DCHECK(!lit.IsAlwaysFalse());
1222 if (lit.IsAlwaysTrue())
continue;
1223 tmp_cleaned_reason_.push_back(lit);
1225 return Enqueue(i_lit, {}, tmp_cleaned_reason_);
1229 absl::Span<const Literal> literal_reason,
1230 absl::Span<const IntegerLiteral> integer_reason) {
1231 return EnqueueInternal(i_lit,
nullptr, literal_reason, integer_reason,
1232 integer_trail_.size());
1237 std::vector<IntegerLiteral>* integer_reason) {
1245 return Enqueue(i_lit, *literal_reason, *integer_reason);
1249 literal_reason->push_back(lit.
Negated());
1250 return Enqueue(i_lit, *literal_reason, *integer_reason);
1254 integer_reason->push_back(
1270 const auto [it, inserted] =
1271 conditional_lbs_.insert({{lit.
Index(), i_lit.
var}, i_lit.
bound});
1280 absl::Span<const Literal> literal_reason,
1281 absl::Span<const IntegerLiteral> integer_reason,
1282 int trail_index_with_same_reason) {
1283 return EnqueueInternal(i_lit,
nullptr, literal_reason, integer_reason,
1284 trail_index_with_same_reason);
1289 return EnqueueInternal(i_lit, lazy_reason, {}, {}, integer_trail_.size());
1292 bool IntegerTrail::ReasonIsValid(
1293 absl::Span<const Literal> literal_reason,
1294 absl::Span<const IntegerLiteral> integer_reason) {
1296 for (
const Literal lit : literal_reason) {
1299 for (
const IntegerLiteral i_lit : integer_reason) {
1302 LOG(INFO) <<
"Reason has a constant false literal!";
1305 if (i_lit.
bound > vars_[i_lit.
var].current_bound) {
1308 LOG(INFO) <<
"Reason " << i_lit <<
" is not true!"
1309 <<
" optional variable:" << i_lit.
var
1312 <<
" current_lb:" << vars_[i_lit.
var].current_bound;
1314 LOG(INFO) <<
"Reason " << i_lit <<
" is not true!"
1315 <<
" non-optional variable:" << i_lit.
var
1316 <<
" current_lb:" << vars_[i_lit.
var].current_bound;
1324 if (!integer_search_levels_.empty()) {
1325 int num_literal_assigned_after_root_node = 0;
1326 for (
const Literal lit : literal_reason) {
1327 if (trail_->
Info(lit.Variable()).
level > 0) {
1328 num_literal_assigned_after_root_node++;
1331 for (
const IntegerLiteral i_lit : integer_reason) {
1334 num_literal_assigned_after_root_node++;
1337 if (num_literal_assigned_after_root_node == 0) {
1338 VLOG(2) <<
"Propagating a literal with no reason at a positive level!\n"
1339 <<
"level:" << integer_search_levels_.size() <<
" "
1340 << ReasonDebugString(literal_reason, integer_reason) <<
"\n"
1348 bool IntegerTrail::ReasonIsValid(
1349 IntegerLiteral i_lit, absl::Span<const Literal> literal_reason,
1350 absl::Span<const IntegerLiteral> integer_reason) {
1351 if (!ReasonIsValid(literal_reason, integer_reason))
return false;
1352 if (debug_checker_ ==
nullptr)
return true;
1354 std::vector<Literal> clause;
1355 clause.assign(literal_reason.begin(), literal_reason.end());
1356 std::vector<IntegerLiteral> lits;
1357 lits.assign(integer_reason.begin(), integer_reason.end());
1359 if (!debug_checker_(clause, {i_lit})) {
1360 LOG(INFO) <<
"Invalid reason for loaded solution: " << i_lit <<
" "
1361 << literal_reason <<
" " << integer_reason;
1367 bool IntegerTrail::ReasonIsValid(
1368 Literal lit, absl::Span<const Literal> literal_reason,
1369 absl::Span<const IntegerLiteral> integer_reason) {
1370 if (!ReasonIsValid(literal_reason, integer_reason))
return false;
1371 if (debug_checker_ ==
nullptr)
return true;
1373 std::vector<Literal> clause;
1374 clause.assign(literal_reason.begin(), literal_reason.end());
1375 clause.push_back(lit);
1376 std::vector<IntegerLiteral> lits;
1377 lits.assign(integer_reason.begin(), integer_reason.end());
1379 if (!debug_checker_(clause, {})) {
1380 LOG(INFO) <<
"Invalid reason for loaded solution: " << lit <<
" "
1381 << literal_reason <<
" " << integer_reason;
1389 absl::Span<const IntegerLiteral> integer_reason) {
1390 EnqueueLiteralInternal(
literal,
nullptr, literal_reason, integer_reason);
1393 void IntegerTrail::EnqueueLiteralInternal(
1395 absl::Span<const Literal> literal_reason,
1396 absl::Span<const IntegerLiteral> integer_reason) {
1398 DCHECK(lazy_reason !=
nullptr ||
1399 ReasonIsValid(
literal, literal_reason, integer_reason));
1400 if (integer_search_levels_.empty()) {
1407 if (!integer_search_levels_.empty() && integer_reason.empty() &&
1408 literal_reason.empty() && lazy_reason ==
nullptr) {
1412 const int trail_index = trail_->
Index();
1413 if (trail_index >= boolean_trail_index_to_integer_one_.size()) {
1414 boolean_trail_index_to_integer_one_.resize(trail_index + 1);
1416 boolean_trail_index_to_integer_one_[trail_index] = integer_trail_.size();
1418 int reason_index = literals_reason_starts_.size();
1419 if (lazy_reason !=
nullptr) {
1420 if (integer_trail_.size() >= lazy_reasons_.size()) {
1421 lazy_reasons_.resize(integer_trail_.size() + 1,
nullptr);
1423 lazy_reasons_[integer_trail_.size()] = lazy_reason;
1427 literals_reason_starts_.push_back(literals_reason_buffer_.size());
1428 literals_reason_buffer_.insert(literals_reason_buffer_.end(),
1429 literal_reason.begin(),
1430 literal_reason.end());
1431 bounds_reason_starts_.push_back(bounds_reason_buffer_.size());
1432 bounds_reason_buffer_.insert(bounds_reason_buffer_.end(),
1433 integer_reason.begin(), integer_reason.end());
1436 integer_trail_.push_back({IntegerValue(0),
1448 if (parameters_.propagation_loop_detection_factor() == 0.0)
return false;
1450 !integer_search_levels_.empty() &&
1451 integer_trail_.size() - integer_search_levels_.back() >
1452 std::max(10000.0, parameters_.propagation_loop_detection_factor() *
1453 static_cast<double>(vars_.
size())) &&
1454 parameters_.search_branching() != SatParameters::FIXED_SEARCH);
1458 if (first_level_without_full_propagation_ == -1) {
1467 ++num_decisions_to_break_loop_;
1468 std::vector<IntegerVariable> vars;
1469 for (
int i = integer_search_levels_.back(); i < integer_trail_.size(); ++i) {
1470 const IntegerVariable
var = integer_trail_[i].var;
1473 vars.push_back(
var);
1476 std::sort(vars.begin(), vars.end());
1477 IntegerVariable best_var = vars[0];
1480 for (
int i = 1; i < vars.size(); ++i) {
1481 if (vars[i] != vars[i - 1]) {
1485 if (count > best_count) {
1495 return first_level_without_full_propagation_ != -1;
1499 for (IntegerVariable
var(0);
var < vars_.
size();
var += 2) {
1506 void IntegerTrail::CanonicalizeLiteralIfNeeded(
IntegerLiteral* i_lit) {
1517 bool IntegerTrail::EnqueueInternal(
1518 IntegerLiteral i_lit, LazyReasonFunction lazy_reason,
1519 absl::Span<const Literal> literal_reason,
1520 absl::Span<const IntegerLiteral> integer_reason,
1521 int trail_index_with_same_reason) {
1522 DCHECK(lazy_reason !=
nullptr ||
1523 ReasonIsValid(i_lit, literal_reason, integer_reason));
1524 const IntegerVariable
var(i_lit.var);
1532 if (i_lit.bound <= vars_[
var].current_bound)
return true;
1541 CanonicalizeLiteralIfNeeded(&i_lit);
1549 Literal(is_ignored_literals_[
var]))) {
1552 auto* conflict = InitializeConflict(i_lit, lazy_reason, literal_reason,
1555 conflict->push_back(Literal(is_ignored_literals_[
var]));
1558 const int trail_index = FindLowestTrailIndexThatExplainBound(ub_reason);
1559 const int num_vars = vars_.
size();
1560 if (trail_index >= num_vars) tmp_queue_.push_back(trail_index);
1562 MergeReasonIntoInternal(conflict);
1569 const Literal is_ignored = Literal(is_ignored_literals_[
var]);
1570 if (integer_search_levels_.empty()) {
1577 if (lazy_reason !=
nullptr) {
1578 lazy_reason(i_lit, integer_trail_.size(), &lazy_reason_literals_,
1579 &lazy_reason_trail_indices_);
1580 std::vector<IntegerLiteral> temp;
1581 for (
const int trail_index : lazy_reason_trail_indices_) {
1582 const TrailEntry& entry = integer_trail_[trail_index];
1583 temp.push_back(IntegerLiteral(entry.var, entry.bound));
1591 bounds_reason_buffer_.push_back(ub_reason);
1609 const IntegerValue lb =
LowerBound(i_lit.var);
1610 const IntegerValue ub =
UpperBound(i_lit.var);
1611 if (i_lit.bound - lb < (ub - lb) / 2) {
1612 if (first_level_without_full_propagation_ == -1) {
1620 for (SparseBitset<IntegerVariable>* bitset : watchers_) {
1621 bitset->Set(i_lit.var);
1637 const LiteralIndex literal_index =
1640 const Literal to_enqueue = Literal(literal_index);
1642 auto* conflict = InitializeConflict(i_lit, lazy_reason, literal_reason,
1644 conflict->push_back(to_enqueue);
1645 MergeReasonIntoInternal(conflict);
1653 if (
bound >= i_lit.bound) {
1654 DCHECK_EQ(
bound, i_lit.bound);
1656 EnqueueLiteralInternal(to_enqueue, lazy_reason, literal_reason,
1659 return EnqueueAssociatedIntegerLiteral(i_lit, to_enqueue);
1663 if (integer_search_levels_.empty()) {
1669 const int trail_index = trail_->
Index();
1670 if (trail_index >= boolean_trail_index_to_integer_one_.size()) {
1671 boolean_trail_index_to_integer_one_.resize(trail_index + 1);
1673 boolean_trail_index_to_integer_one_[trail_index] =
1674 trail_index_with_same_reason;
1681 if (integer_search_levels_.empty()) {
1682 ++num_level_zero_enqueues_;
1683 vars_[i_lit.var].current_bound = i_lit.bound;
1684 integer_trail_[i_lit.var.value()].bound = i_lit.bound;
1697 if (!integer_search_levels_.empty() && integer_reason.empty() &&
1698 literal_reason.empty() && lazy_reason ==
nullptr &&
1699 trail_index_with_same_reason >= integer_trail_.size()) {
1703 int reason_index = literals_reason_starts_.size();
1704 if (lazy_reason !=
nullptr) {
1705 if (integer_trail_.size() >= lazy_reasons_.size()) {
1706 lazy_reasons_.resize(integer_trail_.size() + 1,
nullptr);
1708 lazy_reasons_[integer_trail_.size()] = lazy_reason;
1710 }
else if (trail_index_with_same_reason >= integer_trail_.size()) {
1712 literals_reason_starts_.push_back(literals_reason_buffer_.size());
1713 if (!literal_reason.empty()) {
1714 literals_reason_buffer_.insert(literals_reason_buffer_.end(),
1715 literal_reason.begin(),
1716 literal_reason.end());
1718 bounds_reason_starts_.push_back(bounds_reason_buffer_.size());
1719 if (!integer_reason.empty()) {
1720 bounds_reason_buffer_.insert(bounds_reason_buffer_.end(),
1721 integer_reason.begin(),
1722 integer_reason.end());
1725 reason_index = integer_trail_[trail_index_with_same_reason].reason_index;
1728 const int prev_trail_index = vars_[i_lit.var].current_trail_index;
1729 integer_trail_.push_back({i_lit.bound,
1734 vars_[i_lit.var].current_bound = i_lit.bound;
1735 vars_[i_lit.var].current_trail_index = integer_trail_.size() - 1;
1739 bool IntegerTrail::EnqueueAssociatedIntegerLiteral(IntegerLiteral i_lit,
1740 Literal literal_reason) {
1741 DCHECK(ReasonIsValid(i_lit, {literal_reason.Negated()}, {}));
1745 if (i_lit.bound <= vars_[i_lit.var].current_bound)
return true;
1749 CanonicalizeLiteralIfNeeded(&i_lit);
1756 return Enqueue(i_lit, {literal_reason.Negated()}, {});
1760 for (SparseBitset<IntegerVariable>* bitset : watchers_) {
1761 bitset->Set(i_lit.var);
1765 if (integer_search_levels_.empty()) {
1766 vars_[i_lit.var].current_bound = i_lit.bound;
1767 integer_trail_[i_lit.var.value()].bound = i_lit.bound;
1778 const int reason_index = literals_reason_starts_.size();
1779 CHECK_EQ(reason_index, bounds_reason_starts_.size());
1780 literals_reason_starts_.push_back(literals_reason_buffer_.size());
1781 bounds_reason_starts_.push_back(bounds_reason_buffer_.size());
1782 literals_reason_buffer_.push_back(literal_reason.Negated());
1784 const int prev_trail_index = vars_[i_lit.var].current_trail_index;
1785 integer_trail_.push_back({i_lit.bound,
1790 vars_[i_lit.var].current_bound = i_lit.bound;
1791 vars_[i_lit.var].current_trail_index = integer_trail_.size() - 1;
1795 void IntegerTrail::ComputeLazyReasonIfNeeded(
int trail_index)
const {
1796 const int reason_index = integer_trail_[trail_index].reason_index;
1797 if (reason_index == -1) {
1798 const TrailEntry& entry = integer_trail_[trail_index];
1799 const IntegerLiteral
literal(entry.var, entry.bound);
1800 lazy_reasons_[trail_index](
literal, trail_index, &lazy_reason_literals_,
1801 &lazy_reason_trail_indices_);
1805 absl::Span<const int> IntegerTrail::Dependencies(
int trail_index)
const {
1806 const int reason_index = integer_trail_[trail_index].reason_index;
1807 if (reason_index == -1) {
1808 return absl::Span<const int>(lazy_reason_trail_indices_);
1811 const int start = bounds_reason_starts_[reason_index];
1812 const int end = reason_index + 1 < bounds_reason_starts_.size()
1813 ? bounds_reason_starts_[reason_index + 1]
1814 : bounds_reason_buffer_.size();
1822 if (
end > trail_index_reason_buffer_.size()) {
1823 trail_index_reason_buffer_.resize(
end, -1);
1825 if (trail_index_reason_buffer_[
start] == -1) {
1826 int new_end =
start;
1827 const int num_vars = vars_.
size();
1828 for (
int i =
start; i <
end; ++i) {
1830 FindLowestTrailIndexThatExplainBound(bounds_reason_buffer_[i]);
1831 if (dep >= num_vars) {
1832 trail_index_reason_buffer_[new_end++] = dep;
1835 return absl::Span<const int>(&trail_index_reason_buffer_[
start],
1841 return absl::Span<const int>(&trail_index_reason_buffer_[
start],
1846 void IntegerTrail::AppendLiteralsReason(
int trail_index,
1847 std::vector<Literal>* output)
const {
1848 CHECK_GE(trail_index, vars_.
size());
1849 const int reason_index = integer_trail_[trail_index].reason_index;
1850 if (reason_index == -1) {
1851 for (
const Literal l : lazy_reason_literals_) {
1852 if (!added_variables_[l.Variable()]) {
1853 added_variables_.
Set(l.Variable());
1854 output->push_back(l);
1860 const int start = literals_reason_starts_[reason_index];
1861 const int end = reason_index + 1 < literals_reason_starts_.size()
1862 ? literals_reason_starts_[reason_index + 1]
1863 : literals_reason_buffer_.size();
1864 for (
int i =
start; i <
end; ++i) {
1865 const Literal l = literals_reason_buffer_[i];
1866 if (!added_variables_[l.Variable()]) {
1867 added_variables_.
Set(l.Variable());
1868 output->push_back(l);
1874 std::vector<Literal> reason;
1880 std::vector<Literal>* output)
const {
1881 DCHECK(tmp_queue_.empty());
1882 const int num_vars = vars_.
size();
1884 if (
literal.IsAlwaysTrue())
continue;
1885 const int trail_index = FindLowestTrailIndexThatExplainBound(
literal);
1889 if (trail_index >= num_vars) tmp_queue_.push_back(trail_index);
1891 return MergeReasonIntoInternal(output);
1896 void IntegerTrail::MergeReasonIntoInternal(std::vector<Literal>* output)
const {
1899 DCHECK(std::all_of(tmp_var_to_trail_index_in_queue_.
begin(),
1900 tmp_var_to_trail_index_in_queue_.
end(),
1901 [](
int v) { return v == 0; }));
1904 for (
const Literal l : *output) {
1905 added_variables_.
Set(l.Variable());
1910 for (
const int trail_index : tmp_queue_) {
1911 DCHECK_GE(trail_index, vars_.
size());
1912 DCHECK_LT(trail_index, integer_trail_.size());
1913 const TrailEntry& entry = integer_trail_[trail_index];
1914 tmp_var_to_trail_index_in_queue_[entry.var] =
1915 std::max(tmp_var_to_trail_index_in_queue_[entry.var], trail_index);
1920 std::make_heap(tmp_queue_.begin(), tmp_queue_.end());
1925 tmp_to_clear_.clear();
1926 while (!tmp_queue_.empty()) {
1927 const int trail_index = tmp_queue_.front();
1928 const TrailEntry& entry = integer_trail_[trail_index];
1929 std::pop_heap(tmp_queue_.begin(), tmp_queue_.end());
1930 tmp_queue_.pop_back();
1935 if (tmp_var_to_trail_index_in_queue_[entry.var] != trail_index) {
1942 var_trail_index_cache_threshold_ = trail_index;
1947 const LiteralIndex associated_lit =
1949 IntegerVariable(entry.var), entry.bound));
1952 const int reason_index = integer_trail_[trail_index].reason_index;
1953 CHECK_NE(reason_index, -1);
1955 const int start = literals_reason_starts_[reason_index];
1956 const int end = reason_index + 1 < literals_reason_starts_.size()
1957 ? literals_reason_starts_[reason_index + 1]
1958 : literals_reason_buffer_.size();
1966 CHECK_EQ(literals_reason_buffer_[
start],
1967 Literal(associated_lit).Negated());
1971 const int start = bounds_reason_starts_[reason_index];
1972 const int end = reason_index + 1 < bounds_reason_starts_.size()
1973 ? bounds_reason_starts_[reason_index + 1]
1974 : bounds_reason_buffer_.size();
1988 tmp_var_to_trail_index_in_queue_[entry.var] = 0;
1989 has_dependency_ =
false;
1991 ComputeLazyReasonIfNeeded(trail_index);
1992 AppendLiteralsReason(trail_index, output);
1993 for (
const int next_trail_index : Dependencies(trail_index)) {
1994 if (next_trail_index < 0)
break;
1995 DCHECK_LT(next_trail_index, trail_index);
1996 const TrailEntry& next_entry = integer_trail_[next_trail_index];
2002 const int index_in_queue =
2003 tmp_var_to_trail_index_in_queue_[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());
2014 if (!has_dependency_) {
2015 tmp_to_clear_.push_back(entry.var);
2016 tmp_var_to_trail_index_in_queue_[entry.var] =
2022 for (
const IntegerVariable
var : tmp_to_clear_) {
2023 tmp_var_to_trail_index_in_queue_[
var] = 0;
2030 int trail_index)
const {
2031 const int index = boolean_trail_index_to_integer_one_[trail_index];
2035 ComputeLazyReasonIfNeeded(
index);
2036 AppendLiteralsReason(
index, reason);
2037 DCHECK(tmp_queue_.empty());
2038 for (
const int prev_trail_index : Dependencies(
index)) {
2039 if (prev_trail_index < 0)
break;
2040 DCHECK_GE(prev_trail_index, vars_.
size());
2041 tmp_queue_.push_back(prev_trail_index);
2043 MergeReasonIntoInternal(reason);
2054 for (
int i = integer_trail_.size(); --i >=
end;) {
2055 const TrailEntry& entry = integer_trail_[i];
2057 if (tmp_marked_[entry.var])
continue;
2059 tmp_marked_.
Set(entry.var);
2076 &id_to_greatest_common_level_since_last_call_);
2078 queue_by_priority_.resize(2);
2082 var_to_watcher_.
reserve(2 * num_vars);
2086 if (in_queue_[
id])
return;
2087 in_queue_[id] =
true;
2088 queue_by_priority_[id_to_priority_[id]].push_back(
id);
2091 void GenericLiteralWatcher::UpdateCallingNeeds(
Trail* trail) {
2093 while (propagation_trail_index_ < trail->
Index()) {
2095 if (
literal.Index() >= literal_to_watcher_.
size())
continue;
2096 for (
const auto entry : literal_to_watcher_[
literal.Index()]) {
2097 if (!in_queue_[entry.id]) {
2098 in_queue_[entry.id] =
true;
2099 queue_by_priority_[id_to_priority_[entry.id]].push_back(entry.id);
2101 if (entry.watch_index >= 0) {
2102 id_to_watch_indices_[entry.id].push_back(entry.watch_index);
2109 if (
var.value() >= var_to_watcher_.
size())
continue;
2110 for (
const auto entry : var_to_watcher_[
var]) {
2111 if (!in_queue_[entry.id]) {
2112 in_queue_[entry.id] =
true;
2113 queue_by_priority_[id_to_priority_[entry.id]].push_back(entry.id);
2115 if (entry.watch_index >= 0) {
2116 id_to_watch_indices_[entry.id].push_back(entry.watch_index);
2122 !level_zero_modified_variable_callback_.empty()) {
2123 modified_vars_for_callback_.
Resize(modified_vars_.
size());
2125 modified_vars_for_callback_.
Set(
var);
2137 for (
const int id : propagator_ids_to_call_at_level_zero_) {
2138 if (in_queue_[
id])
continue;
2139 in_queue_[id] =
true;
2140 queue_by_priority_[id_to_priority_[id]].push_back(
id);
2144 UpdateCallingNeeds(trail);
2149 for (
int priority = 0; priority < queue_by_priority_.size(); ++priority) {
2156 if (test_limit > 100) {
2160 if (stop_propagation_callback_ !=
nullptr && stop_propagation_callback_()) {
2165 std::deque<int>& queue = queue_by_priority_[priority];
2166 while (!queue.empty()) {
2167 const int id = queue.front();
2175 id_to_greatest_common_level_since_last_call_[IdType(
id)];
2176 const int high = id_to_level_at_last_call_[id];
2177 if (low < high || level > low) {
2178 id_to_level_at_last_call_[id] = level;
2179 id_to_greatest_common_level_since_last_call_.
MutableRef(IdType(
id)) =
2182 if (low < high) rev->SetLevel(low);
2183 if (level > low) rev->SetLevel(level);
2185 for (
int* rev_int : id_to_reversible_ints_[
id]) {
2186 rev_int_repository_->
SaveState(rev_int);
2192 const int64_t old_integer_timestamp = integer_trail_->
num_enqueues();
2193 const int64_t old_boolean_timestamp = trail->
Index();
2196 std::vector<int>& watch_indices_ref = id_to_watch_indices_[id];
2198 watch_indices_ref.empty()
2199 ? watchers_[id]->Propagate()
2200 : watchers_[id]->IncrementalPropagate(watch_indices_ref);
2202 watch_indices_ref.clear();
2203 in_queue_[id] =
false;
2209 if (id_to_idempotence_[
id]) {
2213 UpdateCallingNeeds(trail);
2214 watch_indices_ref.clear();
2215 in_queue_[id] =
false;
2220 watch_indices_ref.clear();
2221 in_queue_[id] =
false;
2222 UpdateCallingNeeds(trail);
2228 if (trail->
Index() > old_boolean_timestamp) {
2240 if (integer_trail_->
num_enqueues() > old_integer_timestamp) {
2250 const std::vector<IntegerVariable>& modified_vars =
2252 for (
const auto&
callback : level_zero_modified_variable_callback_) {
2270 for (std::deque<int>& queue : queue_by_priority_) {
2271 for (
const int id : queue) {
2272 id_to_watch_indices_[id].clear();
2282 in_queue_.assign(watchers_.size(),
false);
2287 const int id = watchers_.size();
2288 watchers_.push_back(propagator);
2289 id_to_level_at_last_call_.push_back(0);
2290 id_to_greatest_common_level_since_last_call_.
GrowByOne();
2291 id_to_reversible_classes_.push_back(std::vector<ReversibleInterface*>());
2292 id_to_reversible_ints_.push_back(std::vector<int*>());
2293 id_to_watch_indices_.push_back(std::vector<int>());
2294 id_to_priority_.push_back(1);
2295 id_to_idempotence_.push_back(
true);
2304 in_queue_.push_back(
true);
2305 queue_by_priority_[1].push_back(
id);
2310 id_to_priority_[id] = priority;
2311 if (priority >= queue_by_priority_.size()) {
2312 queue_by_priority_.resize(priority + 1);
2318 id_to_idempotence_[id] =
false;
2322 propagator_ids_to_call_at_level_zero_.push_back(
id);
2327 id_to_reversible_classes_[id].push_back(rev);
2331 id_to_reversible_ints_[id].push_back(rev);
2335 std::function<void(
Model*)>
2343 std::vector<Literal> clause_to_exclude_solution;
2344 clause_to_exclude_solution.reserve(current_level);
2345 for (
int i = 0; i < current_level; ++i) {
2346 bool include_decision =
true;
2352 encoder->GetIntegerLiterals(decision);
2354 if (integer_trail->IsCurrentlyIgnored(
bound.var)) {
2360 clause_to_exclude_solution.push_back(
2361 integer_trail->IsIgnoredLiteral(
bound.var).Negated());
2362 include_decision =
false;
2366 if (include_decision) {
2367 clause_to_exclude_solution.push_back(decision.
Negated());
void resize(size_type new_size)
void reserve(size_type n)
void push_back(const value_type &x)
We call domain any subset of Int64 = [kint64min, kint64max].
Domain Negation() const
Returns {x ∈ Int64, ∃ e ∈ D, x = -e}.
bool Contains(int64_t value) const
Returns true iff value is in Domain.
absl::InlinedVector< ClosedInterval, 1 >::const_iterator end() const
int NumIntervals() const
Basic read-only std::vector<> wrapping to view a Domain as a sorted list of non-adjacent intervals.
bool IsFixed() const
Returns true iff the domain is reduced to a single value.
Domain IntersectionWith(const Domain &domain) const
Returns the intersection of D and domain.
int64_t Min() const
Returns the min value of the domain.
bool IsEmpty() const
Returns true if this is the empty set.
int64_t Max() const
Returns the max value of the domain.
int64_t ValueAtOrAfter(int64_t input) const
int64_t ValueAtOrBefore(int64_t input) const
Returns the closest value in the domain that is <= (resp.
void SaveState(T *object)
T & MutableRef(IndexType index)
const std::vector< IntegerType > & PositionsSetAtLeastOnce() const
void Set(IntegerType index)
void Resize(IntegerType size)
void ClearAndResize(IntegerType size)
A simple class to enforce both an elapsed time limit and a deterministic time limit in the same threa...
bool LimitReached()
Returns true when the external limit is true, or the deterministic time is over the deterministic lim...
bool Propagate(Trail *trail) final
void ReserveSpaceForNumVariables(int num_vars)
void AlwaysCallAtLevelZero(int id)
void CallOnNextPropagate(int id)
void RegisterReversibleInt(int id, int *rev)
void RegisterReversibleClass(int id, ReversibleInterface *rev)
GenericLiteralWatcher(Model *model)
void SetPropagatorPriority(int id, int priority)
int Register(PropagatorInterface *propagator)
void NotifyThatPropagatorMayNotReachFixedPointInOnePass(int id)
void Untrail(const Trail &trail, int literal_trail_index) final
Literal GetOrCreateLiteralAssociatedToEquality(IntegerVariable var, IntegerValue value)
LiteralIndex GetAssociatedLiteral(IntegerLiteral i_lit) const
void FullyEncodeVariable(IntegerVariable var)
bool UpdateEncodingOnInitialDomainChange(IntegerVariable var, Domain domain)
void ReserveSpaceForNumVariables(int num_vars)
Literal GetFalseLiteral()
const IntegerVariable GetLiteralView(Literal lit) const
std::pair< IntegerLiteral, IntegerLiteral > Canonicalize(IntegerLiteral i_lit) const
LiteralIndex SearchForLiteralAtOrBefore(IntegerLiteral i_lit, IntegerValue *bound) const
void AssociateToIntegerEqualValue(Literal literal, IntegerVariable var, IntegerValue value)
std::vector< ValueLiteralPair > PartialDomainEncoding(IntegerVariable var) const
const InlinedIntegerLiteralVector & GetIntegerLiterals(Literal lit) const
ABSL_MUST_USE_RESULT bool LiteralOrNegationHasView(Literal lit, IntegerVariable *view=nullptr, bool *view_is_direct=nullptr) const
std::vector< ValueLiteralPair > FullDomainEncoding(IntegerVariable var) const
void AddAllImplicationsBetweenAssociatedLiterals()
bool VariableIsFullyEncoded(IntegerVariable var) const
std::vector< ValueLiteralPair > PartialGreaterThanEncoding(IntegerVariable var) const
LiteralIndex GetAssociatedEqualityLiteral(IntegerVariable var, IntegerValue value) const
void AssociateToIntegerLiteral(Literal literal, IntegerLiteral i_lit)
Literal GetOrCreateAssociatedLiteral(IntegerLiteral i_lit)
IntegerVariable FirstUnassignedVariable() const
ABSL_MUST_USE_RESULT bool Enqueue(IntegerLiteral i_lit, absl::Span< const Literal > literal_reason, absl::Span< const IntegerLiteral > integer_reason)
IntegerVariable GetOrCreateConstantIntegerVariable(IntegerValue value)
int64_t num_enqueues() const
void RegisterWatcher(SparseBitset< IntegerVariable > *p)
bool Propagate(Trail *trail) final
void ReserveSpaceForNumVariables(int num_vars)
void NotifyThatPropagationWasAborted()
int FindTrailIndexOfVarBefore(IntegerVariable var, int threshold) const
bool IsCurrentlyIgnored(IntegerVariable i) const
std::vector< Literal > ReasonFor(IntegerLiteral literal) const
std::function< void(IntegerLiteral literal_to_explain, int trail_index_of_literal, std::vector< Literal > *literals, std::vector< int > *dependencies)> LazyReasonFunction
bool IsFixed(IntegerVariable i) const
LiteralIndex OptionalLiteralIndex(IntegerVariable i) const
absl::Span< const Literal > Reason(const Trail &trail, int trail_index) const final
bool CurrentBranchHadAnIncompletePropagation()
bool InPropagationLoop() const
bool ReportConflict(absl::Span< const Literal > literal_reason, absl::Span< const IntegerLiteral > integer_reason)
void EnqueueLiteral(Literal literal, absl::Span< const Literal > literal_reason, absl::Span< const IntegerLiteral > integer_reason)
ABSL_MUST_USE_RESULT bool RootLevelEnqueue(IntegerLiteral i_lit)
IntegerVariable NextVariableToBranchOnInPropagationLoop() const
IntegerValue UpperBound(IntegerVariable i) const
ABSL_MUST_USE_RESULT bool SafeEnqueue(IntegerLiteral i_lit, absl::Span< const IntegerLiteral > integer_reason)
IntegerValue LevelZeroUpperBound(IntegerVariable var) const
void AppendRelaxedLinearReason(IntegerValue slack, absl::Span< const IntegerValue > coeffs, absl::Span< const IntegerVariable > vars, std::vector< IntegerLiteral > *reason) const
IntegerValue LevelZeroLowerBound(IntegerVariable var) const
void RelaxLinearReason(IntegerValue slack, absl::Span< const IntegerValue > coeffs, std::vector< IntegerLiteral > *reason) const
void AppendNewBounds(std::vector< IntegerLiteral > *output) const
IntegerValue LowerBound(IntegerVariable i) const
int NumConstantVariables() const
void MergeReasonInto(absl::Span< const IntegerLiteral > literals, std::vector< Literal > *output) const
Literal IsIgnoredLiteral(IntegerVariable i) const
bool IsOptional(IntegerVariable i) const
ABSL_MUST_USE_RESULT bool ConditionalEnqueue(Literal lit, IntegerLiteral i_lit, std::vector< Literal > *literal_reason, std::vector< IntegerLiteral > *integer_reason)
bool IntegerLiteralIsFalse(IntegerLiteral l) const
void RemoveLevelZeroBounds(std::vector< IntegerLiteral > *reason) const
IntegerVariable AddIntegerVariable()
void RegisterReversibleClass(ReversibleInterface *rev)
const Domain & InitialVariableDomain(IntegerVariable var) const
void Untrail(const Trail &trail, int literal_trail_index) final
IntegerVariable NumIntegerVariables() const
bool UpdateInitialDomain(IntegerVariable var, Domain domain)
LiteralIndex Index() const
std::string DebugString() const
Class that owns everything related to a particular optimization model.
int propagation_trail_index_
bool AddClauseDuringSearch(absl::Span< const Literal > literals)
BooleanVariable NewBooleanVariable()
void NotifyThatModelIsUnsat()
const VariablesAssignment & Assignment() const
bool AddBinaryClause(Literal a, Literal b)
void Backtrack(int target_level)
int CurrentDecisionLevel() const
const std::vector< Decision > & Decisions() const
bool AddUnitClause(Literal true_literal)
void Enqueue(Literal true_literal, int propagator_id)
const AssignmentInfo & Info(BooleanVariable var) const
std::vector< Literal > * GetEmptyVectorToStoreReason(int trail_index) const
std::vector< Literal > * MutableConflict()
const VariablesAssignment & Assignment() const
int CurrentDecisionLevel() const
void EnqueueWithUnitReason(Literal true_literal)
bool LiteralIsAssigned(Literal literal) const
bool LiteralIsTrue(Literal literal) const
bool LiteralIsFalse(Literal literal) const
absl::InlinedVector< IntegerLiteral, 2 > InlinedIntegerLiteralVector
constexpr IntegerValue kMaxIntegerValue(std::numeric_limits< IntegerValue::ValueType >::max() - 1)
std::ostream & operator<<(std::ostream &os, const BoolVar &var)
std::function< void(Model *)> ClauseConstraint(absl::Span< const Literal > literals)
const LiteralIndex kNoLiteralIndex(-1)
constexpr IntegerValue kMinIntegerValue(-kMaxIntegerValue.value())
const IntegerVariable kNoIntegerVariable(-1)
IntegerVariable PositiveVariable(IntegerVariable i)
std::vector< IntegerVariable > NegationOf(const std::vector< IntegerVariable > &vars)
std::function< void(Model *)> ExcludeCurrentSolutionWithoutIgnoredVariableAndBacktrack()
PositiveOnlyIndex GetPositiveOnlyIndex(IntegerVariable var)
bool VariableIsPositive(IntegerVariable i)
Collection of objects used to extend the Constraint Solver library.
int64_t CapProd(int64_t x, int64_t y)
std::optional< int64_t > end
Represents a closed interval [start, end].
std::vector< IntegerLiteral > integer_literal_to_fix
std::vector< Literal > literal_to_fix
bool IsAlwaysFalse() const
static IntegerLiteral LowerOrEqual(IntegerVariable i, IntegerValue bound)
static IntegerLiteral GreaterOrEqual(IntegerVariable i, IntegerValue bound)
std::string DebugString() const
bool IsAlwaysTrue() const
IntegerLiteral Negated() const
std::string DebugString() const
#define VLOG(verboselevel)