27#include "absl/base/attributes.h"
28#include "absl/container/btree_map.h"
29#include "absl/container/flat_hash_map.h"
30#include "absl/container/flat_hash_set.h"
31#include "absl/flags/flag.h"
32#include "absl/log/check.h"
33#include "absl/log/log.h"
34#include "absl/log/vlog_is_on.h"
35#include "absl/numeric/int128.h"
36#include "absl/strings/str_cat.h"
37#include "absl/strings/string_view.h"
38#include "absl/types/span.h"
59 "DEBUG ONLY. When set to true, the mapping_model.proto will contains "
60 "file:line of the code that created that constraint. This is helpful "
61 "for debugging postsolve");
82 const Domain& domain, absl::Span<
const std::pair<int, int64_t>> definition,
83 bool append_constraint_to_mapping_model) {
84 if (domain.
Size() == 1) {
93 append_constraint_to_mapping_model
96 for (
const auto [var, coeff] : definition) {
97 new_linear->add_vars(var);
98 new_linear->add_coeffs(coeff);
100 new_linear->add_vars(new_var);
101 new_linear->add_coeffs(-1);
102 new_linear->add_domain(0);
103 new_linear->add_domain(0);
105 new_linear->coeffs())) {
107 if (append_constraint_to_mapping_model) {
114 if (!append_constraint_to_mapping_model) {
118 solution_crush_.SetVarToLinearExpression(new_var, definition);
128 const int new_var =
NewBoolVar(
"with clause");
129 solution_crush_.SetVarToClause(new_var, clause);
134 absl::Span<const int> conjunction) {
135 const int new_var =
NewBoolVar(
"with conjunction");
136 solution_crush_.SetVarToConjunction(new_var, conjunction);
141 if (!true_literal_is_defined_) {
142 true_literal_is_defined_ =
true;
144 solution_crush_.SetVarToConjunction(true_literal_, {});
146 return true_literal_;
152 absl::Span<const int> enforcement_literals) {
155 enforcement_literals.end()};
208 return domains_[var].Min() >= 0 && domains_[var].Max() <= 1;
214 return domains_[lit].Min() == 1;
223 return domains_[lit].Max() == 0;
249 int64_t result = expr.
offset();
251 const int64_t coeff = expr.
coeffs(
i);
262 int64_t result = expr.
offset();
264 const int64_t coeff = expr.
coeffs(
i);
282 int64_t result = expr.
offset();
284 if (expr.
coeffs(
i) == 0)
continue;
292 int64_t result = expr.
offset();
294 if (expr.
coeffs(
i) == 0)
continue;
296 if (!domain.
IsFixed())
return std::nullopt;
314 if (expr.
vars().size() != 1)
return false;
320 const int ref = expr.
vars(0);
330 int* literal)
const {
332 const int ref = expr.
vars(0);
334 if (
MinOf(var) < 0 ||
MaxOf(var) > 1)
return false;
337 if (literal !=
nullptr) *literal = ref;
341 if (literal !=
nullptr) *literal =
NegatedRef(ref);
345 if (literal !=
nullptr) *literal = ref;
363 return absl::StrCat(
"interval_", ct_ref,
"(",
StartMin(ct_ref),
"..",
369 return absl::StrCat(
"interval_", ct_ref,
"(lit=", literal,
", ",
373 return absl::StrCat(
"interval_", ct_ref,
"(lit=", literal,
", ",
378 return absl::StrCat(
"interval_", ct_ref,
"(",
StartMin(ct_ref),
" --(",
381 return absl::StrCat(
"interval_", ct_ref,
"(",
StartMin(ct_ref),
" --(",
430 return var_to_constraints_[var].size() == 1;
434 return !params_.keep_all_feasible_solutions_in_presolve() &&
441 return var_to_constraints_[var].size() == 2 &&
452 return !params_.keep_all_feasible_solutions_in_presolve() &&
460 return var_to_constraints_[
PositiveRef(ref)].empty();
472 if (
IsFixed(ref))
return false;
473 if (!removed_variables_.contains(
PositiveRef(ref)))
return false;
474 if (!var_to_constraints_[
PositiveRef(ref)].empty()) {
476 " was removed, yet it appears in some constraints!");
479 for (
const int c : var_to_constraints_[
PositiveRef(ref)]) {
493 if (var_to_num_linear1_[var] == 0)
return false;
494 return var_to_num_linear1_[var] == var_to_constraints_[var].size() ||
496 var_to_num_linear1_[var] + 1 == var_to_constraints_[var].size());
502 if (var_to_num_linear1_[var] == 0)
return false;
504 return var_to_num_linear1_[var] + 1 == var_to_constraints_[var].size();
509 return domains_[var];
518 if (!CanonicalizeEncoding(&var, &value))
return false;
519 return domains_[var].Contains(value);
523 int64_t value)
const {
528 if (value >
MaxOf(expr))
return false;
529 if (value <
MinOf(expr))
return false;
533 if ((value - expr.
offset()) % expr.
coeffs(0) != 0)
return false;
539 int ref,
const Domain& domain,
bool* domain_modified) {
544 if (domains_[var].IsIncludedIn(domain)) {
547 domains_[var] = domains_[var].IntersectionWith(domain);
550 if (domains_[var].IsIncludedIn(temp)) {
556 if (domain_modified !=
nullptr) {
557 *domain_modified =
true;
560 if (domains_[var].IsEmpty()) {
562 absl::StrCat(
"var #", ref,
" as empty domain after intersecting with ",
566 solution_crush_.SetOrUpdateVarToDomain(var, domains_[var]);
575 .InverseMultiplicationBy(r.
coeff),
581 bool* domain_modified) {
582 if (expr.
vars().empty()) {
588 " as empty domain after intersecting with ", domain.
ToString()));
591 if (expr.
vars().size() == 1) {
604 const Domain a_var_domain =
606 const Domain b_var_domain =
609 const int64_t b_coeff =
b.vars_size() == 1 ?
b.coeffs(0) : 0;
611 a_var_domain, a_coeff, b_var_domain, -b_coeff, -a.
offset() +
b.offset());
637 std::string_view reason) {
638 DCHECK(!reason.empty());
654 bool contains_one_free_literal =
false;
657 if (!
LiteralIsTrue(literal)) contains_one_free_literal =
true;
659 return contains_one_free_literal;
663 DCHECK(!name.empty());
667 const bool is_todo = name.size() >= 4 && name.substr(0, 4) ==
"TODO";
670 if (logger_->LoggingIsEnabled()) {
672 int level = is_todo ? 3 : 2;
674 params_.debug_max_num_presolve_operations()) <= 100) {
680 stats_by_rule_name_[name] += num_times;
684void PresolveContext::UpdateLinear1Usage(
const ConstraintProto& ct,
int c) {
685 const int old_var = constraint_to_linear1_var_[c];
687 var_to_num_linear1_[old_var]--;
688 DCHECK_GE(var_to_num_linear1_[old_var], 0);
693 constraint_to_linear1_var_[c] = var;
694 var_to_num_linear1_[var]++;
696 constraint_to_linear1_var_[c] = -1;
700void PresolveContext::MaybeResizeIntervalData() {
702 const int num_constraints = constraint_to_vars_.size();
703 if (constraint_to_intervals_.size() != num_constraints) {
704 constraint_to_intervals_.resize(num_constraints);
705 interval_usage_.resize(num_constraints);
709void PresolveContext::AddVariableUsage(
int c) {
713 for (
const int v : constraint_to_vars_[c]) {
714 DCHECK_LT(v, var_to_constraints_.size());
716 var_to_constraints_[v].insert(c);
720 if (!used_interval.empty()) {
721 MaybeResizeIntervalData();
722 constraint_to_intervals_[
c].swap(used_interval);
723 for (
const int i : constraint_to_intervals_[c]) interval_usage_[
i]++;
726 UpdateLinear1Usage(ct, c);
732 solution_crush_.SolutionIsLoaded() &&
734 solution_crush_.GetVarValues())) {
735 LOG(FATAL) <<
"Hint infeasible for constraint #" <<
c <<
" : "
736 << ct.ShortDebugString();
741void PresolveContext::EraseFromVarToConstraint(
int var,
int c) {
742 var_to_constraints_[var].erase(c);
743 if (var_to_constraints_[var].size() <= 3) {
749 if (is_unsat_)
return;
750 DCHECK_EQ(constraint_to_vars_.size(),
working_model->constraints_size());
755 if (c < constraint_to_intervals_.size() || !used_interval.empty()) {
756 MaybeResizeIntervalData();
757 for (
const int i : constraint_to_intervals_[c]) interval_usage_[
i]--;
758 constraint_to_intervals_[c].swap(used_interval);
759 for (
const int i : constraint_to_intervals_[c]) interval_usage_[
i]++;
765 const absl::Span<const int> old_usage = constraint_to_vars_[c];
766 const int old_size = old_usage.size();
768 for (
const int var : new_usage) {
770 while (
i < old_size && old_usage[
i] < var) {
771 EraseFromVarToConstraint(old_usage[
i], c);
774 if (
i < old_size && old_usage[
i] == var) {
777 var_to_constraints_[var].insert(c);
780 for (;
i < old_size; ++
i) {
781 EraseFromVarToConstraint(old_usage[
i], c);
783 constraint_to_vars_[c].swap(new_usage);
785 UpdateLinear1Usage(ct, c);
791 solution_crush_.SolutionIsLoaded() &&
793 solution_crush_.GetVarValues())) {
794 LOG(FATAL) <<
"Hint infeasible for constraint #" << c <<
" : "
795 << ct.ShortDebugString();
801 if (is_unsat_)
return true;
802 return constraint_to_vars_.size() ==
working_model->constraints_size();
806 if (is_unsat_)
return;
807 const int old_size = constraint_to_vars_.size();
809 DCHECK_LE(old_size, new_size);
810 constraint_to_vars_.resize(new_size);
811 constraint_to_linear1_var_.resize(new_size, -1);
812 for (
int c = old_size; c < new_size; ++c) {
818 if (is_unsat_)
return false;
819 if (params_.keep_all_feasible_solutions_in_presolve())
return false;
822 if (time_limit_->LimitReached())
return false;
824 for (
int var = 0; var <
working_model->variables_size(); ++var) {
828 if (constraints.size() == 1 &&
840 if (is_unsat_)
return true;
841 if (time_limit_->LimitReached())
return true;
843 if (var_to_constraints_.size() !=
working_model->variables_size()) {
844 LOG(INFO) <<
"Wrong var_to_constraints_ size!";
847 if (constraint_to_vars_.size() !=
working_model->constraints_size()) {
848 LOG(INFO) <<
"Wrong constraint_to_vars size!";
851 std::vector<int> linear1_count(var_to_constraints_.size(), 0);
852 for (
int c = 0; c < constraint_to_vars_.size(); ++c) {
855 LOG(INFO) <<
"Wrong variables usage for constraint: \n"
857 <<
" old_size: " << constraint_to_vars_[c].size();
864 LOG(INFO) <<
"Wrong variables for linear1: \n"
866 <<
" saved_var: " << constraint_to_linear1_var_[c];
871 int num_in_objective = 0;
872 for (
int v = 0; v < var_to_constraints_.size(); ++v) {
873 if (linear1_count[v] != var_to_num_linear1_[v]) {
874 LOG(INFO) <<
"Variable " << v <<
" has wrong linear1 count!"
875 <<
" stored: " << var_to_num_linear1_[v]
876 <<
" actual: " << linear1_count[v];
881 if (!objective_map_.contains(v)) {
882 LOG(INFO) <<
"Variable " << v
883 <<
" is marked as part of the objective but isn't.";
888 if (num_in_objective != objective_map_.size()) {
889 LOG(INFO) <<
"Not all variables are marked as part of the objective";
906bool PresolveContext::AddRelation(
int x,
int y, int64_t c, int64_t o,
910 if (std::abs(c) != 1)
return repo->
TryAdd(x, y, c, o);
925 const int64_t m_x = std::max(std::abs(
MinOf(rep_x)), std::abs(
MaxOf(rep_x)));
926 const int64_t m_y = std::max(std::abs(
MinOf(rep_y)), std::abs(
MaxOf(rep_y)));
927 bool allow_rep_x = m_x < m_y;
928 bool allow_rep_y = m_y < m_x;
935 if (allow_rep_x && allow_rep_y) {
945 return repo->
TryAdd(x, y, c, o, allow_rep_x, allow_rep_y);
965 .AdditionWith(
Domain(-offset))
966 .InverseMultiplicationBy(coeff))) {
971 DomainOf(rep).MultiplicationBy(coeff).AdditionWith(
Domain(offset)))) {
979 for (
auto& ref_map : var_to_constraints_) {
1000 arg->add_coeffs(-r.
coeff);
1001 arg->add_domain(r.
offset);
1002 arg->add_domain(r.
offset);
1014 CHECK_EQ(var_to_constraints_[var].size(), 1);
1024 affine_relations_.IgnoreFromClassSize(var);
1028 if (affine_relations_.ClassSize(rep) == 1) {
1032 if (VLOG_IS_ON(2)) {
1039 const int64_t min =
MinOf(var);
1040 if (min == 0 ||
IsFixed(var))
return;
1053 std::vector<std::pair<int, double>> terms;
1054 for (
int i = 0;
i < objective.vars_size(); ++
i) {
1056 terms.push_back({objective.vars(
i), objective.coeffs(
i)});
1058 const double offset = objective.
offset();
1059 const bool maximize = objective.maximize();
1066 int64_t mod, int64_t rhs) {
1070 const int64_t gcd = std::gcd(coeff, mod);
1072 if (rhs % gcd != 0) {
1074 absl::StrCat(
"Infeasible ", coeff,
" * X = ", rhs,
" % ", mod));
1082 if (std::abs(mod) == 1)
return true;
1096 const Domain new_domain =
1100 "Empty domain in CanonicalizeAffineVariable()");
1116 const int64_t min_value = new_domain.
Min();
1131 bool debug_no_recursion) {
1134 DCHECK_NE(coeff, 0);
1135 if (is_unsat_)
return false;
1139 solution_crush_.SetVarToLinearConstraintSolution(
1140 {}, 1, {var_x, var_y}, {},
1141 {1, -coeff}, offset);
1151 if (lhs % std::abs(coeff) != 0) {
1174 const int64_t a = coeff * ry.
coeff - rx.
coeff;
1184 const int64_t unique_value = -
b / a;
1204 int64_t a = rx.
coeff;
1205 int64_t
b = -coeff * ry.
coeff;
1210 const int64_t gcd = std::gcd(std::abs(a), std::abs(
b));
1221 if (std::abs(a) > 1 && std::abs(
b) > 1) {
1236 bool negate =
false;
1237 if (std::abs(a) == 1) {
1243 CHECK_EQ(std::abs(
b), 1);
1258 y,
DomainOf(x).AdditionWith(
Domain(-o)).InverseMultiplicationBy(c))) {
1263 DomainOf(y).ContinuousMultiplicationBy(c).AdditionWith(
Domain(o)))) {
1273 if (std::abs(o) > std::max(std::abs(
MinOf(x)), std::abs(
MaxOf(x)))) {
1276 CHECK(!debug_no_recursion);
1282 CHECK(AddRelation(x, y, c, o, &affine_relations_));
1309 int ref_a,
int ref_b) {
1310 if (is_unsat_)
return false;
1319 if (ref_a == ref_b)
return true;
1356 DCHECK_NE(positive_possible, negative_possible);
1394 var_to_constraints_.clear();
1395 var_to_num_linear1_.clear();
1396 objective_map_.clear();
1397 DCHECK(!solution_crush_.SolutionIsLoaded());
1403 DCHECK_GE(new_size, domains_.size());
1404 if (domains_.size() == new_size)
return;
1408 var_to_constraints_.resize(new_size);
1409 var_to_num_linear1_.resize(new_size);
1413 const int old_size = domains_.size();
1414 domains_.resize(new_size);
1415 for (
int i = old_size;
i < new_size; ++
i) {
1418 if (domains_[
i].IsEmpty()) {
1425 solution_crush_.Resize(new_size);
1432 absl::flat_hash_map<int, int64_t> hint_values;
1433 int num_changes = 0;
1434 for (
int i = 0;
i < hint_proto.vars().size(); ++
i) {
1435 const int var = hint_proto.vars(
i);
1437 const int64_t hint_value = hint_proto.values(
i);
1439 if (clamped_hint_value != hint_value) {
1442 hint_values[var] = clamped_hint_value;
1444 if (num_changes > 0) {
1445 UpdateRuleStats(
"hint: moved var hint within its domain.", num_changes);
1447 for (
int i = 0;
i < num_vars; ++
i) {
1448 if (!hint_values.contains(
i) &&
IsFixed(
i)) {
1452 solution_crush_.LoadSolution(num_vars, hint_values);
1459 const int64_t var_min =
MinOf(var);
1460 const int64_t var_max =
MaxOf(var);
1462 if (is_unsat_)
return;
1464 absl::flat_hash_map<int64_t, SavedLiteral>& var_map = encoding_[var];
1467 auto min_it = var_map.find(var_min);
1468 if (min_it != var_map.end()) {
1469 const int old_var =
PositiveRef(min_it->second.Get(
this));
1470 if (removed_variables_.contains(old_var)) {
1471 var_map.erase(min_it);
1472 min_it = var_map.end();
1477 auto max_it = var_map.find(var_max);
1478 if (max_it != var_map.end()) {
1479 const int old_var =
PositiveRef(max_it->second.Get(
this));
1480 if (removed_variables_.contains(old_var)) {
1481 var_map.erase(max_it);
1482 max_it = var_map.end();
1489 if (min_it != var_map.end() && max_it != var_map.end()) {
1490 min_literal = min_it->second.Get(
this);
1491 max_literal = max_it->second.Get(
this);
1492 if (min_literal !=
NegatedRef(max_literal)) {
1501 }
else if (min_it != var_map.end() && max_it == var_map.end()) {
1503 min_literal = min_it->second.Get(
this);
1506 }
else if (min_it == var_map.end() && max_it != var_map.end()) {
1508 max_literal = max_it->second.Get(
this);
1513 max_literal =
NewBoolVar(
"var with 2 values");
1514 solution_crush_.MaybeSetLiteralToValueEncoding(max_literal, var, var_max);
1536 var_max - var_min, var_min);
1539 var_min - var_max, var_max);
1544bool PresolveContext::InsertVarValueEncodingInternal(
int literal,
int var,
1546 bool add_constraints) {
1550 if (is_unsat_)
return false;
1551 absl::flat_hash_map<int64_t, SavedLiteral>& var_map = encoding_[var];
1554 if (!
DomainOf(var).Contains(value)) {
1568 const auto [it, inserted] =
1569 var_map.insert(std::make_pair(value, SavedLiteral(literal)));
1571 const int previous_literal = it->second.Get(
this);
1578 it->second = SavedLiteral(literal);
1580 if (literal != previous_literal) {
1582 "variables: merge equivalent var value encoding literals");
1596 if (is_unsat_)
return false;
1607 CanonicalizeEncoding(&var, &value);
1619 }
else if (add_constraints) {
1629bool PresolveContext::InsertHalfVarValueEncoding(
int literal,
int var,
1630 int64_t value,
bool imply_eq) {
1631 if (is_unsat_)
return false;
1636 auto& direct_set = imply_eq ? eq_half_encoding_ : neq_half_encoding_;
1637 auto insert_result = direct_set.insert({{literal, var}, value});
1638 if (!insert_result.second) {
1639 if (insert_result.first->second != value && imply_eq) {
1646 int fully_encoded_lit = 0;
1649 fully_encoded_lit =
NegatedRef(fully_encoded_lit);
1652 "variables: half reified value encoding implies fully reified");
1659 auto negated_encoding = direct_set.find({
NegatedRef(literal), var});
1660 if (negated_encoding != direct_set.end()) {
1661 if (negated_encoding->second == value) {
1663 "variables: both boolean and its negation imply same equality");
1668 const int64_t other_value = negated_encoding->second;
1673 "variables: both boolean and its negation fix the same variable");
1683 VLOG(2) <<
"Collect lit(" << literal <<
") implies var(" << var
1684 << (imply_eq ?
") == " :
") != ") << value;
1689 auto& other_set = imply_eq ? neq_half_encoding_ : eq_half_encoding_;
1690 auto it = other_set.find({
NegatedRef(literal), var});
1691 if (it != other_set.end() && it->second == value) {
1693 const int imply_eq_literal = imply_eq ? literal :
NegatedRef(literal);
1694 if (!InsertVarValueEncodingInternal(imply_eq_literal, var, value,
1703bool PresolveContext::CanonicalizeEncoding(
int* ref, int64_t* value)
const {
1705 if ((*value - r.offset) % r.coeff != 0)
return false;
1706 *ref = r.representative;
1707 *value = (*value - r.offset) / r.coeff;
1713 if (!CanonicalizeEncoding(&var, &value) || !
DomainOf(var).Contains(value)) {
1717 if (!InsertVarValueEncodingInternal(literal, var, value,
1722 solution_crush_.MaybeSetLiteralToValueEncoding(literal, var, value);
1728 if (!CanonicalizeEncoding(&var, &value) || !
DomainOf(var).Contains(value)) {
1733 return InsertHalfVarValueEncoding(literal, var, value,
true);
1738 if (!CanonicalizeEncoding(&var, &value) || !
DomainOf(var).Contains(value)) {
1743 return InsertHalfVarValueEncoding(literal, var, value,
false);
1750 if (!CanonicalizeEncoding(&ref, &value))
return false;
1752 DCHECK(
DomainOf(ref).Contains(value));
1755 if (literal !=
nullptr) {
1756 *literal = value == 1 ? ref :
NegatedRef(ref);
1761 const auto first_it = encoding_.find(ref);
1762 if (first_it == encoding_.end())
return false;
1763 const auto it = first_it->second.find(value);
1764 if (it == first_it->second.end())
return false;
1767 if (literal !=
nullptr) {
1768 *literal = it->second.Get(
this);
1774 int64_t value,
int* literal) {
1777 const int64_t var_value = (value - expr.
offset()) / expr.
coeffs(0);
1783 const int64_t size = domains_[var].Size();
1784 if (size <= 2)
return true;
1785 const auto& it = encoding_.find(var);
1786 return it == encoding_.end() ? false : size <= it->second.size();
1791 if (
IsFixed(expr))
return true;
1797 const int64_t size = domains_[var].Size();
1798 if (size <= 2)
return true;
1799 const auto& it = encoding_.find(var);
1800 return it == encoding_.end() ? false : size <= 2 * it->second.size();
1805 const auto& it = encoding_.find(var);
1806 return it == encoding_.end() ? 0 : it->second.size();
1814 const int var = ref;
1817 if (!domains_[var].Contains(value)) {
1827 absl::flat_hash_map<int64_t, SavedLiteral>& var_map = encoding_[var];
1828 auto it = var_map.find(value);
1829 if (it != var_map.end()) {
1830 const int lit = it->second.Get(
this);
1834 var_map.erase(value);
1841 if (domains_[var].Size() == 1) {
1844 return true_literal;
1848 const int64_t var_min =
MinOf(var);
1849 const int64_t var_max =
MaxOf(var);
1850 if (domains_[var].Size() == 2) {
1852 const int64_t other_value = value == var_min ? var_max : var_min;
1853 auto other_it = var_map.find(other_value);
1854 if (other_it != var_map.end()) {
1855 const int literal =
NegatedRef(other_it->second.Get(
this));
1859 var_map.erase(other_value);
1868 if (var_min == 0 && var_max == 1) {
1872 return value == 1 ? representative :
NegatedRef(representative);
1874 const int literal =
NewBoolVar(
"integer encoding");
1879 return value == var_max ? representative :
NegatedRef(representative);
1883 const int literal =
NewBoolVar(
"integer encoding");
1913 objective_proto_is_up_to_date_ =
false;
1915 objective_offset_ = obj.
offset();
1917 if (objective_scaling_factor_ == 0.0) {
1918 objective_scaling_factor_ = 1.0;
1924 if (objective_integer_scaling_factor_ == 0) {
1925 objective_integer_scaling_factor_ = 1;
1928 if (!obj.
domain().empty()) {
1931 objective_domain_is_constraining_ =
true;
1934 objective_domain_is_constraining_ =
false;
1941 objective_overflow_detection_ = std::abs(objective_integer_before_offset_);
1942 int64_t fixed_terms = 0;
1944 objective_map_.clear();
1946 int var = obj.
vars(
i);
1947 int64_t coeff = obj.
coeffs(
i);
1962 const int64_t var_max_magnitude =
1963 std::max(std::abs(
MinOf(var)), std::abs(
MaxOf(var)));
1964 objective_overflow_detection_ += var_max_magnitude * std::abs(coeff);
1967 if (objective_map_[var] == 0) {
1974 if (fixed_terms != 0) {
1980 const auto it = objective_map_.find(var);
1981 if (it == objective_map_.end())
return true;
1982 const int64_t coeff = it->second;
1987 if (params_.cp_model_presolve() &&
1988 !params_.keep_all_feasible_solutions_in_presolve() &&
1989 !objective_domain_is_constraining_ &&
1991 var_to_constraints_[var].size() == 1 &&
2025 if (new_coeff == 0) {
2039 objective_proto_is_up_to_date_ =
false;
2045 tmp_entries_.clear();
2046 for (
const auto& entry : objective_map_) {
2047 tmp_entries_.push_back(entry);
2053 for (
const auto& entry : tmp_entries_) {
2059 Domain implied_domain(0);
2063 tmp_entries_.clear();
2064 for (
const auto& entry : objective_map_) {
2065 tmp_entries_.push_back(entry);
2067 std::sort(tmp_entries_.begin(), tmp_entries_.end());
2068 for (
const auto& entry : tmp_entries_) {
2069 const int var = entry.first;
2070 const int64_t coeff = entry.second;
2071 gcd = std::gcd(gcd, std::abs(coeff));
2079 objective_domain_ = objective_domain_.IntersectionWith(implied_domain);
2082 if (simplify_domain) {
2084 objective_domain_.SimplifyUsingImpliedDomain(implied_domain);
2089 for (
auto& entry : objective_map_) {
2090 entry.second /= gcd;
2092 objective_domain_ = objective_domain_.InverseMultiplicationBy(gcd);
2093 if (objective_domain_.IsEmpty()) {
2097 objective_offset_ /=
static_cast<double>(gcd);
2098 objective_scaling_factor_ *=
static_cast<double>(gcd);
2104 const absl::int128 offset =
2105 absl::int128(objective_integer_before_offset_) *
2106 absl::int128(objective_integer_scaling_factor_) +
2107 absl::int128(objective_integer_after_offset_);
2108 objective_integer_scaling_factor_ *= gcd;
2109 objective_integer_before_offset_ =
static_cast<int64_t
>(
2110 offset / absl::int128(objective_integer_scaling_factor_));
2111 objective_integer_after_offset_ =
static_cast<int64_t
>(
2112 offset % absl::int128(objective_integer_scaling_factor_));
2119 if (objective_domain_.IsEmpty()) {
2126 objective_domain_is_constraining_ =
2129 objective_domain_.Max()))
2131 if (objective_domain_is_constraining_) {
2132 VLOG(3) <<
"objective domain is constraining: size: "
2133 << objective_map_.size()
2134 <<
", implied: " << implied_domain.
ToString()
2135 <<
" objective: " << objective_domain_.ToString();
2141 CHECK_EQ(objective_map_.size(), 1);
2142 const int var = objective_map_.begin()->first;
2143 const int64_t coeff = objective_map_.begin()->second;
2147 objective_domain_.InverseMultiplicationBy(coeff))) {
2152 objective_proto_is_up_to_date_ =
false;
2154 objective_domain_is_constraining_ =
false;
2159 objective_proto_is_up_to_date_ =
false;
2161 objective_map_.erase(var);
2167 objective_proto_is_up_to_date_ =
false;
2168 int64_t& map_ref = objective_map_[var];
2178 objective_proto_is_up_to_date_ =
false;
2180 int64_t& map_ref = objective_map_[var];
2195 objective_proto_is_up_to_date_ =
false;
2196 const int64_t temp =
CapAdd(objective_integer_before_offset_, delta);
2197 if (temp == std::numeric_limits<int64_t>::min())
return false;
2198 if (temp == std::numeric_limits<int64_t>::max())
return false;
2199 objective_integer_before_offset_ = temp;
2202 objective_offset_ +=
static_cast<double>(delta);
2203 objective_domain_ = objective_domain_.AdditionWith(
Domain(-delta));
2208 int var_in_equality, int64_t coeff_in_equality,
2210 objective_proto_is_up_to_date_ =
false;
2216 const int64_t coeff_in_objective = objective_map_.at(var_in_equality);
2217 CHECK_NE(coeff_in_equality, 0);
2218 CHECK_EQ(coeff_in_objective % coeff_in_equality, 0);
2220 const int64_t multiplier = coeff_in_objective / coeff_in_equality;
2224 for (
int i = 0;
i < equality.
linear().vars().size(); ++
i) {
2226 if (
PositiveRef(var) == var_in_equality)
continue;
2229 std::abs(coeff) * std::max(std::abs(
MinOf(var)), std::abs(
MaxOf(var)));
2231 const int64_t new_value =
2233 objective_overflow_detection_ -
2234 std::abs(coeff_in_equality) *
2235 std::max(std::abs(
MinOf(var_in_equality)),
2236 std::abs(
MaxOf(var_in_equality))));
2237 if (new_value == std::numeric_limits<int64_t>::max())
return false;
2238 objective_overflow_detection_ = new_value;
2242 DCHECK_EQ(offset.
Min(), offset.
Max());
2252 for (
int i = 0;
i < equality.
linear().vars().size(); ++
i) {
2259 if (var == var_in_equality)
continue;
2261 int64_t& map_ref = objective_map_[var];
2262 map_ref -= coeff * multiplier;
2276 if (objective_map_.size() < 256) {
2277 Domain implied_domain(0);
2280 tmp_entries_.clear();
2281 for (
const auto& entry : objective_map_) {
2282 tmp_entries_.push_back(entry);
2284 std::sort(tmp_entries_.begin(), tmp_entries_.end());
2285 for (
const auto& entry : tmp_entries_) {
2286 const int var = entry.first;
2287 const int64_t coeff = entry.second;
2295 objective_domain_ = objective_domain_.IntersectionWith(implied_domain)
2296 .SimplifyUsingImpliedDomain(implied_domain);
2298 if (objective_domain_.IsEmpty()) {
2305 objective_domain_is_constraining_ =
2308 objective_domain_.Max()))
2310 if (objective_domain_is_constraining_) {
2311 VLOG(3) <<
"objective domain is constraining: size: "
2312 << objective_map_.size()
2313 <<
", implied: " << implied_domain.
ToString()
2314 <<
" objective: " << objective_domain_.ToString();
2317 objective_domain_is_constraining_ =
true;
2324 absl::Span<const int> exactly_one) {
2325 if (objective_map_.empty())
return false;
2326 if (exactly_one.empty())
return false;
2328 int64_t min_coeff = std::numeric_limits<int64_t>::max();
2329 for (
const int ref : exactly_one) {
2330 const auto it = objective_map_.find(
PositiveRef(ref));
2331 if (it == objective_map_.end())
return false;
2333 const int64_t coeff = it->second;
2335 min_coeff = std::min(min_coeff, coeff);
2338 min_coeff = std::min(min_coeff, -coeff);
2347 if (shift == 0)
return true;
2355 int64_t new_sum = 0;
2356 for (
const int ref : exactly_one) {
2359 sum =
CapAdd(sum, std::abs(obj));
2361 const int64_t new_obj =
RefIsPositive(ref) ? obj - shift : obj + shift;
2362 new_sum =
CapAdd(new_sum, std::abs(new_obj));
2365 if (new_sum > sum) {
2366 const int64_t new_value =
2367 CapAdd(objective_overflow_detection_, new_sum - sum);
2369 objective_overflow_detection_ = new_value;
2372 int64_t offset = shift;
2373 objective_proto_is_up_to_date_ =
false;
2374 for (
const int ref : exactly_one) {
2378 int64_t& map_ref = objective_map_[var];
2409 if (!objective_domain_is_constraining_) {
2411 Domain(std::numeric_limits<int64_t>::min(), objective_domain_.Max());
2418 if (objective_proto_is_up_to_date_)
return;
2419 objective_proto_is_up_to_date_ =
true;
2423 tmp_entries_.clear();
2424 tmp_entries_.reserve(objective_map_.size());
2425 for (
const auto& entry : objective_map_) {
2426 tmp_entries_.push_back(entry);
2428 std::sort(tmp_entries_.begin(), tmp_entries_.end(),
2429 [](
const std::pair<int, int64_t>& a,
2430 const std::pair<int, int64_t>&
b) { return a.first < b.first; });
2437 if (objective_integer_scaling_factor_ == 1) {
2445 for (
const auto& entry : tmp_entries_) {
2446 mutable_obj->
add_vars(entry.first);
2459 int active_i,
int active_j) {
2465 const std::tuple<int, int64_t, int, int64_t, int64_t, int, int> key =
2467 const auto& it = reified_precedences_cache_.find(key);
2468 if (it != reified_precedences_cache_.end())
return it->second;
2470 const int result =
NewBoolVar(
"precedences");
2471 reified_precedences_cache_[key] = result;
2473 solution_crush_.SetVarToReifiedPrecedenceLiteral(result, time_i, time_j,
2474 active_i, active_j);
2494 const int64_t offset =
2537 const auto& rev_it = reified_precedences_cache_.find(
2539 if (rev_it != reified_precedences_cache_.end()) {
2540 auto*
const bool_or =
working_model->add_constraints()->mutable_bool_or();
2541 bool_or->add_literals(result);
2542 bool_or->add_literals(rev_it->second);
2554std::tuple<int, int64_t, int, int64_t, int64_t, int, int>
2557 int active_i,
int active_j) {
2559 IsFixed(time_i) ? std::numeric_limits<int>::min() : time_i.
vars(0);
2560 const int64_t coeff_i =
IsFixed(time_i) ? 0 : time_i.
coeffs(0);
2562 IsFixed(time_j) ? std::numeric_limits<int>::min() : time_j.
vars(0);
2563 const int64_t coeff_j =
IsFixed(time_j) ? 0 : time_j.
coeffs(0);
2564 const int64_t offset =
2569 if (active_j < active_i) std::swap(active_i, active_j);
2570 return std::make_tuple(var_i, coeff_i, var_j, coeff_j, offset, active_i,
2575 reified_precedences_cache_.clear();
2582 " affine relations were detected.");
2583 absl::btree_map<std::string, int> sorted_rules(stats_by_rule_name_.begin(),
2584 stats_by_rule_name_.end());
2585 for (
const auto& entry : sorted_rules) {
2586 if (entry.second == 1) {
2587 SOLVER_LOG(logger_,
" - rule '", entry.first,
"' was applied 1 time.");
2589 SOLVER_LOG(logger_,
" - rule '", entry.first,
"' was applied ",
2616 local_model,
"probing");
2621 absl::string_view name_for_logging) {
2637 if (sat_solver->ModelIsUnsat()) {
2639 absl::StrCat(
"Initial loading for ", name_for_logging));
2642 if (mapping->ConstraintIsAlreadyLoaded(&ct))
continue;
2644 if (sat_solver->ModelIsUnsat()) {
2646 absl::StrCat(
"after loading constraint during ", name_for_logging,
2650 encoder->AddAllImplicationsBetweenAssociatedLiterals();
2651 if (sat_solver->ModelIsUnsat())
return false;
2652 if (!sat_solver->Propagate()) {
2654 "during probing initial propagation");
2660template <
typename ProtoWithVarsAndCoeffs,
typename PresolveContextT>
2662 absl::Span<const int> enforcements, ProtoWithVarsAndCoeffs* proto,
2663 int64_t* offset, std::vector<std::pair<int, int64_t>>* tmp_terms,
2664 PresolveContextT* context) {
2670 int64_t sum_of_fixed_terms = 0;
2671 bool remapped =
false;
2672 const int old_size = proto->vars().size();
2673 DCHECK_EQ(old_size, proto->coeffs().size());
2674 for (
int i = 0;
i < old_size; ++
i) {
2682 const int ref = proto->vars(
i);
2684 const int64_t coeff =
2686 if (coeff == 0)
continue;
2688 if (context->IsFixed(var)) {
2689 sum_of_fixed_terms += coeff * context->FixedValue(var);
2696 sum_of_fixed_terms += coeff * r.
offset;
2700 new_coeff = coeff * r.
coeff;
2705 bool removed =
false;
2706 for (
const int enf : enforcements) {
2710 sum_of_fixed_terms += new_coeff;
2719 context->UpdateRuleStats(
"linear: enforcement literal in expression");
2723 tmp_terms->push_back({new_var, new_coeff});
2725 proto->clear_vars();
2726 proto->clear_coeffs();
2727 std::sort(tmp_terms->begin(), tmp_terms->end());
2728 int current_var = 0;
2729 int64_t current_coeff = 0;
2730 for (
const auto& entry : *tmp_terms) {
2732 if (entry.first == current_var) {
2733 current_coeff += entry.second;
2735 if (current_coeff != 0) {
2736 proto->add_vars(current_var);
2737 proto->add_coeffs(current_coeff);
2739 current_var = entry.first;
2740 current_coeff = entry.second;
2743 if (current_coeff != 0) {
2744 proto->add_vars(current_var);
2745 proto->add_coeffs(current_coeff);
2748 context->UpdateRuleStats(
"linear: remapped using affine relations");
2750 if (proto->vars().size() < old_size) {
2751 context->UpdateRuleStats(
"linear: fixed or dup variables");
2753 *offset = sum_of_fixed_terms;
2754 return remapped || proto->vars().size() < old_size;
2758bool CanonicalizeLinearExpressionNoContext(absl::Span<const int> enforcements,
2759 LinearConstraintProto* proto) {
2760 struct DummyContext {
2761 bool IsFixed(
int )
const {
return false; }
2762 int64_t FixedValue(
int )
const {
return 0; }
2763 AffineRelation::Relation GetAffineRelation(
int var)
const {
2766 void UpdateRuleStats(absl::string_view )
const {}
2769 std::vector<std::pair<int, int64_t>> tmp_terms;
2771 enforcements, proto, &offset, &tmp_terms, &dummy_context);
2781 bool* is_impossible) {
2783 if (is_impossible) *is_impossible =
false;
2788 const Domain implied =
Domain(min_activity, max_activity);
2789 const Domain original_domain =
2793 if (is_impossible) *is_impossible =
true;
2808 enforcements, expr, &offset, &tmp_terms_,
this);
2817 if (absl::GetFlag(FLAGS_cp_model_debug_postsolve)) {
2818 new_ct->
set_name(absl::StrCat(
"#", c,
" ",
file,
":", line));
2828 if (absl::GetFlag(FLAGS_cp_model_debug_postsolve)) {
2829 new_ct->
set_name(absl::StrCat(
"#c", c,
" ",
file,
":", line));
2836 std::vector<int>* variable_mapping,
2838 mini_model->
Clear();
2842 absl::flat_hash_map<int, int> inverse_interval_map;
2844 auto [it, inserted] =
2867 absl::flat_hash_map<int, int> inverse_variable_map;
2870 auto [it, inserted] =
2878 variable_mapping->resize(inverse_variable_map.size());
2879 for (
const auto& [k, v] : inverse_variable_map) {
2880 (*variable_mapping)[v] = k;
2882 const auto mapping_function = [&inverse_variable_map](
int*
i) {
2884 const int positive_ref = is_positive ? *
i :
NegatedRef(*
i);
2886 const auto it = inverse_variable_map.find(positive_ref);
2887 DCHECK(it != inverse_variable_map.end());
2888 *
i = is_positive ? it->second :
NegatedRef(it->second);
2890 const auto interval_mapping_function = [&inverse_interval_map](
int*
i) {
2891 const auto it = inverse_interval_map.find(*
i);
2892 DCHECK(it != inverse_interval_map.end());
2903 if (expr.vars().empty())
continue;
2904 DCHECK_EQ(expr.vars().size(), 1);
2905 const int ref = expr.vars(0);
2906 const auto it = inverse_variable_map.find(
PositiveRef(ref));
2907 if (it == inverse_variable_map.end()) {
2909 expr.clear_coeffs();
2912 const int image = it->second;
2922 const absl::Span<const int64_t> hint = solution_crush_.GetVarValues();
2923 if (hint.size() !=
working_model->variables().size())
return false;
bool TryAdd(int x, int y, int64_t coeff, int64_t offset)
Relation Get(int x) const
Domain MultiplicationBy(int64_t coeff, bool *exact=nullptr) const
Domain IntersectionWith(const Domain &domain) const
Domain ContinuousMultiplicationBy(int64_t coeff) const
bool Contains(int64_t value) const
Domain AdditionWith(const Domain &domain) const
bool IsIncludedIn(const Domain &domain) const
int64_t FixedValue() const
std::string ToString() const
static Domain AllValues()
Domain RelaxIfTooComplex() const
Domain InverseMultiplicationBy(int64_t coeff) const
int64_t ClosestValue(int64_t wanted) const
void add_literals(::int32_t value)
ConstraintCase constraint_case() const
::operations_research::sat::BoolArgumentProto *PROTOBUF_NONNULL mutable_bool_and()
::int32_t enforcement_literal(int index) const
const ::operations_research::sat::LinearConstraintProto & linear() const
const ::operations_research::sat::IntervalConstraintProto & interval() const
void clear_enforcement_literal()
::operations_research::sat::BoolArgumentProto *PROTOBUF_NONNULL mutable_bool_or()
void add_enforcement_literal(::int32_t value)
::operations_research::sat::LinearConstraintProto *PROTOBUF_NONNULL mutable_linear()
::operations_research::sat::RoutesConstraintProto *PROTOBUF_NONNULL mutable_routes()
::google::protobuf::RepeatedField<::int32_t > *PROTOBUF_NONNULL mutable_enforcement_literal()
void set_name(Arg_ &&arg, Args_... args)
void clear_floating_point_objective()
::operations_research::sat::ConstraintProto *PROTOBUF_NONNULL mutable_constraints(int index)
bool has_floating_point_objective() const
const ::operations_research::sat::FloatObjectiveProto & floating_point_objective() const
const ::operations_research::sat::ConstraintProto & constraints(int index) const
bool has_objective() const
ABSL_ATTRIBUTE_REINITIALIZES void Clear() PROTOBUF_FINAL
int constraints_size() const
::operations_research::sat::IntegerVariableProto *PROTOBUF_NONNULL add_variables()
::operations_research::sat::ConstraintProto *PROTOBUF_NONNULL add_constraints()
int variables_size() const
void set_scaling_factor(double value)
void set_integer_scaling_factor(::int64_t value)
::int64_t domain(int index) const
void set_integer_before_offset(::int64_t value)
double scaling_factor() const
::int64_t integer_scaling_factor() const
void add_coeffs(::int64_t value)
void set_offset(double value)
::int64_t integer_after_offset() const
void set_integer_after_offset(::int64_t value)
::int32_t vars(int index) const
void add_vars(::int32_t value)
::int64_t coeffs(int index) const
::int64_t integer_before_offset() const
void DisableImplicationBetweenLiteral()
const ::operations_research::sat::LinearExpressionProto & size() const
const ::operations_research::sat::LinearExpressionProto & end() const
const ::operations_research::sat::LinearExpressionProto & start() const
::int32_t vars(int index) const
::google::protobuf::RepeatedField<::int64_t > *PROTOBUF_NONNULL mutable_coeffs()
void add_vars(::int32_t value)
void add_domain(::int64_t value)
::google::protobuf::RepeatedField<::int32_t > *PROTOBUF_NONNULL mutable_vars()
void add_coeffs(::int64_t value)
::int64_t coeffs(int index) const
::int64_t coeffs(int index) const
::int32_t vars(int index) const
void set_offset(::int64_t value)
void Register(T *non_owned_class)
const SatParameters & params() const
bool HasAffineValueEncoding(const LinearExpressionProto &expr, int64_t value, int *literal=nullptr)
ABSL_MUST_USE_RESULT bool CanonicalizeObjective(bool simplify_domain=true)
bool ExpressionIsSingleVariable(const LinearExpressionProto &expr) const
bool CanonicalizeAffineVariable(int ref, int64_t coeff, int64_t mod, int64_t rhs)
int64_t GetValueEncodingSize(int ref) const
bool AddToObjectiveOffset(int64_t delta)
ABSL_MUST_USE_RESULT bool IntersectDomainWith(int ref, const Domain &domain, bool *domain_modified=nullptr)
bool ExpressionIsALiteral(const LinearExpressionProto &expr, int *literal=nullptr) const
CpModelProto * working_model
bool StoreLiteralImpliesVarEqValue(int literal, int var, int64_t value)
bool VariableIsUniqueAndRemovable(int ref) const
bool DomainContains(const LinearExpressionProto &expr, int64_t value) const
bool StoreAffineRelation(int var_x, int var_y, int64_t coeff, int64_t offset, bool debug_no_recursion=false)
SparseBitset< int > modified_domains
ABSL_MUST_USE_RESULT bool SetLiteralToTrue(int lit)
bool LiteralIsFalse(int lit) const
void CanonicalizeVariable(int ref)
bool VariableWithCostIsUniqueAndRemovable(int ref) const
int NewIntVarWithDefinition(const Domain &domain, absl::Span< const std::pair< int, int64_t > > definition, bool append_constraint_to_mapping_model=false)
ABSL_MUST_USE_RESULT bool IntersectionOfAffineExprsIsNotEmpty(const LinearExpressionProto &a, const LinearExpressionProto &b)
bool DomainIsEmpty(int ref) const
ABSL_MUST_USE_RESULT bool SubstituteVariableInObjective(int var_in_equality, int64_t coeff_in_equality, const ConstraintProto &equality)
int64_t FixedValue(int ref) const
void AddImplication(int a, int b)
bool IntervalIsConstant(int ct_ref) const
int NewIntVar(const Domain &domain)
bool DebugTestHintFeasibility()
bool ShiftCostInExactlyOne(absl::Span< const int > exactly_one, int64_t shift)
ABSL_MUST_USE_RESULT bool SetLiteralToFalse(int lit)
int64_t ObjectiveCoeff(int var) const
void ReadObjectiveFromProto()
ABSL_MUST_USE_RESULT bool NotifyThatModelIsUnsat(absl::string_view message="")
bool HasUnusedAffineVariable() const
void CanonicalizeDomainOfSizeTwo(int var)
int GetOrCreateVarValueEncoding(int ref, int64_t value)
int64_t num_presolve_operations
int64_t SizeMax(int ct_ref) const
ABSL_MUST_USE_RESULT bool CanonicalizeOneObjectiveVariable(int var)
std::string IntervalDebugString(int ct_ref) const
bool ExpressionIsAffineBoolean(const LinearExpressionProto &expr) const
void WriteObjectiveToProto() const
bool IsFixed(int ref) const
int64_t EndMin(int ct_ref) const
bool VariableIsOnlyUsedInLinear1AndOneExtraConstraint(int var) const
int64_t EndMax(int ct_ref) const
bool StoreBooleanEqualityRelation(int ref_a, int ref_b)
void AddImplyInDomain(int b, int x, const Domain &domain)
int64_t SizeMin(int ct_ref) const
bool RecomputeSingletonObjectiveDomain()
bool VariableIsOnlyUsedInEncodingAndMaybeInObjective(int var) const
std::tuple< int, int64_t, int, int64_t, int64_t, int, int > GetReifiedPrecedenceKey(const LinearExpressionProto &time_i, const LinearExpressionProto &time_j, int active_i, int active_j)
bool CanonicalizeLinearConstraint(ConstraintProto *ct, bool *is_impossible=nullptr)
std::pair< int64_t, int64_t > ComputeMinMaxActivity(const ProtoWithVarsAndCoeffs &proto) const
int NewBoolVar(absl::string_view source)
void RemoveNonRepresentativeAffineVariableIfUnused(int var)
void ClearPrecedenceCache()
bool IsFullyEncoded(int ref) const
bool ConstraintIsInactive(int ct_index) const
int NewBoolVarWithClause(absl::Span< const int > clause)
bool HasVarValueEncoding(int ref, int64_t value, int *literal=nullptr)
void RemoveVariableFromObjective(int ref)
bool MarkConstraintAsFalse(ConstraintProto *ct, std::string_view reason)
std::optional< int64_t > FixedValueOrNullopt(const LinearExpressionProto &expr) const
bool ConstraintIsOptional(int ct_ref) const
void RemoveAllVariablesFromAffineRelationConstraint()
Domain DomainSuperSetOf(const LinearExpressionProto &expr) const
bool PropagateAffineRelation(int var)
int64_t DomainSize(int ref) const
void InitializeNewDomains()
bool VariableIsNotUsedAnymore(int ref) const
bool VariableIsUnique(int ref) const
bool VariableWasRemoved(int ref) const
ConstraintProto * NewMappingConstraint(absl::string_view file, int line)
bool ConstraintVariableGraphIsUpToDate() const
int64_t StartMax(int ct_ref) const
int GetLiteralRepresentative(int ref) const
int GetOrCreateAffineValueEncoding(const LinearExpressionProto &expr, int64_t value)
int LiteralForExpressionMax(const LinearExpressionProto &expr) const
void UpdateConstraintVariableUsage(int c)
SparseBitset< int > var_with_reduced_small_degree
bool CanonicalizeLinearExpression(absl::Span< const int > enforcements, LinearExpressionProto *expr)
AffineRelation::Relation GetAffineRelation(int ref) const
ConstraintProto * AddEnforcedConstraint(absl::Span< const int > enforcement_literals)
void AddToObjective(int var, int64_t value)
const absl::flat_hash_set< int > & VarToConstraints(int var) const
std::string RefDebugString(int ref) const
bool IsMostlyFullyEncoded(int ref) const
void MarkVariableAsRemoved(int ref)
void AddLiteralToObjective(int ref, int64_t value)
void WriteVariableDomainsToProto() const
bool InsertVarValueEncoding(int literal, int var, int64_t value)
void UpdateNewConstraintsVariableUsage()
bool VariableIsAffineRepresentative(int var) const
int NumAffineRelations() const
bool CanBeUsedAsLiteral(int ref) const
bool ConstraintVariableUsageIsConsistent()
int64_t StartMin(int ct_ref) const
std::string AffineRelationDebugString(int ref) const
int64_t MinOf(int ref) const
int64_t MaxOf(int ref) const
void RemoveVariableFromAffineRelation(int var)
ModelRandomGenerator * random()
bool VarCanTakeValue(int var, int64_t value) const
bool ExploitExactlyOneInObjective(absl::Span< const int > exactly_one)
bool VariableWithCostIsUnique(int ref) const
const Domain & DomainOf(int var) const
bool StoreLiteralImpliesVarNeValue(int literal, int var, int64_t value)
void UpdateRuleStats(std::string_view name, int num_times=1)
CpModelProto * mapping_model
bool ModelIsUnsat() const
int NewBoolVarWithConjunction(absl::Span< const int > conjunction)
int GetOrCreateReifiedPrecedenceLiteral(const LinearExpressionProto &time_i, const LinearExpressionProto &time_j, int active_i, int active_j)
bool LiteralIsTrue(int lit) const
::operations_research::sat::RoutesConstraintProto_NodeExpressions *PROTOBUF_NONNULL mutable_dimensions(int index)
RoutesConstraintProto_NodeExpressions NodeExpressions
void set_use_implied_bounds(bool value)
int Get(PresolveContext *context) const
bool CanonicalizeLinearExpressionInternal(absl::Span< const int > enforcements, ProtoWithVarsAndCoeffs *proto, int64_t *offset, std::vector< std::pair< int, int64_t > > *tmp_terms, PresolveContextT *context)
bool LoadModelForProbing(PresolveContext *context, Model *local_model)
void ApplyToAllVariableIndices(absl::FunctionRef< void(int *)> f, ConstraintProto *ct)
bool RefIsPositive(int ref)
bool SolutionIsFeasible(const CpModelProto &model, absl::Span< const int64_t > variable_values, const CpModelProto *mapping_proto, const std::vector< int > *postsolve_mapping)
int64_t ProductWithModularInverse(int64_t coeff, int64_t mod, int64_t rhs)
bool ConstraintIsFeasible(const CpModelProto &model, const ConstraintProto &constraint, absl::Span< const int64_t > variable_values)
void ApplyToAllLiteralIndices(absl::FunctionRef< void(int *)> f, ConstraintProto *ct)
bool HasEnforcementLiteral(const ConstraintProto &ct)
void LoadVariables(const CpModelProto &model_proto, bool view_all_booleans_as_integers, Model *m)
bool ScaleFloatingPointObjective(const SatParameters ¶ms, SolverLogger *logger, CpModelProto *proto)
bool ScaleAndSetObjective(const SatParameters ¶ms, absl::Span< const std::pair< int, double > > objective, double objective_offset, bool maximize, CpModelProto *cp_model, SolverLogger *logger)
bool PossibleIntegerOverflow(const CpModelProto &model, absl::Span< const int > vars, absl::Span< const int64_t > coeffs, int64_t offset, std::pair< int64_t, int64_t > *implied_domain)
bool ExpressionIsAffine(const LinearExpressionProto &expr)
constexpr int kAffineRelationConstraint
std::vector< int > UsedVariables(const ConstraintProto &ct)
std::vector< int > UsedIntervals(const ConstraintProto &ct)
void FillDomainInProto(const Domain &domain, ProtoWithDomain *proto)
constexpr int kObjectiveConstraint
bool DiophantineEquationOfSizeTwoHasSolutionInDomain(const Domain &x, int64_t a, const Domain &y, int64_t b, int64_t cte)
Domain ReadDomainFromProto(const ProtoWithDomain &proto)
bool LoadConstraint(const ConstraintProto &ct, Model *m)
void AddLinearExpressionToLinearConstraint(const LinearExpressionProto &expr, int64_t coefficient, LinearConstraintProto *linear)
void CreateValidModelWithSingleConstraint(const ConstraintProto &ct, const PresolveContext *context, std::vector< int > *variable_mapping, CpModelProto *mini_model)
void ApplyToAllIntervalIndices(absl::FunctionRef< void(int *)> f, ConstraintProto *ct)
bool LoadModelForPresolve(const CpModelProto &model_proto, SatParameters params, PresolveContext *context, Model *local_model, absl::string_view name_for_logging)
void ExtractEncoding(const CpModelProto &model_proto, Model *m)
bool AtMinOrMaxInt64(int64_t x)
int64_t CapAdd(int64_t x, int64_t y)
std::string ProtobufShortDebugString(const P &message)
std::string FormatCounter(int64_t num)
int64_t CapProd(int64_t x, int64_t y)
std::string ProtobufDebugString(const P &message)
absl::string_view ToString(MPSolver::OptimizationProblemType optimization_problem_type)
ABSL_FLAG(bool, cp_model_debug_postsolve, false, "DEBUG ONLY. When set to true, the mapping_model.proto will contains " "file:line of the code that created that constraint. This is helpful " "for debugging postsolve")
#define SOLVER_LOG(logger,...)