Files
ortools-clone/ortools/pdlp/termination.h

135 lines
6.2 KiB
C
Raw Permalink Normal View History

2025-01-10 11:35:44 +01:00
// Copyright 2010-2025 Google LLC
// 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>
#include <optional>
#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
// https://developers.google.com/optimization/lp/pdlp_math#dual_variable_bounds.
2023-01-20 09:05:22 +01:00
std::optional<TerminationReasonAndPointType> CheckIterateTerminationCriteria(
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`.
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);
// 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
// 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`
// 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.
//
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`.
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,
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);
} // namespace operations_research::pdlp
#endif // PDLP_TERMINATION_H_