OR-Tools  9.3
primal_dual_hybrid_gradient.h
Go to the documentation of this file.
1// Copyright 2010-2021 Google LLC
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
14#ifndef PDLP_PRIMAL_DUAL_HYBRID_GRADIENT_H_
15#define PDLP_PRIMAL_DUAL_HYBRID_GRADIENT_H_
16
17#include <atomic>
18#include <functional>
19
20#include "Eigen/Core"
21#include "absl/status/statusor.h"
22#include "absl/types/optional.h"
23#include "ortools/linear_solver/linear_solver.pb.h"
26#include "ortools/pdlp/solve_log.pb.h"
27#include "ortools/pdlp/solvers.pb.h"
29
31
33 Eigen::VectorXd primal_solution;
34 Eigen::VectorXd dual_solution;
35};
36
37// The following table defines the interpretation of the result vectors
38// depending on the value of solve_log.termination_reason: (the
39// TERMINATION_REASON_ prefix is omitted for brevity):
40//
41// * OPTIMAL: the vectors satisfy the termination criteria for optimality.
42// * PRIMAL_INFEASIBLE: dual_solution and reduced_costs provide an approximate
43// certificate of primal infeasibility; see
44// https://developers.google.com/optimization/lp/pdlp_math#infeasibility_identification
45// for more information.
46// * DUAL_INFEASIBLE: primal_solution provides an approximate certificate of
47// dual infeasibility; see
48// https://developers.google.com/optimization/lp/pdlp_math#infeasibility_identification
49// for more information.
50// * PRIMAL_OR_DUAL_INFEASIBLE: the problem was shown to be primal and/or dual
51// infeasible but no certificate of infeasibility is available. The
52// primal_solution and dual_solution have no meaning. This status is only used
53// when presolve is enabled.
54// * TIME_LIMIT, ITERATION_LIMIT, KKT_MATRIX_PASS_LIMIT, NUMERICAL_ERROR,
55// INTERRUPTED_BY_USER: the vectors contain an iterate at the time that the
56// respective event occurred. Their values may or may not be meaningful. In
57// some cases solution quality information is available; see documentation for
58// solve_log.solution_type.
59// * INVALID_PROBLEM, INVALID_PARAMETER, OTHER: the solution vectors are
60// meaningless and may not have lengths consistent with the input problem.
62 Eigen::VectorXd primal_solution;
63 // See https://developers.google.com/optimization/lp/pdlp_math for the
64 // interpretation of the dual and reduced costs.
65 Eigen::VectorXd dual_solution;
66 Eigen::VectorXd reduced_costs;
67 SolveLog solve_log;
68};
69
71 TerminationCriteria termination_criteria;
72 IterationStats iteration_stats;
74};
75
76// Solves the given QP using PDLP (Primal-Dual hybrid gradient enhanced for LP).
77//
78// All operations that are repeated each iteration are executed in parallel
79// using params.num_threads() threads.
80//
81// The algorithm generally follows the description in
82// https://arxiv.org/pdf/2106.04756.pdf, with further enhancements for QP.
83// Notation here and in the implementation follows Chambolle and Pock, "On the
84// ergodic convergence rates of a first-order primal-dual algorithm"
85// (http://www.optimization-online.org/DB_FILE/2014/09/4532.pdf).
86// That paper doesn't explicitly use the terminology "primal-dual hybrid
87// gradient" but their Theorem 1 is analyzing PDHG. See
88// https://developers.google.com/optimization/lp/pdlp_math#saddle-point_formulation
89// for the saddle-point formulation of the QP we use that is compatible with
90// Chambolle and Pock.
91//
92// We use 0.5 ||.||^2 for both the primal and dual distance functions.
93//
94// We parameterize the primal and dual step sizes (tau and sigma in Chambolle
95// and Pock) as:
96// primal_stepsize = step_size / primal_weight
97// dual_stepsize = step_size * primal_weight
98// where step_size and primal_weight are parameters.
99// params.linesearch_rule determines the update rule for step_size.
100// params.initial_primal_weight specifies how primal_weight is initialized
101// and params.primal_weight_update_smoothing controls how primal_weight is
102// updated.
103//
104// If interrupt_solve is not nullptr, then the solver will periodically check if
105// interrupt_solve->load() is true, in which case the solve will terminate with
106// TERMINATION_REASON_INTERRUPTED_BY_USER.
107//
108// If iteration_stats_callback is not nullptr, then at each termination step
109// (when iteration stats are logged), iteration_stats_callback will also
110// be called with those iteration stats.
111//
112// Callers MUST check solve_log.termination_reason before using the vectors in
113// the SolverResult. See the comment on SolverResult for interpreting the
114// termination reason.
115//
116// All objective values reported by the algorithm are transformed by using
117// QuadraticProgram::ApplyObjectiveScalingAndOffset.
118//
119// NOTE: qp is intentionally passed by value, because PrimalDualHybridGradient
120// modifies its copy.
122 QuadraticProgram qp, const PrimalDualHybridGradientParams& params,
123 const std::atomic<bool>* interrupt_solve = nullptr,
124 std::function<void(const IterationCallbackInfo&)> iteration_stats_callback =
125 nullptr);
126
127// Like above but optionally starts with the given initial solution. If no
128// initial solution is given the zero vector is used. In either case the initial
129// solution is projected onto the primal and dual variable bounds before use.
130// Convergence should be faster if the initial solution is close to an optimal
131// solution. NOTE: initial_solution is intentionally passed by value.
133 QuadraticProgram qp, const PrimalDualHybridGradientParams& params,
134 absl::optional<PrimalAndDualSolution> initial_solution,
135 const std::atomic<bool>* interrupt_solve = nullptr,
136 std::function<void(const IterationCallbackInfo&)> iteration_stats_callback =
137 nullptr);
138
139namespace internal {
140
141// Computes variable and constraint statuses. This determines if primal
142// variables are at their bounds based on exact comparisons and therefore may
143// not work with unscaled solutions. The primal and dual solution in the
144// returned ProblemSolution are NOT set.
146 const PrimalAndDualSolution& solution);
147
148} // namespace internal
149
150} // namespace operations_research::pdlp
151
152#endif // PDLP_PRIMAL_DUAL_HYBRID_GRADIENT_H_
glop::ProblemSolution ComputeStatuses(const QuadraticProgram &qp, const PrimalAndDualSolution &solution)
SolverResult PrimalDualHybridGradient(QuadraticProgram qp, const PrimalDualHybridGradientParams &params, const std::atomic< bool > *interrupt_solve, IterationStatsCallback iteration_stats_callback)