1
// Ceres Solver - A fast non-linear least squares minimizer
2
// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
3
// http://code.google.com/p/ceres-solver/
5
// Redistribution and use in source and binary forms, with or without
6
// modification, are permitted provided that the following conditions are met:
8
// * Redistributions of source code must retain the above copyright notice,
9
// this list of conditions and the following disclaimer.
10
// * Redistributions in binary form must reproduce the above copyright notice,
11
// this list of conditions and the following disclaimer in the documentation
12
// and/or other materials provided with the distribution.
13
// * Neither the name of Google Inc. nor the names of its contributors may be
14
// used to endorse or promote products derived from this software without
15
// specific prior written permission.
17
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
// POSSIBILITY OF SUCH DAMAGE.
29
// Author: sameeragarwal@google.com (Sameer Agarwal)
31
// A preconditioned conjugate gradients solver
32
// (ConjugateGradientsSolver) for positive semidefinite linear
35
// We have also augmented the termination criterion used by this
36
// solver to support not just residual based termination but also
37
// termination based on decrease in the value of the quadratic model
40
#include "ceres/conjugate_gradients_solver.h"
44
#include "ceres/fpclassify.h"
45
#include "ceres/internal/eigen.h"
46
#include "ceres/linear_operator.h"
47
#include "ceres/types.h"
48
#include "glog/logging.h"
54
bool IsZeroOrInfinity(double x) {
55
return ((x == 0.0) || (IsInfinite(x)));
58
// Constant used in the MATLAB implementation ~ 2 * eps.
59
const double kEpsilon = 2.2204e-16;
63
ConjugateGradientsSolver::ConjugateGradientsSolver(
64
const LinearSolver::Options& options)
68
LinearSolver::Summary ConjugateGradientsSolver::Solve(
71
const LinearSolver::PerSolveOptions& per_solve_options,
76
CHECK_EQ(A->num_rows(), A->num_cols());
78
LinearSolver::Summary summary;
79
summary.termination_type = MAX_ITERATIONS;
80
summary.num_iterations = 0;
82
int num_cols = A->num_cols();
83
VectorRef xref(x, num_cols);
84
ConstVectorRef bref(b, num_cols);
86
double norm_b = bref.norm();
89
summary.termination_type = TOLERANCE;
98
double tol_r = per_solve_options.r_tolerance * norm_b;
101
A->RightMultiply(x, tmp.data());
103
double norm_r = r.norm();
105
if (norm_r <= tol_r) {
106
summary.termination_type = TOLERANCE;
112
// Initial value of the quadratic model Q = x'Ax - 2 * b'x.
113
double Q0 = -1.0 * xref.dot(bref + r);
115
for (summary.num_iterations = 1;
116
summary.num_iterations < options_.max_num_iterations;
117
++summary.num_iterations) {
118
VLOG(3) << "cg iteration " << summary.num_iterations;
120
// Apply preconditioner
121
if (per_solve_options.preconditioner != NULL) {
123
per_solve_options.preconditioner->RightMultiply(r.data(), z.data());
128
double last_rho = rho;
131
if (IsZeroOrInfinity(rho)) {
132
LOG(ERROR) << "Numerical failure. rho = " << rho;
133
summary.termination_type = FAILURE;
137
if (summary.num_iterations == 1) {
140
double beta = rho / last_rho;
141
if (IsZeroOrInfinity(beta)) {
142
LOG(ERROR) << "Numerical failure. beta = " << beta;
143
summary.termination_type = FAILURE;
151
A->RightMultiply(p.data(), q.data());
152
double pq = p.dot(q);
154
if ((pq <= 0) || IsInfinite(pq)) {
155
LOG(ERROR) << "Numerical failure. pq = " << pq;
156
summary.termination_type = FAILURE;
160
double alpha = rho / pq;
161
if (IsInfinite(alpha)) {
162
LOG(ERROR) << "Numerical failure. alpha " << alpha;
163
summary.termination_type = FAILURE;
167
xref = xref + alpha * p;
169
// Ideally we would just use the update r = r - alpha*q to keep
170
// track of the residual vector. However this estimate tends to
171
// drift over time due to round off errors. Thus every
172
// residual_reset_period iterations, we calculate the residual as
173
// r = b - Ax. We do not do this every iteration because this
174
// requires an additional matrix vector multiply which would
175
// double the complexity of the CG algorithm.
176
if (summary.num_iterations % options_.residual_reset_period == 0) {
178
A->RightMultiply(x, tmp.data());
184
// Quadratic model based termination.
185
// Q1 = x'Ax - 2 * b' x.
186
double Q1 = -1.0 * xref.dot(bref + r);
188
// For PSD matrices A, let
190
// Q(x) = x'Ax - 2b'x
192
// be the cost of the quadratic function defined by A and b. Then,
193
// the solver terminates at iteration i if
195
// i * (Q(x_i) - Q(x_i-1)) / Q(x_i) < q_tolerance.
197
// This termination criterion is more useful when using CG to
198
// solve the Newton step. This particular convergence test comes
199
// from Stephen Nash's work on truncated Newton
200
// methods. References:
202
// 1. Stephen G. Nash & Ariela Sofer, Assessing A Search
203
// Direction Within A Truncated Newton Method, Operation
204
// Research Letters 9(1990) 219-221.
206
// 2. Stephen G. Nash, A Survey of Truncated Newton Methods,
207
// Journal of Computational and Applied Mathematics,
208
// 124(1-2), 45-59, 2000.
210
double zeta = summary.num_iterations * (Q1 - Q0) / Q1;
211
VLOG(3) << "Q termination: zeta " << zeta
212
<< " " << per_solve_options.q_tolerance;
213
if (zeta < per_solve_options.q_tolerance) {
214
summary.termination_type = TOLERANCE;
219
// Residual based termination.
221
VLOG(3) << "R termination: norm_r " << norm_r
223
if (norm_r <= tol_r) {
224
summary.termination_type = TOLERANCE;
232
} // namespace internal