Google OR-Tools v9.11
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
primal_dual_hybrid_gradient.h
Go to the documentation of this file.
1// Copyright 2010-2024 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#include <optional>
20#include <string>
21
22#include "Eigen/Core"
25#include "ortools/pdlp/solve_log.pb.h"
26#include "ortools/pdlp/solvers.pb.h"
28
30
32 Eigen::VectorXd primal_solution;
33 Eigen::VectorXd dual_solution;
34};
35
36// The following table defines the interpretation of the result vectors
37// depending on the value of `solve_log.termination_reason`: (the
38// TERMINATION_REASON_ prefix is omitted for brevity):
39//
40// * OPTIMAL: the vectors satisfy the termination criteria for optimality.
41// * PRIMAL_INFEASIBLE: dual_solution and reduced_costs provide an approximate
42// certificate of primal infeasibility; see
43// https://developers.google.com/optimization/lp/pdlp_math#infeasibility_identification
44// for more information.
45// * DUAL_INFEASIBLE: `primal_solution` provides an approximate certificate of
46// dual infeasibility; see
47// https://developers.google.com/optimization/lp/pdlp_math#infeasibility_identification
48// for more information.
49// * PRIMAL_OR_DUAL_INFEASIBLE: the problem was shown to be primal and/or dual
50// infeasible but no certificate of infeasibility is available. The
51// `primal_solution` and `dual_solution` have no meaning. This status is only
52// used when presolve is enabled.
53// * TIME_LIMIT, ITERATION_LIMIT, KKT_MATRIX_PASS_LIMIT, NUMERICAL_ERROR,
54// INTERRUPTED_BY_USER: the vectors contain an iterate at the time that the
55// respective event occurred. Their values may or may not be meaningful. In
56// some cases solution quality information is available; see documentation for
57// `solve_log.solution_type`.
58// * INVALID_PROBLEM, INVALID_PARAMETER, OTHER: the solution vectors are
59// meaningless and may not have lengths consistent with the input problem.
61 Eigen::VectorXd primal_solution;
62 // See https://developers.google.com/optimization/lp/pdlp_math for the
63 // interpretation of `dual_solution` and `reduced_costs`.
64 Eigen::VectorXd dual_solution;
65 // NOTE: The definition of reduced_costs changed in OR-tools version 9.8.
66 // See
67 // https://developers.google.com/optimization/lp/pdlp_math#reduced_costs_dual_residuals_and_the_corrected_dual_objective
68 // for details.
69 Eigen::VectorXd reduced_costs;
70 SolveLog solve_log;
71};
72
73// Identifies the iteration type in a callback. The callback is called both for
74// intermediate iterations and upon termination.
75enum class IterationType {
76 // An intermediate iteration in the "main" phase.
77 kNormal,
78 // An intermediate iteration during a primal feasibility polishing phase.
80 // An intermediate iteration during a dual feasibility polishing phase.
82 // Terminating with a solution found by presolve.
84 // Terminating with a solution found by the "main" phase.
86 // Terminating with a solution found by feasibility polishing.
88};
89
92 TerminationCriteria termination_criteria;
93 // Note that if feasibility polishing is enabled, `iteration_stats` will only
94 // describe the iteration within the current phase (main, primal feasibility
95 // polishing, or dual feasibility polishing), and not the total work.
96 IterationStats iteration_stats;
98};
99
100// Solves the given QP using PDLP (Primal-Dual hybrid gradient enhanced for LP).
101//
102// All operations that are repeated each iteration are executed in parallel
103// using `params.num_threads()` threads.
104//
105// The algorithm generally follows the description in
106// https://arxiv.org/pdf/2106.04756.pdf, with further enhancements for QP.
107// Notation here and in the implementation follows Chambolle and Pock, "On the
108// ergodic convergence rates of a first-order primal-dual algorithm"
109// (http://www.optimization-online.org/DB_FILE/2014/09/4532.pdf).
110// That paper doesn't explicitly use the terminology "primal-dual hybrid
111// gradient" but their Theorem 1 is analyzing PDHG. See
112// https://developers.google.com/optimization/lp/pdlp_math#saddle-point_formulation
113// for the saddle-point formulation of the QP we use that is compatible with
114// Chambolle and Pock.
115//
116// We use 0.5 ||.||^2 for both the primal and dual distance functions.
117//
118// We parameterize the primal and dual step sizes (tau and sigma in Chambolle
119// and Pock) as:
120// primal_stepsize = step_size / primal_weight
121// dual_stepsize = step_size * primal_weight
122// where step_size and primal_weight are parameters.
123// `params.linesearch_rule` determines the update rule for step_size.
124// `params.initial_primal_weight` specifies how primal_weight is initialized
125// and `params.primal_weight_update_smoothing` controls how primal_weight is
126// updated.
127//
128// If `interrupt_solve` is not nullptr, then the solver will periodically check
129// if `interrupt_solve->load()` is true, in which case the solve will terminate
130// with `TERMINATION_REASON_INTERRUPTED_BY_USER`.
131//
132// If `message_callback` is not nullptr, solver logging will be passed to
133// `message_callback`. Otherwise solver logging will be written to stdout.
134// In either case, the amount of logging is controlled by `verbosity_level`.
135// In particular, if `verbosity_level == 0`, there will be no logging in either
136// case.
137//
138// If `iteration_stats_callback` is not nullptr, then at each termination step
139// (when iteration stats are logged), `iteration_stats_callback` will also
140// be called with those iteration stats.
141//
142// Callers MUST check `solve_log.termination_reason` before using the vectors in
143// the `SolverResult`. See the comment on `SolverResult` for interpreting the
144// termination reason.
145//
146// All objective values reported by the algorithm are transformed by using
147// `QuadraticProgram::ApplyObjectiveScalingAndOffset`.
148//
149// NOTE: `qp` is intentionally passed by value, because
150// `PrimalDualHybridGradient` modifies its copy.
152 QuadraticProgram qp, const PrimalDualHybridGradientParams& params,
153 const std::atomic<bool>* interrupt_solve = nullptr,
154 std::function<void(const std::string&)> message_callback = nullptr,
155 std::function<void(const IterationCallbackInfo&)> iteration_stats_callback =
156 nullptr);
157
158// Like above but optionally starts with the given `initial_solution`. If no
159// `initial_solution` is given the zero vector is used. In either case
160// `initial_solution` is projected onto the primal and dual variable bounds
161// before use. Convergence should be faster if `initial_solution` is close to an
162// optimal solution. NOTE: `initial_solution` is intentionally passed by value.
164 QuadraticProgram qp, const PrimalDualHybridGradientParams& params,
165 std::optional<PrimalAndDualSolution> initial_solution,
166 const std::atomic<bool>* interrupt_solve = nullptr,
167 std::function<void(const std::string&)> message_callback = nullptr,
168 std::function<void(const IterationCallbackInfo&)> iteration_stats_callback =
169 nullptr);
170
171namespace internal {
172
173// Computes variable and constraint statuses. This determines if primal
174// variables are at their bounds based on exact comparisons and therefore may
175// not work with unscaled solutions. The primal and dual solution in the
176// returned `ProblemSolution` are NOT set.
179
180} // namespace internal
181
182} // namespace operations_research::pdlp
183
184#endif // PDLP_PRIMAL_DUAL_HYBRID_GRADIENT_H_
double solution
glop::ProblemSolution ComputeStatuses(const QuadraticProgram &qp, const PrimalAndDualSolution &solution)
Validation utilities for solvers.proto.
SolverResult PrimalDualHybridGradient(QuadraticProgram qp, const PrimalDualHybridGradientParams &params, const std::atomic< bool > *interrupt_solve, std::function< void(const std::string &)> message_callback, IterationStatsCallback iteration_stats_callback)
@ kNormal
An intermediate iteration in the "main" phase.
@ kPrimalFeasibility
An intermediate iteration during a primal feasibility polishing phase.
@ kFeasibilityPolishingTermination
Terminating with a solution found by feasibility polishing.
@ kPresolveTermination
Terminating with a solution found by presolve.
@ kDualFeasibility
An intermediate iteration during a dual feasibility polishing phase.
@ kNormalTermination
Terminating with a solution found by the "main" phase.
Contains the solution of a LinearProgram as returned by a preprocessor.
Definition lp_data.h:671