21#include "absl/base/log_severity.h" 
   22#include "absl/log/check.h" 
   23#include "absl/types/span.h" 
   43  bool satisfied = 
false;
 
   44  for (
int i = 0; 
i < size; ++
i) {
 
   47    if ((*domains)[var].
IsFixed()) {
 
   48      if ((*domains)[var].FixedValue() == (
RefIsPositive(ref) ? 1 : 0)) {
 
   60  if (satisfied) 
return;
 
 
   68                         std::vector<Domain>* domains) {
 
   69  bool satisfied = 
false;
 
   70  std::vector<int> free_variables;
 
   73    if ((*domains)[var].
IsFixed()) {
 
   74      if ((*domains)[var].FixedValue() == (
RefIsPositive(ref) ? 1 : 0)) {
 
   75        CHECK(!satisfied) << 
"Two variables at one in exactly one.";
 
   79      free_variables.push_back(ref);
 
   84    CHECK(!free_variables.empty()) << 
"All zero in exactly one";
 
   85    const int ref = free_variables.back();
 
   87    free_variables.pop_back();
 
   91  for (
const int ref : free_variables) {
 
 
   99                                  std::vector<Domain>* domains) {
 
  101  bool has_free_enforcement_literal = 
false;
 
  104    has_free_enforcement_literal = 
true;
 
  106      (*domains)[enf] = 
Domain(0);
 
  112  if (!has_free_enforcement_literal) {
 
  114        << 
"Unsatisfied linear constraint with no free enforcement literal: " 
 
  122  int64_t fixed_activity = 0;
 
  124  std::vector<int> free_vars;
 
  125  std::vector<int64_t> free_coeffs;
 
  126  for (
int i = 0; 
i < size; ++
i) {
 
  129    CHECK_LT(var, domains->size());
 
  130    if (coeff == 0) 
continue;
 
  131    if ((*domains)[var].
IsFixed()) {
 
  132      fixed_activity += (*domains)[var].FixedValue() * coeff;
 
  134      free_vars.push_back(var);
 
  135      free_coeffs.push_back(coeff);
 
  138  if (free_vars.empty()) {
 
  140    if (!rhs.
Contains(fixed_activity)) {
 
  168  if (free_vars.size() == 1) {
 
  169    const int var = free_vars[0];
 
  188  std::vector<Domain> rhs_domains;
 
  189  rhs_domains.push_back(initial_rhs);
 
  190  for (
int i = 0; 
i + 1 < free_vars.size(); ++
i) {
 
  197    rhs_domains.push_back(term.
AdditionWith(rhs_domains.back()));
 
  199  std::vector<int64_t> values(free_vars.size());
 
  200  for (
int i = free_vars.size() - 1; 
i >= 0; --
i) {
 
  204    const int var = free_vars[
i];
 
  205    const int64_t coeff = free_coeffs[
i];
 
  206    const Domain domain = rhs_domains[
i]
 
  207                              .AdditionWith(
Domain(-fixed_activity))
 
  208                              .InverseMultiplicationBy(coeff)
 
  209                              .IntersectionWith((*domains)[var]);
 
  215      LOG(INFO) << 
"Empty domain while trying to assign " << var;
 
  216      for (
int i = 0; 
i < size; ++
i) {
 
  218        LOG(INFO) << var << 
" " << (*domains)[var];
 
  220      LOG(FATAL) << 
"Couldn't postsolve the constraint: " 
  227    fixed_activity += coeff * value;
 
  232  for (
int i = 0; 
i < free_vars.size(); ++
i) {
 
  233    (*domains)[free_vars[
i]] = 
Domain(values[
i]);
 
  236  DCHECK(initial_rhs.
Contains(fixed_activity));
 
 
  242int64_t EvaluateLinearExpression(
const LinearExpressionProto& expr,
 
  243                                 absl::Span<const Domain> domains) {
 
  244  int64_t value = expr.offset();
 
  245  for (
int i = 0; 
i < expr.vars_size(); ++
i) {
 
  246    const int ref = expr.vars(
i);
 
  247    const int64_t increment =
 
  255                             absl::Span<const Domain> domains) {
 
  256  for (
const int var : expr.vars()) {
 
  257    if (!domains[var].
IsFixed()) 
return false;
 
  268  int64_t max_value = std::numeric_limits<int64_t>::min();
 
  272    max_value = std::max(max_value, EvaluateLinearExpression(expr, *domains));
 
  276  CHECK_EQ(target.
vars().size(), 1);
 
  279  max_value -= target.
offset();
 
  280  CHECK_EQ(max_value % target.
coeffs(0), 0);
 
  281  max_value /= target.
coeffs(0);
 
  282  (*domains)[target.
vars(0)] = 
Domain(max_value);
 
 
  291  DCHECK(LinearExpressionIsFixed(index, *domains) ||
 
  292         LinearExpressionIsFixed(target, *domains));
 
  295  if (LinearExpressionIsFixed(index, *domains)) {
 
  296    const int64_t index_value = EvaluateLinearExpression(index, *domains);
 
  298    DCHECK(LinearExpressionIsFixed(expr, *domains));
 
  299    const int64_t expr_value = EvaluateLinearExpression(expr, *domains);
 
  300    if (target.
vars().empty()) {
 
  301      DCHECK_EQ(expr_value, target.
offset());
 
  309  const int64_t target_value = EvaluateLinearExpression(target, *domains);
 
  310  int selected_index_value = -1;
 
  311  for (
const int64_t v : (*domains)[index.
vars(0)].Values()) {
 
  312    const int64_t index_value = index.
offset() + v * index.
coeffs(0);
 
  313    DCHECK_GE(index_value, 0);
 
  317    const int64_t value = EvaluateLinearExpression(expr, *domains);
 
  318    if (value == target_value) {
 
  319      selected_index_value = index_value;
 
  324  CHECK_NE(selected_index_value, -1);
 
  325  (*domains)[index.
vars(0)] =
 
 
  331  const int64_t exp = EvaluateLinearExpression(ct.
int_mod().
exprs(0), *domains);
 
  332  const int64_t mod = EvaluateLinearExpression(ct.
int_mod().
exprs(1), *domains);
 
  334  const int64_t target_value = exp % mod;
 
  337  CHECK_EQ(target.
vars().size(), 1);
 
  338  const int64_t term_value = target_value - target.
offset();
 
  339  CHECK_EQ(term_value % target.
coeffs(0), 0);
 
  340  const int64_t value = term_value / target.
coeffs(0);
 
  341  CHECK((*domains)[target.
vars(0)].Contains(value));
 
 
  347  int64_t target_value = 1;
 
  349    target_value *= EvaluateLinearExpression(expr, *domains);
 
  353  CHECK_EQ(target.
vars().size(), 1);
 
  356  target_value -= target.
offset();
 
  357  CHECK_EQ(target_value % target.
coeffs(0), 0);
 
  358  target_value /= target.
coeffs(0);
 
  359  (*domains)[target.
vars(0)] = 
Domain(target_value);
 
 
  363void CheckPostsolveFixedVariables(
const ConstraintProto& ct,
 
  364                                  absl::Span<const Domain> domains) {
 
  369          << 
" is not fixed after postsolve for constraint: \"" 
  371          << 
"\" with domain: " << domains[
PositiveRef(var)] << 
".";
 
  377                             absl::Span<Domain> domains) {
 
  388                       absl::Span<const int> postsolve_mapping,
 
  390  CHECK_EQ(
solution->size(), postsolve_mapping.size());
 
  395  for (
int i = 0; 
i < postsolve_mapping.size(); ++
i) {
 
  396    CHECK_LE(postsolve_mapping[
i], domains.size());
 
  399  for (
int i = 0; 
i < domains.size(); ++
i) {
 
  400    if (domains[
i].IsEmpty()) {
 
  403    CHECK(!domains[
i].IsEmpty());
 
  408  for (
int i = num_constraints - 1; 
i >= 0; 
i--) {
 
  413    bool constraint_can_be_ignored = 
false;
 
  416      const bool is_false =
 
  417          domains[var].IsFixed() &&
 
  420        constraint_can_be_ignored = 
true;
 
  424    if (constraint_can_be_ignored) {
 
  425      ArbitrarilyFixVariables(ct, absl::MakeSpan(domains));
 
  426      CheckPostsolveFixedVariables(ct, domains);
 
  455        LOG(FATAL) << 
"Unsupported constraint: " 
  458    CheckPostsolveFixedVariables(ct, domains);
 
  464  CHECK_LE(num_variables_in_original_model, domains.size());
 
  465  for (
int i = 0; 
i < num_variables_in_original_model; ++
i) {
 
  466    solution->push_back(domains[
i].SmallestValue());
 
 
  472                                   absl::Span<const int> postsolve_mapping,
 
  473                                   absl::Span<const Domain> search_domains,
 
  477  const int num_original_vars = original_model.
variables().size();
 
  478  const int num_expanded_vars = mapping_proto.
variables().size();
 
  479  CHECK_LE(num_original_vars, num_expanded_vars);
 
  480  std::vector<Domain> domains(num_expanded_vars);
 
  484  for (
int i = 0; 
i < num_expanded_vars; ++
i) {
 
  486    if (
i < num_original_vars) {
 
  487      CHECK(domains[
i].IsIncludedIn(
 
  494  int num_common_vars = 0;
 
  495  int num_affine_reductions = 0;
 
  496  if (!search_domains.empty()) {
 
  497    if (postsolve_mapping.empty()) {
 
  503      CHECK_GE(search_domains.size(), num_original_vars);
 
  504      num_common_vars = num_original_vars;
 
  505      for (
int i = 0; 
i < num_original_vars; ++
i) {
 
  506        domains[
i] = domains[
i].IntersectionWith(search_domains[
i]);
 
  511      CHECK_EQ(postsolve_mapping.size(), search_domains.size());
 
  512      for (
int search_i = 0; search_i < postsolve_mapping.size(); ++search_i) {
 
  513        const int i_in_mapping_model = postsolve_mapping[search_i];
 
  514        if (i_in_mapping_model < num_original_vars) {
 
  517        domains[i_in_mapping_model] =
 
  518            domains[i_in_mapping_model].IntersectionWith(
 
  519                search_domains[search_i]);
 
  526        if (lin.
vars().size() != 2) 
continue;
 
  527        if (lin.
domain().size() != 2) 
continue;
 
  530        int v2 = lin.
vars(1);
 
  533        if (v2 < num_original_vars && v1 >= num_original_vars) {
 
  537        if (v1 < num_original_vars && v2 >= num_original_vars) {
 
  541          const int64_t offset = lin.
domain(0);
 
  542          const Domain restriction =
 
  544                  .
AdditionWith(domains[v2].ContinuousMultiplicationBy(-c2))
 
  546          if (!domains[
v1].IsIncludedIn(restriction)) {
 
  547            ++num_affine_reductions;
 
  548            domains[
v1] = domains[
v1].IntersectionWith(restriction);
 
  557  int num_tigher_domains = 0;
 
  560  for (
int i = 0; 
i < num_original_vars; ++
i) {
 
  562    if (domains[
i].IsEmpty()) {
 
  567    if (domains[
i].
IsFixed()) num_fixed++;
 
  569    if (domains[
i] != original) {
 
  570      DCHECK(domains[
i].IsIncludedIn(original));
 
  571      ++num_tigher_domains;
 
  578               " tightened domains are empty. This should not happen except if " 
  579               "we proven infeasibility or optimality.");
 
  581  SOLVER_LOG(logger, 
"Filled tightened domains in the response.");
 
  582  SOLVER_LOG(logger, 
"[TighteningInfo] num_tighter:", num_tigher_domains,
 
  583             " num_fixed:", num_fixed,
 
  584             " num_affine_reductions:", num_affine_reductions);
 
  586             "[TighteningInfo] original_num_variables:", num_original_vars,
 
  587             " during_presolve:", num_expanded_vars,
 
  588             " after:", search_domains.size(), 
" in_common:", num_common_vars);
 
 
Domain MultiplicationBy(int64_t coeff, bool *exact=nullptr) const
Domain IntersectionWith(const Domain &domain) const
bool Contains(int64_t value) const
Domain AdditionWith(const Domain &domain) const
int64_t SmallestValue() const
Domain InverseMultiplicationBy(int64_t coeff) const
::int32_t literals(int index) const
int literals_size() const
repeated int32 literals = 1;
ConstraintCase constraint_case() const
::int32_t enforcement_literal(int index) const
const ::operations_research::sat::BoolArgumentProto & exactly_one() const
const ::operations_research::sat::LinearConstraintProto & linear() const
const ::operations_research::sat::LinearArgumentProto & lin_max() const
const ::operations_research::sat::ElementConstraintProto & element() const
const ::operations_research::sat::BoolArgumentProto & bool_or() const
const ::operations_research::sat::LinearArgumentProto & int_mod() const
const ::operations_research::sat::LinearArgumentProto & int_prod() const
const ::operations_research::sat::IntegerVariableProto & variables(int index) const
const ::operations_research::sat::ConstraintProto & constraints(int index) const
int constraints_size() const
repeated .operations_research.sat.ConstraintProto constraints = 3;
int variables_size() const
repeated .operations_research.sat.IntegerVariableProto variables = 2;
::operations_research::sat::IntegerVariableProto *PROTOBUF_NONNULL mutable_tightened_variables(int index)
int exprs_size() const
repeated .operations_research.sat.LinearExpressionProto exprs = 6;
const ::operations_research::sat::LinearExpressionProto & exprs(int index) const
const ::operations_research::sat::LinearExpressionProto & linear_target() const
const ::operations_research::sat::LinearExpressionProto & linear_index() const
const ::operations_research::sat::LinearExpressionProto & exprs(int index) const
const ::operations_research::sat::LinearExpressionProto & target() const
::int32_t vars(int index) const
::int64_t coeffs(int index) const
::int64_t domain(int index) const
::int64_t coeffs(int index) const
::int32_t vars(int index) const
void PostsolveElement(const ConstraintProto &ct, std::vector< Domain > *domains)
void PostsolveLinear(const ConstraintProto &ct, std::vector< Domain > *domains)
bool RefIsPositive(int ref)
std::function< bool(const Model &)> IsFixed(IntegerVariable v)
int64_t GetInnerVarValue(const LinearExpressionProto &expr, int64_t value)
void PostsolveExactlyOne(const ConstraintProto &ct, std::vector< Domain > *domains)
void SetEnforcementLiteralToFalse(const ConstraintProto &ct, std::vector< Domain > *domains)
void PostsolveIntProd(const ConstraintProto &ct, std::vector< Domain > *domains)
We only support assigning to an affine target.
std::vector< int > UsedVariables(const ConstraintProto &ct)
void PostsolveLinMax(const ConstraintProto &ct, std::vector< Domain > *domains)
void FillDomainInProto(const Domain &domain, ProtoWithDomain *proto)
Serializes a Domain into the domain field of a proto.
void PostsolveIntMod(const ConstraintProto &ct, std::vector< Domain > *domains)
We only support assigning to an affine target.
Domain ReadDomainFromProto(const ProtoWithDomain &proto)
Reads a Domain from the domain field of a proto.
void PostsolveClause(const ConstraintProto &ct, std::vector< Domain > *domains)
void PostsolveResponse(const int64_t num_variables_in_original_model, const CpModelProto &mapping_proto, absl::Span< const int > postsolve_mapping, std::vector< int64_t > *solution)
void FillTightenedDomainInResponse(const CpModelProto &original_model, const CpModelProto &mapping_proto, absl::Span< const int > postsolve_mapping, absl::Span< const Domain > search_domains, CpSolverResponse *response, SolverLogger *logger)
In SWIG mode, we don't want anything besides these top-level includes.
Select next search node to expand Select next item_i to add this new search node to the search Generate a new search node where item_i is not in the knapsack Check validity of this new partial solution(using propagators) - If valid
std::string ProtobufShortDebugString(const P &message)
#define SOLVER_LOG(logger,...)