ortools/sat/linear_programming_constraint.cc
bool LinearProgrammingConstraint::ExactLpReasonning() {
  // Clear old reason and deductions.
  integer_reason_.clear();
  deductions_.clear();
  deductions_reason_.clear();

  // The row multipliers will be the negation of the LP duals.
  //
  // TODO(user): Provide and use a sparse API in Glop to get the duals.
  const RowIndex num_rows = simplex_.GetProblemNumRows();
  glop::DenseColumn lp_multipliers(num_rows);
  for (RowIndex row(0); row < num_rows; ++row) {
    lp_multipliers[row] = -simplex_.GetDualValue(row);
  }

  Fractional scaling;
  std::vector<std::pair<RowIndex, IntegerValue>> integer_multipliers =
      ScaleLpMultiplier(/*take_objective_into_account=*/true,
                        /*use_constraint_status=*/false, lp_multipliers,
                        &scaling);

  gtl::ITIVector<ColIndex, IntegerValue> reduced_costs;
  IntegerValue rc_ub;
  CHECK(ComputeNewLinearConstraint(
      /*use_constraint_status=*/false, integer_multipliers, &reduced_costs,
      &rc_ub));

  // The "objective constraint" behave like if the unscaled cp multiplier was
  // 1.0, so we will multiply it by this number and add it to reduced_costs.
  const IntegerValue obj_scale(std::round(scaling));
  if (obj_scale == 0) {
    VLOG(1) << "Overflow during exact LP reasoning. scaling=" << scaling;
    return true;
  }
  CHECK(AddLinearExpressionMultiple(obj_scale, integer_objective_,
                                    &reduced_costs));

  AdjustNewLinearConstraint(&integer_multipliers, &reduced_costs, &rc_ub);

  // Create the IntegerSumLE that will allow to propagate the objective and more
  // generally do the reduced cost fixing.
  LinearConstraint new_constraint =
      ConvertToLinearConstraint(reduced_costs, rc_ub);
  new_constraint.vars.push_back(objective_cp_);
  new_constraint.coeffs.push_back(-obj_scale);
  DivideByGCD(&new_constraint);

  // Check for possible overflow in IntegerSumLE::Propagate().
  if (PossibleOverflow(new_constraint)) {
    VLOG(2) << "Overflow during exact LP reasoning.";
    return true;
  }

  IntegerSumLE* cp_constraint =
      new IntegerSumLE({}, new_constraint.vars, new_constraint.coeffs,
                       new_constraint.ub, model_);
  optimal_constraints_.emplace_back(cp_constraint);
  rev_optimal_constraints_size_ = optimal_constraints_.size();
  return cp_constraint->Propagate();
}
// The "exact" computation go as follow:
//
// Given any INTEGER linear combination of the LP constraints, we can create a
// new integer constraint that is valid (its computation must not overflow
// though). Lets call this "linear_combination <= ub". We can then always add to
// it the inequality "objective_terms <= objective_var", so we get:
// ImpliedLB(objective_terms + linear_combination) - ub <= objective_var.
// where ImpliedLB() is computed from the variable current bounds.
//
// Now, if we use for the linear combination and approximation of the optimal
// negated dual LP values (by scaling them and rounding them to integer), we
// will get an EXACT objective lower bound that is more or less the same as the
// inexact bound given by the LP relaxation. This allows to derive exact reasons
// for any propagation done by this constraint.
The "exact" computation go as follow:
Given any INTEGER linear combination of the LP constraints, we can create a
new integer constraint that is valid (its computation must not overflow
though). Lets call this "linear_combination <= ub". We can then always add to
it the inequality "objective_terms <= objective_var", so we get:
ImpliedLB(objective_terms + linear_combination) - ub <= objective_var.
where ImpliedLB() is computed from the variable current bounds.

