23#include "absl/log/check.h"
24#include "absl/log/log.h"
34using ::operations_research::glop::ColIndex;
40using ::operations_research::glop::RowIndex;
52 if (std::isnan(lower_bound))
return false;
53 if (std::isnan(upper_bound))
return false;
56 if (lower_bound > upper_bound)
return false;
67 const Fractional tolerance = integer_solution_tolerance_;
72 int64_t num_changed_bounds = 0;
88 VLOG(2) <<
"IntegerBoundsPreprocessor changed " << num_changed_bounds
89 <<
" variable bounds.";
93 num_changed_bounds = 0;
94 for (RowIndex row = RowIndex(0); row < linear_program->
num_constraints();
96 bool integer_constraint =
true;
100 integer_constraint =
false;
111 if (round(var.coefficient()) != var.coefficient()) {
112 integer_constraint =
false;
116 if (integer_constraint) {
127 num_changed_bounds++;
132 VLOG(2) <<
"IntegerBoundsPreprocessor changed " << num_changed_bounds
133 <<
" constraint bounds.";
151 const Fractional tolerance = integer_solution_tolerance_;
156 std::deque<RowIndex> to_process;
157 for (RowIndex row(0); row < linear_program->
num_constraints(); ++row) {
158 to_process.push_back(row);
159 in_queue[row] =
true;
168 const int kMaxNumberOfProcessedRows =
170 for (
int i = 0; i < kMaxNumberOfProcessedRows && !to_process.empty(); ++i) {
171 const RowIndex row = to_process.front();
172 in_queue[row] =
false;
173 to_process.pop_front();
185 const ColIndex col = RowToColIndex(e.row());
190 if (e.coefficient() < 0.0) std::swap(entry_lb, entry_ub);
198 lb_sum.
Add(entry_lb);
199 ub_sum.
Add(entry_ub);
221 if (coeff < 0.0) std::swap(entry_lb, entry_ub);
229 if (coeff < 0.0) std::swap(implied_lb, implied_ub);
233 implied_lb = std::ceil(implied_lb - tolerance);
234 implied_ub = std::floor(implied_ub + tolerance);
239 if (implied_lb > var_lb || implied_ub < var_ub) {
240 Fractional new_lb = std::max(implied_lb, var_lb);
241 Fractional new_ub = std::min(implied_ub, var_ub);
242 if (new_lb > new_ub) {
244 if (new_lb - tolerance > new_ub) {
251 new_lb = new_ub = round(new_lb);
253 new_lb = new_ub = (new_lb + new_ub) / 2.0;
260 if (new_ub != var_ub || new_lb != var_lb) {
263 if (!in_queue[e.row()]) {
264 to_process.push_back(e.row());
265 in_queue[e.row()] =
true;
272 if (!to_process.empty()) {
273 LOG_FIRST_N(WARNING, 10)
274 <<
"Propagation limit reached in the BoundPropagationPreprocessor, "
275 <<
"maybe the limit should be increased.";
278 integer_solution_tolerance_));
280 integer_solution_tolerance_));
290 int64_t num_implied_integer_variables = 0;
291 const Fractional tolerance = integer_solution_tolerance_;
292 for (ColIndex col(0); col < linear_program->
num_variables(); ++col) {
301 const bool is_implied_integer =
302 VariableOccursInAtLeastOneEqualityConstraint(*linear_program, col)
303 ? AnyEqualityConstraintImpliesIntegrality(*linear_program, col)
304 : AllInequalityConstraintsImplyIntegrality(*linear_program, col);
306 if (is_implied_integer) {
309 num_implied_integer_variables++;
310 VLOG(2) <<
"Marked col " << col <<
" implied integer.";
325 VLOG(2) <<
"ImpliedIntegerPreprocessor detected "
326 << num_implied_integer_variables <<
" implied integer variables.";
329 integer_solution_tolerance_));
340bool ImpliedIntegerPreprocessor::AnyEqualityConstraintImpliesIntegrality(
341 const LinearProgram& linear_program, ColIndex variable) {
347 if (ConstraintSupportsImpliedIntegrality(linear_program, variable,
356bool ImpliedIntegerPreprocessor::AllInequalityConstraintsImplyIntegrality(
357 const LinearProgram& linear_program, ColIndex variable) {
377 if (std::ceil(lower_bound) > std::floor(upper_bound))
return false;
383 if (!ConstraintSupportsImpliedIntegrality(linear_program, variable,
391bool ImpliedIntegerPreprocessor::ConstraintSupportsImpliedIntegrality(
392 const LinearProgram& linear_program, ColIndex variable, RowIndex row) {
393 const SparseMatrix& coefficients_transpose =
401 if (col == variable)
continue;
410 entry.coefficient() / variable_coefficient;
412 integer_solution_tolerance_)) {
420 const Fractional constraint_lower_bound_ratio =
423 integer_solution_tolerance_)) {
428 const Fractional constraint_upper_bound_ratio =
431 integer_solution_tolerance_)) {
438bool ImpliedIntegerPreprocessor::VariableOccursInAtLeastOneEqualityConstraint(
439 const LinearProgram& linear_program, ColIndex variable) {
456 LinearProgram* linear_program) {
461 for (RowIndex row(0); row < num_constraints; ++row) {
464 Fractional min_cost = std::numeric_limits<Fractional>::infinity();
465 bool constraint_is_exclusive_or =
true;
467 const ColIndex var = RowToColIndex(e.row());
471 e.coefficient() != 1.0) {
472 constraint_is_exclusive_or =
false;
478 if (constraint_is_exclusive_or && min_cost > 0.0 &&
481 const ColIndex var = RowToColIndex(e.row());
bool Run(glop::LinearProgram *linear_program) override
bool Run(glop::LinearProgram *linear_program) override
bool Run(glop::LinearProgram *linear_program) override
bool Run(glop::LinearProgram *linear_program) override
bool BoundsOfIntegerConstraintsAreInteger(Fractional tolerance) const
const DenseRow & objective_coefficients() const
bool BoundsOfIntegerVariablesAreInteger(Fractional tolerance) const
void SetObjectiveOffset(Fractional objective_offset)
void SetObjectiveCoefficient(ColIndex col, Fractional value)
const DenseColumn & constraint_lower_bounds() const
const SparseMatrix & GetTransposeSparseMatrix() const
const DenseRow & variable_lower_bounds() const
void SetVariableBounds(ColIndex col, Fractional lower_bound, Fractional upper_bound)
const std::vector< ColIndex > & IntegerVariablesList() const
void SetVariableType(ColIndex col, VariableType type)
void SetConstraintBounds(RowIndex row, Fractional lower_bound, Fractional upper_bound)
const DenseRow & variable_upper_bounds() const
VariableType GetVariableType(ColIndex col) const
const DenseColumn & constraint_upper_bounds() const
const SparseColumn & GetSparseColumn(ColIndex col) const
bool IsVariableInteger(ColIndex col) const
ColIndex num_variables() const
ColIndex GetFirstSlackVariable() const
Fractional objective_offset() const
RowIndex num_constraints() const
const SparseColumn & column(ColIndex col) const
Fractional LookUpValue(RowIndex row, ColIndex col) const
typename Iterator::Entry Entry
Fractional SumWithout(Fractional x) const
RowIndex ColToRowIndex(ColIndex col)
constexpr ColIndex kInvalidCol(-1)
SumWithOneMissing< true > SumWithPositiveInfiniteAndOneMissing
ColIndex RowToColIndex(RowIndex row)
bool IsFinite(Fractional value)
RowIndex ColToRowIndex(ColIndex col)
constexpr Fractional kInfinity
SumWithOneMissing< false > SumWithNegativeInfiniteAndOneMissing
bool IsIntegerWithinTolerance(FloatType x, FloatType tolerance)
static constexpr double kInfinity
bool AreBoundsValid(Fractional lower_bound, Fractional upper_bound)
#define RETURN_VALUE_IF_NULL(x, v)
#define SCOPED_INSTRUCTION_COUNT(time_limit)