diff --git a/ortools/glop/lp_solver.cc b/ortools/glop/lp_solver.cc index 278cb78c39..efaa396ff3 100644 --- a/ortools/glop/lp_solver.cc +++ b/ortools/glop/lp_solver.cc @@ -143,22 +143,6 @@ ProblemStatus LPSolver::SolveWithTimeLimit(const LinearProgram& lp, num_revised_simplex_iterations_ = 0; DumpLinearProgramIfRequiredByFlags(lp, num_solves_); - // Check some preconditions. - if (!lp.IsCleanedUp()) { - LOG(DFATAL) << "The columns of the given linear program should be ordered " - << "by row and contain no zero coefficients. Call CleanUp() " - << "on it before calling Solve()."; - ResizeSolution(lp.num_constraints(), lp.num_variables()); - return ProblemStatus::INVALID_PROBLEM; - } - if (!lp.IsValid()) { - LOG(DFATAL) << "The given linear program is invalid. It contains NaNs, " - << "infinite coefficients or invalid bounds specification. " - << "You can construct it in debug mode to get the exact cause."; - ResizeSolution(lp.num_constraints(), lp.num_variables()); - return ProblemStatus::INVALID_PROBLEM; - } - // Display a warning if running in non-opt, unless we're inside a unit test. DLOG(WARNING) << "\n******************************************************************" @@ -176,13 +160,32 @@ ProblemStatus LPSolver::SolveWithTimeLimit(const LinearProgram& lp, logger_.SetLogToStdOut(false); } - // Make an internal copy of the problem for the preprocessing. + // Log some initial info about the input model. if (logger_.LoggingIsEnabled()) { SOLVER_LOG(&logger_, ""); SOLVER_LOG(&logger_, "Initial problem: ", lp.GetDimensionString()); SOLVER_LOG(&logger_, "Objective stats: ", lp.GetObjectiveStatsString()); SOLVER_LOG(&logger_, "Bounds stats: ", lp.GetBoundsStatsString()); } + + // Check some preconditions. + if (!lp.IsCleanedUp()) { + LOG(DFATAL) << "The columns of the given linear program should be ordered " + << "by row and contain no zero coefficients. Call CleanUp() " + << "on it before calling Solve()."; + ResizeSolution(lp.num_constraints(), lp.num_variables()); + return ProblemStatus::INVALID_PROBLEM; + } + if (!lp.IsValid()) { + SOLVER_LOG(&logger_, + "The given linear program is invalid. It contains NaNs, " + "infinite coefficients or invalid bounds specification. " + "You can construct it in debug mode to get the exact cause."); + ResizeSolution(lp.num_constraints(), lp.num_variables()); + return ProblemStatus::INVALID_PROBLEM; + } + + // Make an internal copy of the problem for the preprocessing. current_linear_program_.PopulateFromLinearProgram(lp); // Preprocess. diff --git a/ortools/glop/preprocessor.cc b/ortools/glop/preprocessor.cc index 22c290b1b0..70a6d37eeb 100644 --- a/ortools/glop/preprocessor.cc +++ b/ortools/glop/preprocessor.cc @@ -2862,10 +2862,17 @@ bool SingletonPreprocessor::Run(LinearProgram* lp) { // a cost of zero first. if (lp->objective_coefficients()[col] == 0.0) { DeleteZeroCostSingletonColumn(transpose, e, lp); - } else if (MakeConstraintAnEqualityIfPossible(transpose, e, lp)) { - DeleteSingletonColumnInEquality(transpose, e, lp); } else { - continue; + // We don't want to do a substitution if the entry is too small and + // should be probably set to zero. + if (std::abs(e.coeff) < parameters_.preprocessor_zero_tolerance()) { + continue; + } + if (MakeConstraintAnEqualityIfPossible(transpose, e, lp)) { + DeleteSingletonColumnInEquality(transpose, e, lp); + } else { + continue; + } } --row_degree[e.row]; if (row_degree[e.row] == 1) {