From a9dd4aec9a4a2a5cf1b6a241ae760a213a9f9d2e Mon Sep 17 00:00:00 2001 From: Laurent Perron Date: Tue, 24 Jul 2018 09:32:14 -0700 Subject: [PATCH] Remove CoeffMap typedef in linear_solver --- ortools/linear_solver/bop_interface.cc | 4 +- ortools/linear_solver/cbc_interface.cc | 2 +- ortools/linear_solver/clp_interface.cc | 10 +- ortools/linear_solver/glop_interface.cc | 4 +- ortools/linear_solver/glpk_interface.cc | 8 +- ortools/linear_solver/gurobi_interface.cc | 118 ++++++++++++++++------ ortools/linear_solver/linear_solver.cc | 24 ++--- ortools/linear_solver/linear_solver.h | 39 ++++--- ortools/linear_solver/linear_solver.proto | 8 ++ ortools/linear_solver/scip_interface.cc | 10 +- 10 files changed, 143 insertions(+), 84 deletions(-) diff --git a/ortools/linear_solver/bop_interface.cc b/ortools/linear_solver/bop_interface.cc index 5851ae63e5..2c4edf6e5c 100644 --- a/ortools/linear_solver/bop_interface.cc +++ b/ortools/linear_solver/bop_interface.cc @@ -331,7 +331,7 @@ void BopInterface::ExtractNewConstraints() { DCHECK_EQ(new_row, row); linear_program_.SetConstraintBounds(row, lb, ub); - for (CoeffEntry entry : ct->coefficients_) { + for (const auto& entry : ct->coefficients_) { const int var_index = entry.first->index(); DCHECK(variable_is_extracted(var_index)); const glop::ColIndex col(var_index); @@ -344,7 +344,7 @@ void BopInterface::ExtractNewConstraints() { // TODO(user): remove duplication with GlopInterface. void BopInterface::ExtractObjective() { linear_program_.SetObjectiveOffset(solver_->Objective().offset()); - for (CoeffEntry entry : solver_->objective_->coefficients_) { + for (const auto& entry : solver_->objective_->coefficients_) { const int var_index = entry.first->index(); const glop::ColIndex col(var_index); const double coeff = entry.second; diff --git a/ortools/linear_solver/cbc_interface.cc b/ortools/linear_solver/cbc_interface.cc index 2ec9760fd0..94943f2270 100644 --- a/ortools/linear_solver/cbc_interface.cc +++ b/ortools/linear_solver/cbc_interface.cc @@ -306,7 +306,7 @@ MPSolver::ResultStatus CBCInterface::Solve(const MPSolverParameters& param) { MPConstraint* const ct = solver_->constraints_[i]; const int size = ct->coefficients_.size(); int j = 0; - for (CoeffEntry entry : ct->coefficients_) { + for (const auto& entry : ct->coefficients_) { const int index = MPSolverVarIndexToCbcVarIndex(entry.first->index()); indices[j] = index; coefs[j] = entry.second; diff --git a/ortools/linear_solver/clp_interface.cc b/ortools/linear_solver/clp_interface.cc index 578bc0a61c..0e1e3cc6ad 100644 --- a/ortools/linear_solver/clp_interface.cc +++ b/ortools/linear_solver/clp_interface.cc @@ -217,7 +217,7 @@ void CLPInterface::ClearConstraint(MPConstraint* const constraint) { InvalidateSolutionSynchronization(); // Constraint may not have been extracted yet. if (!constraint_is_extracted(constraint->index())) return; - for (CoeffEntry entry : constraint->coefficients_) { + for (const auto& entry : constraint->coefficients_) { DCHECK(variable_is_extracted(entry.first->index())); clp_->modifyCoefficient(constraint->index(), MPSolverVarIndexToClpVarIndex(entry.first->index()), @@ -249,7 +249,7 @@ void CLPInterface::SetObjectiveOffset(double offset) { void CLPInterface::ClearObjective() { InvalidateSolutionSynchronization(); // Clear linear terms - for (CoeffEntry entry : solver_->objective_->coefficients_) { + for (const auto& entry : solver_->objective_->coefficients_) { const int mpsolver_var_index = entry.first->index(); // Variable may have not been extracted yet. if (!variable_is_extracted(mpsolver_var_index)) { @@ -323,7 +323,7 @@ void CLPInterface::ExtractNewVariables() { for (int i = 0; i < last_constraint_index_; i++) { MPConstraint* const ct = solver_->constraints_[i]; const int ct_index = ct->index(); - for (CoeffEntry entry : ct->coefficients_) { + for (const auto& entry : ct->coefficients_) { const int mpsolver_var_index = entry.first->index(); DCHECK(variable_is_extracted(mpsolver_var_index)); if (mpsolver_var_index >= last_variable_index_) { @@ -368,7 +368,7 @@ void CLPInterface::ExtractNewConstraints() { size = 1; } int j = 0; - for (CoeffEntry entry : ct->coefficients_) { + for (const auto& entry : ct->coefficients_) { const int mpsolver_var_index = entry.first->index(); DCHECK(variable_is_extracted(mpsolver_var_index)); indices[j] = MPSolverVarIndexToClpVarIndex(mpsolver_var_index); @@ -392,7 +392,7 @@ void CLPInterface::ExtractNewConstraints() { void CLPInterface::ExtractObjective() { // Linear objective: set objective coefficients for all variables // (some might have been modified) - for (CoeffEntry entry : solver_->objective_->coefficients_) { + for (const auto& entry : solver_->objective_->coefficients_) { clp_->setObjectiveCoefficient( MPSolverVarIndexToClpVarIndex(entry.first->index()), entry.second); } diff --git a/ortools/linear_solver/glop_interface.cc b/ortools/linear_solver/glop_interface.cc index 7103ab71d5..5b2dff4c54 100644 --- a/ortools/linear_solver/glop_interface.cc +++ b/ortools/linear_solver/glop_interface.cc @@ -304,7 +304,7 @@ void GLOPInterface::ExtractNewConstraints() { DCHECK_EQ(new_row, row); linear_program_.SetConstraintBounds(row, lb, ub); - for (CoeffEntry entry : ct->coefficients_) { + for (const auto& entry : ct->coefficients_) { const int var_index = entry.first->index(); DCHECK(variable_is_extracted(var_index)); const glop::ColIndex col(var_index); @@ -316,7 +316,7 @@ void GLOPInterface::ExtractNewConstraints() { void GLOPInterface::ExtractObjective() { linear_program_.SetObjectiveOffset(solver_->Objective().offset()); - for (CoeffEntry entry : solver_->objective_->coefficients_) { + for (const auto& entry : solver_->objective_->coefficients_) { const int var_index = entry.first->index(); const glop::ColIndex col(var_index); const double coeff = entry.second; diff --git a/ortools/linear_solver/glpk_interface.cc b/ortools/linear_solver/glpk_interface.cc index 2562399bfa..85faec6896 100644 --- a/ortools/linear_solver/glpk_interface.cc +++ b/ortools/linear_solver/glpk_interface.cc @@ -357,7 +357,7 @@ void GLPKInterface::SetObjectiveOffset(double value) { // Clear objective of all its terms (linear) void GLPKInterface::ClearObjective() { InvalidateSolutionSynchronization(); - for (CoeffEntry entry : solver_->objective_->coefficients_) { + for (const auto& entry : solver_->objective_->coefficients_) { const int mpsolver_var_index = entry.first->index(); // Variable may have not been extracted yet. if (!variable_is_extracted(mpsolver_var_index)) { @@ -432,7 +432,7 @@ void GLPKInterface::ExtractOneConstraint(MPConstraint* const constraint, double* const coefs) { // GLPK convention is to start indexing at 1. int k = 1; - for (CoeffEntry entry : constraint->coefficients_) { + for (const auto& entry : constraint->coefficients_) { DCHECK(variable_is_extracted(entry.first->index())); indices[k] = MPSolverIndexToGlpkIndex(entry.first->index()); coefs[k] = entry.second; @@ -477,7 +477,7 @@ void GLPKInterface::ExtractNewConstraints() { int k = 1; for (int i = 0; i < solver_->constraints_.size(); ++i) { MPConstraint* ct = solver_->constraints_[i]; - for (CoeffEntry entry : ct->coefficients_) { + for (const auto& entry : ct->coefficients_) { DCHECK(variable_is_extracted(entry.first->index())); constraint_indices[k] = MPSolverIndexToGlpkIndex(ct->index()); variable_indices[k] = MPSolverIndexToGlpkIndex(entry.first->index()); @@ -507,7 +507,7 @@ void GLPKInterface::ExtractNewConstraints() { void GLPKInterface::ExtractObjective() { // Linear objective: set objective coefficients for all variables // (some might have been modified). - for (CoeffEntry entry : solver_->objective_->coefficients_) { + for (const auto& entry : solver_->objective_->coefficients_) { glp_set_obj_coef(lp_, MPSolverIndexToGlpkIndex(entry.first->index()), entry.second); } diff --git a/ortools/linear_solver/gurobi_interface.cc b/ortools/linear_solver/gurobi_interface.cc index bf340eb1af..b8b76680b0 100644 --- a/ortools/linear_solver/gurobi_interface.cc +++ b/ortools/linear_solver/gurobi_interface.cc @@ -143,6 +143,9 @@ class GurobiInterface : public MPSolverInterface { // } } + // Iterates through the solutions in Gurobi's solution pool. + bool NextSolution() override; + private: // Sets all parameters in the underlying solver. void SetParameters(const MPSolverParameters& param) override; @@ -167,16 +170,21 @@ class GurobiInterface : public MPSolverInterface { << GRBgeterrormsg(env_); } - private: + int SolutionCount() const; + GRBmodel* model_; GRBenv* env_; bool mip_; + int current_solution_index_; }; // Creates a LP/MIP instance with the specified name and minimization objective. GurobiInterface::GurobiInterface(MPSolver* const solver, bool mip) - : MPSolverInterface(solver), model_(nullptr), env_(nullptr), mip_(mip) { - + : MPSolverInterface(solver), + model_(nullptr), + env_(nullptr), + mip_(mip), + current_solution_index_(0) { int ret = GRBloadenv(&env_, nullptr); if (ret != 0 || env_ == nullptr) { std::string err_msg = GRBgeterrormsg(env_); @@ -497,7 +505,7 @@ void GurobiInterface::ExtractNewConstraints() { CHECK(constraint_is_extracted(row)); const int size = ct->coefficients_.size(); int col = 0; - for (CoeffEntry entry : ct->coefficients_) { + for (const auto& entry : ct->coefficients_) { const int var_index = entry.first->index(); CHECK(variable_is_extracted(var_index)); col_indices[col] = var_index; @@ -621,6 +629,13 @@ void GurobiInterface::SetLpAlgorithm(int value) { } } +int GurobiInterface::SolutionCount() const { + int solution_count = 0; + CheckedGurobiCall( + GRBgetintattr(model_, GRB_INT_ATTR_SOLCOUNT, &solution_count)); + return solution_count; +} + MPSolver::ResultStatus GurobiInterface::Solve(const MPSolverParameters& param) { WallTimer timer; timer.Start(); @@ -681,9 +696,7 @@ MPSolver::ResultStatus GurobiInterface::Solve(const MPSolverParameters& param) { CheckedGurobiCall( GRBgetintattr(model_, GRB_INT_ATTR_STATUS, &optimization_status)); VLOG(1) << StringPrintf("Solution status %d.\n", optimization_status); - int solution_count = 0; - CheckedGurobiCall( - GRBgetintattr(model_, GRB_INT_ATTR_SOLCOUNT, &solution_count)); + const int solution_count = SolutionCount(); switch (optimization_status) { case GRB_OPTIMAL: @@ -714,41 +727,47 @@ MPSolver::ResultStatus GurobiInterface::Solve(const MPSolverParameters& param) { if (solution_count > 0 && (result_status_ == MPSolver::FEASIBLE || result_status_ == MPSolver::OPTIMAL)) { + current_solution_index_ = 0; // Get the results. const int total_num_rows = solver_->constraints_.size(); const int total_num_cols = solver_->variables_.size(); - std::unique_ptr values(new double[total_num_cols]); - std::unique_ptr dual_values(new double[total_num_rows]); - std::unique_ptr reduced_costs(new double[total_num_cols]); - - CheckedGurobiCall( - GRBgetdblattr(model_, GRB_DBL_ATTR_OBJVAL, &objective_value_)); - CheckedGurobiCall(GRBgetdblattrarray(model_, GRB_DBL_ATTR_X, 0, - total_num_cols, values.get())); - if (!mip_) { + { + std::vector variable_values(total_num_cols); + CheckedGurobiCall( + GRBgetdblattr(model_, GRB_DBL_ATTR_OBJVAL, &objective_value_)); CheckedGurobiCall(GRBgetdblattrarray( - model_, GRB_DBL_ATTR_RC, 0, total_num_cols, reduced_costs.get())); - CheckedGurobiCall(GRBgetdblattrarray(model_, GRB_DBL_ATTR_PI, 0, - total_num_rows, dual_values.get())); - } + model_, GRB_DBL_ATTR_X, 0, total_num_cols, variable_values.data())); - VLOG(1) << "objective = " << objective_value_; - for (int i = 0; i < solver_->variables_.size(); ++i) { - MPVariable* const var = solver_->variables_[i]; - var->set_solution_value(values[i]); - VLOG(3) << var->name() << ", value = " << values[i]; - if (!mip_) { - var->set_reduced_cost(reduced_costs[i]); - VLOG(4) << var->name() << ", reduced cost = " << reduced_costs[i]; + VLOG(1) << "objective = " << objective_value_; + for (int i = 0; i < solver_->variables_.size(); ++i) { + MPVariable* const var = solver_->variables_[i]; + var->set_solution_value(variable_values[i]); + VLOG(3) << var->name() << ", value = " << variable_values[i]; } } - if (!mip_) { - for (int i = 0; i < solver_->constraints_.size(); ++i) { - MPConstraint* const ct = solver_->constraints_[i]; - ct->set_dual_value(dual_values[i]); - VLOG(4) << "row " << ct->index() << ", dual value = " << dual_values[i]; + { + std::vector reduced_costs(total_num_cols); + CheckedGurobiCall(GRBgetdblattrarray( + model_, GRB_DBL_ATTR_RC, 0, total_num_cols, reduced_costs.data())); + for (int i = 0; i < solver_->variables_.size(); ++i) { + MPVariable* const var = solver_->variables_[i]; + var->set_reduced_cost(reduced_costs[i]); + VLOG(4) << var->name() << ", reduced cost = " << reduced_costs[i]; + } + } + + { + std::vector dual_values(total_num_rows); + CheckedGurobiCall(GRBgetdblattrarray( + model_, GRB_DBL_ATTR_PI, 0, total_num_rows, dual_values.data())); + for (int i = 0; i < solver_->constraints_.size(); ++i) { + MPConstraint* const ct = solver_->constraints_[i]; + ct->set_dual_value(dual_values[i]); + VLOG(4) << "row " << ct->index() + << ", dual value = " << dual_values[i]; + } } } } @@ -758,6 +777,39 @@ MPSolver::ResultStatus GurobiInterface::Solve(const MPSolverParameters& param) { return result_status_; } +bool GurobiInterface::NextSolution() { + // Next solution only supported for MIP + if (!mip_) return false; + + // Make sure we have successfully solved the problem and not modified it. + if (!CheckSolutionIsSynchronizedAndExists()) { + return false; + } + // Check if we are out of solutions. + if (current_solution_index_ + 1 >= SolutionCount()) { + return false; + } + current_solution_index_++; + + const int total_num_cols = solver_->variables_.size(); + std::vector variable_values(total_num_cols); + + CheckedGurobiCall(GRBsetintparam( + GRBgetenv(model_), GRB_INT_PAR_SOLUTIONNUMBER, current_solution_index_)); + + CheckedGurobiCall( + GRBgetdblattr(model_, GRB_DBL_ATTR_POOLOBJVAL, &objective_value_)); + CheckedGurobiCall(GRBgetdblattrarray(model_, GRB_DBL_ATTR_XN, 0, + total_num_cols, variable_values.data())); + for (int i = 0; i < solver_->variables_.size(); ++i) { + MPVariable* const var = solver_->variables_[i]; + var->set_solution_value(variable_values[i]); + } + // TODO(user,user): This reset may not be necessary, investigate. + GRBresetparams(GRBgetenv(model_)); + return true; +} + void GurobiInterface::Write(const std::string& filename) { if (sync_status_ == MUST_RELOAD) { Reset(); diff --git a/ortools/linear_solver/linear_solver.cc b/ortools/linear_solver/linear_solver.cc index 9cc3faf942..cbf0d5e8a9 100644 --- a/ortools/linear_solver/linear_solver.cc +++ b/ortools/linear_solver/linear_solver.cc @@ -75,7 +75,7 @@ void MPConstraint::SetCoefficient(const MPVariable* const var, double coeff) { DLOG_IF(DFATAL, !interface_->solver_->OwnsVariable(var)) << var; if (var == nullptr) return; if (coeff == 0.0) { - CoeffMap::iterator it = coefficients_.find(var); + auto it = coefficients_.find(var); // If setting a coefficient to 0 when this coefficient did not // exist or was already 0, do nothing: skip // interface_->SetCoefficient() and do not store a coefficient in @@ -90,8 +90,7 @@ void MPConstraint::SetCoefficient(const MPVariable* const var, double coeff) { } return; } - std::pair insertion_result = - coefficients_.insert(std::make_pair(var, coeff)); + auto insertion_result = coefficients_.insert(std::make_pair(var, coeff)); const double old_value = insertion_result.second ? 0.0 : insertion_result.first->second; insertion_result.first->second = coeff; @@ -135,7 +134,7 @@ MPSolver::BasisStatus MPConstraint::basis_status() const { bool MPConstraint::ContainsNewVariables() { const int last_variable_index = interface_->last_variable_index(); - for (CoeffEntry entry : coefficients_) { + for (const auto& entry : coefficients_) { const int variable_index = entry.first->index(); if (variable_index >= last_variable_index || !interface_->variable_is_extracted(variable_index)) { @@ -157,7 +156,7 @@ void MPObjective::SetCoefficient(const MPVariable* const var, double coeff) { DLOG_IF(DFATAL, !interface_->solver_->OwnsVariable(var)) << var; if (var == nullptr) return; if (coeff == 0.0) { - CoeffMap::iterator it = coefficients_.find(var); + auto it = coefficients_.find(var); // See the discussion on MPConstraint::SetCoefficient() for 0 coefficients, // the same reasoning applies here. if (it == coefficients_.end() || it->second == 0.0) return; @@ -541,9 +540,6 @@ MPSolverResponseStatus MPSolver::LoadModelFromProto( // duplicate names in the proto (they're not considered as 'ids'), // unlike the MPSolver C++ API which crashes if there are duplicate names. // Clearing the names makes the MPSolver generate unique names. - // - // TODO(user): This limits the number of variables and constraints to 10^9: - // we should fix that. return LoadModelFromProtoInternal(input_model, /*clear_names=*/true, error_message); } @@ -659,6 +655,10 @@ void MPSolver::FillSolutionResponseProto(MPSolutionResponse* response) const { for (int j = 0; j < constraints_.size(); ++j) { response->add_dual_value(constraints_[j]->dual_value()); } + // Reduced cost have no meaning in MIP. + for (int i = 0; i < variables_.size(); ++i) { + response->add_reduced_cost(variables_[i]->reduced_cost()); + } } } } @@ -738,7 +738,7 @@ void MPSolver::ExportModelToProto(MPModelProto* output_model) const { // Vector linear_term will contain pairs (variable index, coeff), that will // be sorted by variable index. std::vector > linear_term; - for (CoeffEntry entry : constraint->coefficients_) { + for (const auto& entry : constraint->coefficients_) { const MPVariable* const var = entry.first; const int var_index = gtl::FindWithDefault(var_to_index, var, -1); DCHECK_NE(-1, var_index); @@ -1088,7 +1088,7 @@ std::vector MPSolver::ComputeConstraintActivities() const { for (int i = 0; i < constraints_.size(); ++i) { const MPConstraint& constraint = *constraints_[i]; AccurateSum sum; - for (CoeffEntry entry : constraint.coefficients_) { + for (const auto& entry : constraint.coefficients_) { sum.Add(entry.first->solution_value() * entry.second); } activities[i] = sum.Value(); @@ -1156,7 +1156,7 @@ bool MPSolver::VerifySolution(double tolerance, bool log_errors) const { const double activity = activities[i]; // Re-compute the activity with a inaccurate summing algorithm. double inaccurate_activity = 0.0; - for (CoeffEntry entry : constraint.coefficients_) { + for (const auto& entry : constraint.coefficients_) { inaccurate_activity += entry.first->solution_value() * entry.second; } // Catch NaNs. @@ -1203,7 +1203,7 @@ bool MPSolver::VerifySolution(double tolerance, bool log_errors) const { AccurateSum objective_sum; objective_sum.Add(objective.offset()); double inaccurate_objective_value = objective.offset(); - for (CoeffEntry entry : objective.coefficients_) { + for (const auto& entry : objective.coefficients_) { const double term = entry.first->solution_value() * entry.second; objective_sum.Add(term); inaccurate_objective_value += term; diff --git a/ortools/linear_solver/linear_solver.h b/ortools/linear_solver/linear_solver.h index 71e6cd92ff..06ccc95761 100644 --- a/ortools/linear_solver/linear_solver.h +++ b/ortools/linear_solver/linear_solver.h @@ -325,9 +325,6 @@ class MPSolver { // homonymous enum values of MPSolutionResponse::Status // (see ./linear_solver.proto) is guaranteed by ./enum_consistency_test.cc, // you may rely on it. - // TODO(user): Figure out once and for all what the status of - // underlying solvers exactly mean, especially for feasible and - // infeasible. enum ResultStatus { OPTIMAL, // optimal. FEASIBLE, // feasible, or stopped by limit. @@ -572,6 +569,20 @@ class MPSolver { // is ill conditioned. double ComputeExactConditionNumber() const; + // Some solvers (MIP only, not LP) can produce multiple solutions to the + // problem. Returns true when another solution is available, and updates the + // MPVariable* objects to make the new solution queryable. Call only after + // calling solve. + // + // The optimality properties of the additional solutions found, and whether + // or not the solver computes them ahead of time or when NextSolution() is + // called is solver specific. + // + // As of July 17, 2018, only Gurobi supports NextSolution(), see + // linear_solver_underlying_gurobi_test for an example of how to configure + // Gurobi for this purpose. The other solvers return false unconditionally. + MUST_USE_RESULT bool NextSolution(); + friend class GLPKInterface; friend class CLPInterface; friend class CBCInterface; @@ -655,21 +666,6 @@ inline std::ostream& operator<<(std::ostream& os, static_cast(status)); } -// The data structure used to store the coefficients of the contraints and of -// the objective. Also define a type to facilitate iteration over them with: -// for (CoeffEntry entry : coefficients_) { ... } -class CoeffMap : public std::unordered_map { - public: - explicit CoeffMap(int num_buckets) -#if !defined(_MSC_VER) // Visual C++ doesn't support this constructor - : std::unordered_map(num_buckets) -#endif // _MSC_VER - { - } -}; - -typedef std::pair CoeffEntry; - // A class to express a linear objective. class MPObjective { public: @@ -760,7 +756,7 @@ class MPObjective { MPSolverInterface* const interface_; // Mapping var -> coefficient. - CoeffMap coefficients_; + std::unordered_map coefficients_; // Constant term. double offset_; @@ -948,7 +944,7 @@ class MPConstraint { bool ContainsNewVariables(); // Mapping var -> coefficient. - CoeffMap coefficients_; + std::unordered_map coefficients_; const int index_; // See index(). @@ -1303,6 +1299,9 @@ class MPSolverInterface { virtual bool InterruptSolve() { return false; } + // See MPSolver::NextSolution() for contract. + virtual bool NextSolution() { return false; } + friend class MPSolver; // To access the maximize_ bool and the MPSolver. diff --git a/ortools/linear_solver/linear_solver.proto b/ortools/linear_solver/linear_solver.proto index a6d1eedfff..a566962064 100644 --- a/ortools/linear_solver/linear_solver.proto +++ b/ortools/linear_solver/linear_solver.proto @@ -376,4 +376,12 @@ message MPSolutionResponse { // it is actually a linear program). // These are set iff 'status' is OPTIMAL or FEASIBLE. repeated double dual_value = 4 [packed = true]; + + // [Advanced usage.] + // Values of the reduced cost of the variables in the same order as the + // MPModelProto::variable. This is a dense representation. + // These are not set if the problem was solved with a MIP solver (even if it + // is actually a linear program). + // These are set iff 'status' is OPTIMAL or FEASIBLE. + repeated double reduced_cost = 6 [packed = true]; } diff --git a/ortools/linear_solver/scip_interface.cc b/ortools/linear_solver/scip_interface.cc index f21a1d45ff..e76a4947f8 100644 --- a/ortools/linear_solver/scip_interface.cc +++ b/ortools/linear_solver/scip_interface.cc @@ -264,7 +264,7 @@ void SCIPInterface::ClearConstraint(MPConstraint* constraint) { const int constraint_index = constraint->index(); // Constraint may not have been extracted yet. if (!constraint_is_extracted(constraint_index)) return; - for (CoeffEntry entry : constraint->coefficients_) { + for (const auto& entry : constraint->coefficients_) { const int var_index = entry.first->index(); const double old_coef_value = entry.second; DCHECK(variable_is_extracted(var_index)); @@ -292,7 +292,7 @@ void SCIPInterface::ClearObjective() { InvalidateSolutionSynchronization(); ORTOOLS_SCIP_CALL(SCIPfreeTransform(scip_)); // Clear linear terms - for (CoeffEntry entry : solver_->objective_->coefficients_) { + for (const auto& entry : solver_->objective_->coefficients_) { const int var_index = entry.first->index(); // Variable may have not been extracted yet. if (!variable_is_extracted(var_index)) { @@ -334,7 +334,7 @@ void SCIPInterface::ExtractNewVariables() { // Add new variables to existing constraints. for (int i = 0; i < last_constraint_index_; i++) { MPConstraint* const ct = solver_->constraints_[i]; - for (CoeffEntry entry : ct->coefficients_) { + for (const auto& entry : ct->coefficients_) { const int var_index = entry.first->index(); DCHECK(variable_is_extracted(var_index)); if (var_index >= last_variable_index_) { @@ -371,7 +371,7 @@ void SCIPInterface::ExtractNewConstraints() { DCHECK(constraint_is_extracted(i)); const int size = ct->coefficients_.size(); int j = 0; - for (CoeffEntry entry : ct->coefficients_) { + for (const auto& entry : ct->coefficients_) { const int var_index = entry.first->index(); DCHECK(variable_is_extracted(var_index)); vars[j] = scip_variables_[var_index]; @@ -406,7 +406,7 @@ void SCIPInterface::ExtractObjective() { ORTOOLS_SCIP_CALL(SCIPfreeTransform(scip_)); // Linear objective: set objective coefficients for all variables (some might // have been modified). - for (CoeffEntry entry : solver_->objective_->coefficients_) { + for (const auto& entry : solver_->objective_->coefficients_) { const int var_index = entry.first->index(); const double obj_coef = entry.second; ORTOOLS_SCIP_CALL(