From 22e59eb39bb4ee6da14e76b7ffe24dbfd710fdaf Mon Sep 17 00:00:00 2001 From: Corentin Le Molgat Date: Tue, 18 Jul 2023 13:55:56 +0200 Subject: [PATCH] pdlp: export from google3 --- ortools/pdlp/primal_dual_hybrid_gradient.cc | 27 ++++++++++--------- ortools/pdlp/solvers.proto | 3 ++- ortools/pdlp/solvers_proto_validation.cc | 11 +++++--- ortools/pdlp/solvers_proto_validation_test.cc | 14 ++++++++++ 4 files changed, 38 insertions(+), 17 deletions(-) diff --git a/ortools/pdlp/primal_dual_hybrid_gradient.cc b/ortools/pdlp/primal_dual_hybrid_gradient.cc index 701c081854..5219b0cf9f 100644 --- a/ortools/pdlp/primal_dual_hybrid_gradient.cc +++ b/ortools/pdlp/primal_dual_hybrid_gradient.cc @@ -2293,8 +2293,15 @@ InnerStepOutcome Solver::TakeMalitskyPockStep() { } InnerStepOutcome Solver::TakeAdaptiveStep() { - bool force_numerical_termination = false; - for (bool accepted_step = false; !accepted_step;) { + InnerStepOutcome outcome = InnerStepOutcome::kSuccessful; + int inner_iterations = 0; + for (bool accepted_step = false; !accepted_step; ++inner_iterations) { + if (inner_iterations >= 60) { + LogInnerIterationLimitHit(); + ResetAverageToCurrent(); + outcome = InnerStepOutcome::kForceNumericalTermination; + break; + } const double primal_step_size = step_size_ / primal_weight_; const double dual_step_size = step_size_ * primal_weight_; NextSolutionAndDelta next_primal_solution = @@ -2306,11 +2313,11 @@ InnerStepOutcome Solver::TakeAdaptiveStep() { if (movement == 0.0) { LogNumericalTermination(); ResetAverageToCurrent(); - force_numerical_termination = true; + outcome = InnerStepOutcome::kForceNumericalTermination; break; } else if (movement > kDivergentMovement) { LogNumericalTermination(); - force_numerical_termination = true; + outcome = InnerStepOutcome::kForceNumericalTermination; break; } VectorXd next_dual_product = TransposedMatrixVectorProduct( @@ -2335,7 +2342,7 @@ InnerStepOutcome Solver::TakeAdaptiveStep() { accepted_step = true; } const double total_steps_attempted = - num_rejected_steps_ + iterations_completed_ + 1; + num_rejected_steps_ + inner_iterations + iterations_completed_ + 1; // Our step sizes are a factor 1 - (`total_steps_attempted` + 1)^(- // `step_size_reduction_exponent`) smaller than they could be as a margin to // reduce rejected steps. @@ -2362,14 +2369,10 @@ InnerStepOutcome Solver::TakeAdaptiveStep() { // step, we overall decrease `step_size_`. When `step_size_` is // sufficiently small we stop having rejected steps. step_size_ = std::min(first_term, second_term); - if (!accepted_step) { - ++num_rejected_steps_; - } } - if (force_numerical_termination) { - return InnerStepOutcome::kForceNumericalTermination; - } - return InnerStepOutcome::kSuccessful; + // `inner_iterations` is incremented for the accepted step. + num_rejected_steps_ += inner_iterations - 1; + return outcome; } InnerStepOutcome Solver::TakeConstantSizeStep() { diff --git a/ortools/pdlp/solvers.proto b/ortools/pdlp/solvers.proto index 1f8b702e6c..edceb341d2 100644 --- a/ortools/pdlp/solvers.proto +++ b/ortools/pdlp/solvers.proto @@ -180,11 +180,12 @@ message AdaptiveLinesearchParams { // The step size reduction exponent defines a step size given by // (1 - (total_steps_attempted + 1)^(-step_size_reduction_exponent)) * // step_size_limit where step_size_limit is the maximum allowed step size at - // the current iteration. + // the current iteration. This should be between 0.1 and 1. optional double step_size_reduction_exponent = 1 [default = 0.3]; // The step size growth exponent defines a step size given by (1 + // (total_steps_attempted + 1)^(-step_size_growth_exponent)) * step_size_. + // This should be between 0.1 and 1. optional double step_size_growth_exponent = 2 [default = 0.6]; } diff --git a/ortools/pdlp/solvers_proto_validation.cc b/ortools/pdlp/solvers_proto_validation.cc index 2c8fc1e25f..d7d98560e4 100644 --- a/ortools/pdlp/solvers_proto_validation.cc +++ b/ortools/pdlp/solvers_proto_validation.cc @@ -122,15 +122,18 @@ absl::Status ValidateAdaptiveLinesearchParams( if (std::isnan(params.step_size_reduction_exponent())) { return InvalidArgumentError("step_size_reduction_exponent is NAN"); } - if (params.step_size_reduction_exponent() <= 0) { + if (params.step_size_reduction_exponent() < 0.1 || + params.step_size_reduction_exponent() > 1.0) { return InvalidArgumentError( - "step_size_reduction_exponent must be positive"); + "step_size_reduction_exponent must be between 0.1 and 1.0 inclusive"); } if (std::isnan(params.step_size_growth_exponent())) { return InvalidArgumentError("step_size_growth_exponent is NAN"); } - if (params.step_size_growth_exponent() <= 0) { - return InvalidArgumentError("step_size_growth_exponent must be positive"); + if (params.step_size_growth_exponent() < 0.1 || + params.step_size_growth_exponent() > 1.0) { + return InvalidArgumentError( + "step_size_growth_exponent must be between 0.1 and 1.0 inclusive"); } return OkStatus(); } diff --git a/ortools/pdlp/solvers_proto_validation_test.cc b/ortools/pdlp/solvers_proto_validation_test.cc index b8a05f6adc..08c659490b 100644 --- a/ortools/pdlp/solvers_proto_validation_test.cc +++ b/ortools/pdlp/solvers_proto_validation_test.cc @@ -256,6 +256,13 @@ TEST(ValidateAdaptiveLinesearchParams, BadReductionExponent) { EXPECT_EQ(status_low.code(), absl::StatusCode::kInvalidArgument); EXPECT_THAT(status_low.message(), HasSubstr("step_size_reduction_exponent")); + AdaptiveLinesearchParams params_high; + params_high.set_step_size_reduction_exponent(2.0); + const absl::Status status_high = + ValidateAdaptiveLinesearchParams(params_high); + EXPECT_EQ(status_high.code(), absl::StatusCode::kInvalidArgument); + EXPECT_THAT(status_high.message(), HasSubstr("step_size_reduction_exponent")); + AdaptiveLinesearchParams params_nan; params_nan.set_step_size_reduction_exponent( std::numeric_limits::quiet_NaN()); @@ -271,6 +278,13 @@ TEST(ValidateAdaptiveLinesearchParams, BadGrowthExponent) { EXPECT_EQ(status_low.code(), absl::StatusCode::kInvalidArgument); EXPECT_THAT(status_low.message(), HasSubstr("step_size_growth_exponent")); + AdaptiveLinesearchParams params_high; + params_high.set_step_size_growth_exponent(2.0); + const absl::Status status_high = + ValidateAdaptiveLinesearchParams(params_high); + EXPECT_EQ(status_high.code(), absl::StatusCode::kInvalidArgument); + EXPECT_THAT(status_high.message(), HasSubstr("step_size_growth_exponent")); + AdaptiveLinesearchParams params_nan; params_nan.set_step_size_growth_exponent( std::numeric_limits::quiet_NaN());