2025-01-10 11:35:44 +01:00
|
|
|
// Copyright 2010-2025 Google LLC
|
2022-02-09 10:48:30 +01:00
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
|
//
|
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
//
|
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
|
// limitations under the License.
|
|
|
|
|
|
|
|
|
|
#ifndef PDLP_TERMINATION_H_
|
|
|
|
|
#define PDLP_TERMINATION_H_
|
|
|
|
|
|
2022-09-19 18:30:50 +02:00
|
|
|
#include <atomic>
|
2022-03-07 11:31:58 +01:00
|
|
|
#include <optional>
|
|
|
|
|
|
2022-02-09 10:48:30 +01:00
|
|
|
#include "ortools/pdlp/solve_log.pb.h"
|
|
|
|
|
#include "ortools/pdlp/solvers.pb.h"
|
|
|
|
|
|
|
|
|
|
namespace operations_research::pdlp {
|
|
|
|
|
|
|
|
|
|
struct TerminationReasonAndPointType {
|
|
|
|
|
TerminationReason reason;
|
|
|
|
|
PointType type;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Information about the quadratic program's primal and dual bounds that are
|
|
|
|
|
// needed to evaluate relative convergence criteria.
|
|
|
|
|
struct QuadraticProgramBoundNorms {
|
|
|
|
|
double l2_norm_primal_linear_objective;
|
|
|
|
|
double l2_norm_constraint_bounds;
|
|
|
|
|
double l_inf_norm_primal_linear_objective;
|
|
|
|
|
double l_inf_norm_constraint_bounds;
|
|
|
|
|
};
|
|
|
|
|
|
2023-02-09 16:16:42 -08:00
|
|
|
// Computes the effective optimality criteria for a `TerminationCriteria`.
|
2022-09-19 18:30:50 +02:00
|
|
|
TerminationCriteria::DetailedOptimalityCriteria EffectiveOptimalityCriteria(
|
|
|
|
|
const TerminationCriteria& termination_criteria);
|
|
|
|
|
|
2023-02-09 16:16:42 -08:00
|
|
|
// Like the previous overload but takes a `SimpleOptimalityCriteria`. Useful in
|
|
|
|
|
// unit tests where no `TerminationCriteria` is naturally available.
|
2022-09-19 18:30:50 +02:00
|
|
|
TerminationCriteria::DetailedOptimalityCriteria EffectiveOptimalityCriteria(
|
|
|
|
|
const TerminationCriteria::SimpleOptimalityCriteria& simple_criteria);
|
2022-09-26 10:27:38 +02:00
|
|
|
|
2022-05-18 16:37:15 +02:00
|
|
|
// Checks if any of the simple termination criteria are satisfied by `stats`,
|
|
|
|
|
// and returns a termination reason if so, and nullopt otherwise. The "simple"
|
|
|
|
|
// termination criteria are `time_sec_limit`, `iteration_limit`,
|
|
|
|
|
// `kkt_matrix_pass_limit`, and `interrupt_solve`. The corresponding fields of
|
|
|
|
|
// `stats` (`cumulative_time_sec`, `iteration_number`,
|
|
|
|
|
// `cumulative_kkt_matrix_passes`) are the only ones accessed. If returning a
|
2023-02-09 16:16:42 -08:00
|
|
|
// termination reason, the `PointType` will be set to `POINT_TYPE_NONE`.
|
2022-05-18 16:37:15 +02:00
|
|
|
std::optional<TerminationReasonAndPointType> CheckSimpleTerminationCriteria(
|
|
|
|
|
const TerminationCriteria& criteria, const IterationStats& stats,
|
|
|
|
|
const std::atomic<bool>* interrupt_solve = nullptr);
|
|
|
|
|
|
2023-01-20 09:05:22 +01:00
|
|
|
// Checks if any iterate-based termination criteria (i.e., the criteria not
|
2023-02-09 16:16:42 -08:00
|
|
|
// checked by `CheckSimpleTerimationCriteria()`) are satisfied by the solution
|
|
|
|
|
// state described by `stats` (see definitions of termination criteria in
|
|
|
|
|
// solvers.proto). `bound_norms` provides the instance-dependent data required
|
|
|
|
|
// for the relative convergence criteria. Returns a termination reason and a
|
|
|
|
|
// point type if so (if multiple criteria are satisfied, the optimality and
|
|
|
|
|
// infeasibility conditions are checked first). If `force_numerical_termination`
|
|
|
|
|
// is true, returns `TERMINATION_REASON_NUMERICAL_ERROR` if no other criteria
|
|
|
|
|
// are satisfied. The return value is empty in any other case. If the output is
|
|
|
|
|
// not empty, the `PointType` indicates which entry prompted termination. If no
|
|
|
|
|
// entry prompted termination, e.g. `TERMINATION_REASON_NUMERICAL_ERROR` is
|
|
|
|
|
// returned, then the `PointType` is set to `POINT_TYPE_NONE`. NOTE: This
|
|
|
|
|
// function assumes that the solution used to compute the stats satisfies the
|
|
|
|
|
// primal and dual variable bounds; see
|
2022-02-09 10:48:30 +01:00
|
|
|
// https://developers.google.com/optimization/lp/pdlp_math#dual_variable_bounds.
|
2023-01-20 09:05:22 +01:00
|
|
|
std::optional<TerminationReasonAndPointType> CheckIterateTerminationCriteria(
|
2022-02-09 10:48:30 +01:00
|
|
|
const TerminationCriteria& criteria, const IterationStats& stats,
|
|
|
|
|
const QuadraticProgramBoundNorms& bound_norms,
|
|
|
|
|
bool force_numerical_termination = false);
|
|
|
|
|
|
|
|
|
|
// Extracts the norms needed for the termination criteria from the full problem
|
2023-02-09 16:16:42 -08:00
|
|
|
// `stats`.
|
2022-02-09 10:48:30 +01:00
|
|
|
QuadraticProgramBoundNorms BoundNormsFromProblemStats(
|
|
|
|
|
const QuadraticProgramStats& stats);
|
|
|
|
|
|
2023-02-09 16:16:42 -08:00
|
|
|
// Returns `epsilon_absolute / epsilon_relative`, returning 1.0 if
|
|
|
|
|
// `epsilon_absolute` and `epsilon_relative` are equal (even if they are both
|
|
|
|
|
// 0.0 or infinity, which would normally yield NAN).
|
2023-01-20 09:05:22 +01:00
|
|
|
double EpsilonRatio(double epsilon_absolute, double epsilon_relative);
|
|
|
|
|
|
2022-02-09 10:48:30 +01:00
|
|
|
// Metrics for tracking progress when relative convergence criteria are used.
|
2023-02-09 16:16:42 -08:00
|
|
|
// These depend on the `ConvergenceInformation`, the problem data, and the
|
2022-02-09 10:48:30 +01:00
|
|
|
// convergence tolerances.
|
|
|
|
|
struct RelativeConvergenceInformation {
|
|
|
|
|
// Relative versions of the residuals, defined as
|
|
|
|
|
// relative_residual = residual / (eps_ratio + norm),
|
|
|
|
|
// where
|
2023-02-09 16:16:42 -08:00
|
|
|
// eps_ratio = `eps_optimal_absolute / eps_optimal_relative`
|
2022-02-09 10:48:30 +01:00
|
|
|
// residual = one of the residuals (l{2,_inf}_{primal,dual}_residual)
|
|
|
|
|
// norm = the relative norm (l{2,_inf} norm of
|
|
|
|
|
// {constraint_bounds,primal_linear_objective} respectively).
|
2023-02-09 16:16:42 -08:00
|
|
|
// If `eps_optimal_relative == eps_optimal_absolute`, eps_ratio will be 1.0
|
|
|
|
|
// (even if `eps_optimal_relative` == 0.0 or inf). Otherwise, if
|
|
|
|
|
// `eps_optimal_relative == 0.0`, these will all be 0.0.
|
2022-02-09 10:48:30 +01:00
|
|
|
//
|
2023-02-09 16:16:42 -08:00
|
|
|
// If `eps_optimal_relative > 0.0`, the absolute and relative termination
|
|
|
|
|
// criteria translate to relative_residual <= `eps_optimal_relative`.
|
2022-02-09 10:48:30 +01:00
|
|
|
double relative_l_inf_primal_residual = 0;
|
|
|
|
|
double relative_l2_primal_residual = 0;
|
|
|
|
|
double relative_l_inf_dual_residual = 0;
|
|
|
|
|
double relative_l2_dual_residual = 0;
|
|
|
|
|
|
|
|
|
|
// Relative optimality gap:
|
|
|
|
|
// (primal_objective - dual_objective) /
|
|
|
|
|
// (eps_ratio + |primal_objective| + |dual_objective|)
|
|
|
|
|
double relative_optimality_gap = 0;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
RelativeConvergenceInformation ComputeRelativeResiduals(
|
2022-09-19 18:30:50 +02:00
|
|
|
const TerminationCriteria::DetailedOptimalityCriteria& optimality_criteria,
|
2022-09-26 10:27:38 +02:00
|
|
|
const ConvergenceInformation& stats,
|
|
|
|
|
const QuadraticProgramBoundNorms& bound_norms);
|
|
|
|
|
|
|
|
|
|
bool ObjectiveGapMet(
|
|
|
|
|
const TerminationCriteria::DetailedOptimalityCriteria& optimality_criteria,
|
2022-02-09 10:48:30 +01:00
|
|
|
const ConvergenceInformation& stats);
|
|
|
|
|
|
2022-09-26 10:27:38 +02:00
|
|
|
// Determines if the optimality criteria are met.
|
|
|
|
|
bool OptimalityCriteriaMet(
|
|
|
|
|
const TerminationCriteria::DetailedOptimalityCriteria& optimality_criteria,
|
2023-02-09 16:16:42 -08:00
|
|
|
const ConvergenceInformation& stats, OptimalityNorm optimality_norm,
|
2022-09-26 10:27:38 +02:00
|
|
|
const QuadraticProgramBoundNorms& bound_norms);
|
|
|
|
|
|
2022-02-09 10:48:30 +01:00
|
|
|
} // namespace operations_research::pdlp
|
|
|
|
|
|
|
|
|
|
#endif // PDLP_TERMINATION_H_
|