1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346
|
// Ceres Solver - A fast non-linear least squares minimizer
// Copyright 2015 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of Google Inc. nor the names of its contributors may be
// used to endorse or promote products derived from this software without
// specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Author: sameeragarwal@google.com (Sameer Agarwal)
//
// Abstract interface for objects solving linear systems of various
// kinds.
#ifndef CERES_INTERNAL_LINEAR_SOLVER_H_
#define CERES_INTERNAL_LINEAR_SOLVER_H_
#include <cstddef>
#include <map>
#include <memory>
#include <string>
#include <vector>
#include "ceres/block_sparse_matrix.h"
#include "ceres/casts.h"
#include "ceres/compressed_row_sparse_matrix.h"
#include "ceres/context_impl.h"
#include "ceres/dense_sparse_matrix.h"
#include "ceres/execution_summary.h"
#include "ceres/internal/disable_warnings.h"
#include "ceres/internal/export.h"
#include "ceres/triplet_sparse_matrix.h"
#include "ceres/types.h"
#include "glog/logging.h"
namespace ceres {
namespace internal {
enum LinearSolverTerminationType {
// Termination criterion was met.
LINEAR_SOLVER_SUCCESS,
// Solver ran for max_num_iterations and terminated before the
// termination tolerance could be satisfied.
LINEAR_SOLVER_NO_CONVERGENCE,
// Solver was terminated due to numerical problems, generally due to
// the linear system being poorly conditioned.
LINEAR_SOLVER_FAILURE,
// Solver failed with a fatal error that cannot be recovered from,
// e.g. CHOLMOD ran out of memory when computing the symbolic or
// numeric factorization or an underlying library was called with
// the wrong arguments.
LINEAR_SOLVER_FATAL_ERROR
};
// This enum controls the fill-reducing ordering a sparse linear
// algebra library should use before computing a sparse factorization
// (usually Cholesky).
enum OrderingType {
NATURAL, // Do not re-order the matrix. This is useful when the
// matrix has been ordered using a fill-reducing ordering
// already.
AMD // Use the Approximate Minimum Degree algorithm to re-order
// the matrix.
};
class LinearOperator;
// Abstract base class for objects that implement algorithms for
// solving linear systems
//
// Ax = b
//
// It is expected that a single instance of a LinearSolver object
// maybe used multiple times for solving multiple linear systems with
// the same sparsity structure. This allows them to cache and reuse
// information across solves. This means that calling Solve on the
// same LinearSolver instance with two different linear systems will
// result in undefined behaviour.
//
// Subclasses of LinearSolver use two structs to configure themselves.
// The Options struct configures the LinearSolver object for its
// lifetime. The PerSolveOptions struct is used to specify options for
// a particular Solve call.
class CERES_NO_EXPORT LinearSolver {
public:
struct Options {
LinearSolverType type = SPARSE_NORMAL_CHOLESKY;
PreconditionerType preconditioner_type = JACOBI;
VisibilityClusteringType visibility_clustering_type = CANONICAL_VIEWS;
DenseLinearAlgebraLibraryType dense_linear_algebra_library_type = EIGEN;
SparseLinearAlgebraLibraryType sparse_linear_algebra_library_type =
SUITE_SPARSE;
// See solver.h for information about these flags.
bool use_postordering = false;
bool dynamic_sparsity = false;
bool use_explicit_schur_complement = false;
// Number of internal iterations that the solver uses. This
// parameter only makes sense for iterative solvers like CG.
int min_num_iterations = 1;
int max_num_iterations = 1;
// If possible, how many threads can the solver use.
int num_threads = 1;
// Hints about the order in which the parameter blocks should be
// eliminated by the linear solver.
//
// For example if elimination_groups is a vector of size k, then
// the linear solver is informed that it should eliminate the
// parameter blocks 0 ... elimination_groups[0] - 1 first, and
// then elimination_groups[0] ... elimination_groups[1] - 1 and so
// on. Within each elimination group, the linear solver is free to
// choose how the parameter blocks are ordered. Different linear
// solvers have differing requirements on elimination_groups.
//
// The most common use is for Schur type solvers, where there
// should be at least two elimination groups and the first
// elimination group must form an independent set in the normal
// equations. The first elimination group corresponds to the
// num_eliminate_blocks in the Schur type solvers.
std::vector<int> elimination_groups;
// Iterative solvers, e.g. Preconditioned Conjugate Gradients
// maintain a cheap estimate of the residual which may become
// inaccurate over time. Thus for non-zero values of this
// parameter, the solver can be told to recalculate the value of
// the residual using a |b - Ax| evaluation.
int residual_reset_period = 10;
// If the block sizes in a BlockSparseMatrix are fixed, then in
// some cases the Schur complement based solvers can detect and
// specialize on them.
//
// It is expected that these parameters are set programmatically
// rather than manually.
//
// Please see schur_complement_solver.h and schur_eliminator.h for
// more details.
int row_block_size = Eigen::Dynamic;
int e_block_size = Eigen::Dynamic;
int f_block_size = Eigen::Dynamic;
bool use_mixed_precision_solves = false;
int max_num_refinement_iterations = 0;
int subset_preconditioner_start_row_block = -1;
ContextImpl* context = nullptr;
};
// Options for the Solve method.
struct PerSolveOptions {
// This option only makes sense for unsymmetric linear solvers
// that can solve rectangular linear systems.
//
// Given a matrix A, an optional diagonal matrix D as a vector,
// and a vector b, the linear solver will solve for
//
// | A | x = | b |
// | D | | 0 |
//
// If D is null, then it is treated as zero, and the solver returns
// the solution to
//
// A x = b
//
// In either case, x is the vector that solves the following
// optimization problem.
//
// arg min_x ||Ax - b||^2 + ||Dx||^2
//
// Here A is a matrix of size m x n, with full column rank. If A
// does not have full column rank, the results returned by the
// solver cannot be relied on. D, if it is not null is an array of
// size n. b is an array of size m and x is an array of size n.
double* D = nullptr;
// This option only makes sense for iterative solvers.
//
// In general the performance of an iterative linear solver
// depends on the condition number of the matrix A. For example
// the convergence rate of the conjugate gradients algorithm
// is proportional to the square root of the condition number.
//
// One particularly useful technique for improving the
// conditioning of a linear system is to precondition it. In its
// simplest form a preconditioner is a matrix M such that instead
// of solving Ax = b, we solve the linear system AM^{-1} y = b
// instead, where M is such that the condition number k(AM^{-1})
// is smaller than the conditioner k(A). Given the solution to
// this system, x = M^{-1} y. The iterative solver takes care of
// the mechanics of solving the preconditioned system and
// returning the corrected solution x. The user only needs to
// supply a linear operator.
//
// A null preconditioner is equivalent to an identity matrix being
// used a preconditioner.
LinearOperator* preconditioner = nullptr;
// The following tolerance related options only makes sense for
// iterative solvers. Direct solvers ignore them.
// Solver terminates when
//
// |Ax - b| <= r_tolerance * |b|.
//
// This is the most commonly used termination criterion for
// iterative solvers.
double r_tolerance = 0.0;
// For PSD matrices A, let
//
// Q(x) = x'Ax - 2b'x
//
// be the cost of the quadratic function defined by A and b. Then,
// the solver terminates at iteration i if
//
// i * (Q(x_i) - Q(x_i-1)) / Q(x_i) < q_tolerance.
//
// This termination criterion is more useful when using CG to
// solve the Newton step. This particular convergence test comes
// from Stephen Nash's work on truncated Newton
// methods. References:
//
// 1. Stephen G. Nash & Ariela Sofer, Assessing A Search
// Direction Within A Truncated Newton Method, Operation
// Research Letters 9(1990) 219-221.
//
// 2. Stephen G. Nash, A Survey of Truncated Newton Methods,
// Journal of Computational and Applied Mathematics,
// 124(1-2), 45-59, 2000.
//
double q_tolerance = 0.0;
};
// Summary of a call to the Solve method. We should move away from
// the true/false method for determining solver success. We should
// let the summary object do the talking.
struct Summary {
double residual_norm = -1.0;
int num_iterations = -1;
LinearSolverTerminationType termination_type = LINEAR_SOLVER_FAILURE;
std::string message;
};
// If the optimization problem is such that there are no remaining
// e-blocks, a Schur type linear solver cannot be used. If the
// linear solver is of Schur type, this function implements a policy
// to select an alternate nearest linear solver to the one selected
// by the user. The input linear_solver_type is returned otherwise.
static LinearSolverType LinearSolverForZeroEBlocks(
LinearSolverType linear_solver_type);
virtual ~LinearSolver();
// Solve Ax = b.
virtual Summary Solve(LinearOperator* A,
const double* b,
const PerSolveOptions& per_solve_options,
double* x) = 0;
// This method returns copies instead of references so that the base
// class implementation does not have to worry about life time
// issues. Further, this calls are not expected to be frequent or
// performance sensitive.
virtual std::map<std::string, CallStatistics> Statistics() const {
return {};
}
// Factory
static std::unique_ptr<LinearSolver> Create(const Options& options);
};
// This templated subclass of LinearSolver serves as a base class for
// other linear solvers that depend on the particular matrix layout of
// the underlying linear operator. For example some linear solvers
// need low level access to the TripletSparseMatrix implementing the
// LinearOperator interface. This class hides those implementation
// details behind a private virtual method, and has the Solve method
// perform the necessary upcasting.
template <typename MatrixType>
class TypedLinearSolver : public LinearSolver {
public:
LinearSolver::Summary Solve(
LinearOperator* A,
const double* b,
const LinearSolver::PerSolveOptions& per_solve_options,
double* x) override {
ScopedExecutionTimer total_time("LinearSolver::Solve", &execution_summary_);
CHECK(A != nullptr);
CHECK(b != nullptr);
CHECK(x != nullptr);
return SolveImpl(down_cast<MatrixType*>(A), b, per_solve_options, x);
}
std::map<std::string, CallStatistics> Statistics() const override {
return execution_summary_.statistics();
}
private:
virtual LinearSolver::Summary SolveImpl(
MatrixType* A,
const double* b,
const LinearSolver::PerSolveOptions& per_solve_options,
double* x) = 0;
ExecutionSummary execution_summary_;
};
// Linear solvers that depend on acccess to the low level structure of
// a SparseMatrix.
// clang-format off
typedef TypedLinearSolver<BlockSparseMatrix> BlockSparseMatrixSolver; // NOLINT
typedef TypedLinearSolver<CompressedRowSparseMatrix> CompressedRowSparseMatrixSolver; // NOLINT
typedef TypedLinearSolver<DenseSparseMatrix> DenseSparseMatrixSolver; // NOLINT
typedef TypedLinearSolver<TripletSparseMatrix> TripletSparseMatrixSolver; // NOLINT
// clang-format on
} // namespace internal
} // namespace ceres
#include "ceres/internal/reenable_warnings.h"
#endif // CERES_INTERNAL_LINEAR_SOLVER_H_
|