Now, if we use for the linear combination and approximation of the optimal
negated dual LP values (by scaling them and rounding them to integer), we
will get an EXACT objective lower bound that is more or less the same as the
inexact bound given by the LP relaxation. This allows to derive exact reasons
for any propagation done by this constraint.
The " exact " computation go as follow : Given any INTEGER linear combination of the LP constraints we can create a new integer constraint that is valid ( its computation must not overflow though ) . Lets call this " linear_combination < = ub " . We can then always add to it the inequality " objective_terms < = objective_var " so we get : ImpliedLB ( objective_terms + linear_combination ) - ub < = objective_var . where ImpliedLB () is computed from the variable current bounds . Now if we use for the linear combination and approximation of the optimal negated dual LP values ( by scaling them and rounding them to integer ) we will get an EXACT objective lower bound that is more or less the same as the inexact bound given by the LP relaxation . This allows to derive exact reasons for any propagation done by this constraint .
bool LinearProgrammingConstraint::ExactLpReasonning() {
  integer_reason_.clear();
  deductions_.clear();
  deductions_reason_.clear();
   TODO(user): Provide and use a sparse API in Glop to get the duals.
  const RowIndex num_rows = simplex_.GetProblemNumRows();
  glop::DenseColumn lp_multipliers(num_rows);
  for (RowIndex row(0); row < num_rows; ++row) {
    lp_multipliers[row] = -simplex_.GetDualValue(row);
  }
  Fractional scaling;
  std::vector<std::pair<RowIndex, IntegerValue>> integer_multipliers =
      ScaleLpMultiplier(true,
                        false, lp_multipliers,
                        &scaling);
  gtl::ITIVector<ColIndex, IntegerValue> reduced_costs;
  IntegerValue rc_ub;
  CHECK(ComputeNewLinearConstraint(
      false, integer_multipliers, &reduced_costs,
      &rc_ub));
   The "objective constraint" behave like if the unscaled cp multiplier was
   1.0, so we will multiply it by this number and add it to reduced_costs.
  const IntegerValue obj_scale(std::round(scaling));
  if (obj_scale == 0) {
    VLOG(1) << "Overflow during exact LP reasoning. scaling=" << scaling;
    return true;
  }
  CHECK(AddLinearExpressionMultiple(obj_scale, integer_objective_,
                                    &reduced_costs));
  AdjustNewLinearConstraint(&integer_multipliers, &reduced_costs, &rc_ub);
   Create the IntegerSumLE that will allow to propagate the objective and more
   generally do the reduced cost fixing.
  LinearConstraint new_constraint =
      ConvertToLinearConstraint(reduced_costs, rc_ub);
  new_constraint.vars.push_back(objective_cp_);
  new_constraint.coeffs.push_back(-obj_scale);
  DivideByGCD(&new_constraint);
   Check for possible overflow in IntegerSumLE::Propagate().
  if (PossibleOverflow(new_constraint)) {
    VLOG(2) << "Overflow during exact LP reasoning.";
    return true;
  }
  IntegerSumLE* cp_constraint =
      new IntegerSumLE({}, new_constraint.vars, new_constraint.coeffs,
                       new_constraint.ub, model_);
  optimal_constraints_.emplace_back(cp_constraint);
  rev_optimal_constraints_size_ = optimal_constraints_.size();
  return cp_constraint->Propagate();
}
bool LinearProgrammingConstraint :: ExactLpReasonning ( ) { integer_reason_ . clear ( ) ; deductions_ . clear ( ) ; deductions_reason_ . clear ( ) ; const RowIndex num_rows = simplex_ . GetProblemNumRows ( ) ; glop :: DenseColumn lp_multipliers ( num_rows ) ; for ( RowIndex row ( 0 ) ; row < num_rows ; ++ row ) { lp_multipliers [ row ] = - simplex_ . GetDualValue ( row ) ; } Fractional scaling ; std :: vector < std :: pair < RowIndex , IntegerValue > > integer_multipliers = ScaleLpMultiplier ( true , false , lp_multipliers , & scaling ) ; gtl :: ITIVector < ColIndex , IntegerValue > reduced_costs ; IntegerValue rc_ub ; CHECK ( ComputeNewLinearConstraint ( false , integer_multipliers , & reduced_costs , & rc_ub ) ) ; const IntegerValue obj_scale ( std :: round ( scaling ) ) ; if ( obj_scale == 0 ) { VLOG ( 1 ) << " " << scaling ; return true ; } CHECK ( AddLinearExpressionMultiple ( obj_scale , integer_objective_ , & reduced_costs ) ) ; AdjustNewLinearConstraint ( & integer_multipliers , & reduced_costs , & rc_ub ) ; LinearConstraint new_constraint = ConvertToLinearConstraint ( reduced_costs , rc_ub ) ; new_constraint . vars . push_back ( objective_cp_ ) ; new_constraint . coeffs . push_back ( - obj_scale ) ; DivideByGCD ( & new_constraint ) ; if ( PossibleOverflow ( new_constraint ) ) { VLOG ( 2 ) << " " ; return true ; } IntegerSumLE * cp_constraint = new IntegerSumLE ( { } , new_constraint . vars , new_constraint . coeffs , new_constraint . ub , model_ ) ; optimal_constraints_ . emplace_back ( cp_constraint ) ; rev_optimal_constraints_size_ = optimal_constraints_ . size ( ) ; return cp_constraint -> Propagate ( ) ; }
The "exact" computation go as follow:
Given any INTEGER linear combination of the LP constraints, we can create a
new integer constraint that is valid (its computation must not overflow
though).
The " exact " computation go as follow : Given any INTEGER linear combination of the LP constraints we can create a new integer constraint that is valid ( its computation must not overflow though ) .
// Clear old reason and deductions. // The row multipliers will be the negation of the LP duals. // // TODO(user): Provide and use a sparse API in Glop to get the duals. /*take_objective_into_account=*/ /*use_constraint_status=*/ /*use_constraint_status=*/ // The "objective constraint" behave like if the unscaled cp multiplier was // 1.0, so we will multiply it by this number and add it to reduced_costs. // Create the IntegerSumLE that will allow to propagate the objective and more // generally do the reduced cost fixing. // Check for possible overflow in IntegerSumLE::Propagate().