blob: 723b149030427a174df88ce290fb5bf9aecce06b [file] [log] [blame]
Angus Kong0ae28bd2013-02-13 14:56:04 -08001// 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/
4//
5// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are met:
7//
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.
16//
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.
28//
29// Author: sameeragarwal@google.com (Sameer Agarwal)
30
31#ifndef CERES_INTERNAL_SCHUR_COMPLEMENT_SOLVER_H_
32#define CERES_INTERNAL_SCHUR_COMPLEMENT_SOLVER_H_
33
34#include <set>
35#include <utility>
Sascha Haeberling1d2624a2013-07-23 19:00:21 -070036#include <vector>
Angus Kong0ae28bd2013-02-13 14:56:04 -080037
Carlos Hernandez79397c22014-08-07 17:51:38 -070038#include "ceres/internal/port.h"
39
Angus Kong0ae28bd2013-02-13 14:56:04 -080040#include "ceres/block_random_access_matrix.h"
41#include "ceres/block_sparse_matrix.h"
42#include "ceres/block_structure.h"
43#include "ceres/cxsparse.h"
44#include "ceres/linear_solver.h"
45#include "ceres/schur_eliminator.h"
46#include "ceres/suitesparse.h"
47#include "ceres/internal/scoped_ptr.h"
48#include "ceres/types.h"
49
Carlos Hernandez79397c22014-08-07 17:51:38 -070050#ifdef CERES_USE_EIGEN_SPARSE
51#include "Eigen/SparseCholesky"
52#endif
53
Angus Kong0ae28bd2013-02-13 14:56:04 -080054namespace ceres {
55namespace internal {
56
Sascha Haeberling1d2624a2013-07-23 19:00:21 -070057class BlockSparseMatrix;
Angus Kong0ae28bd2013-02-13 14:56:04 -080058
59// Base class for Schur complement based linear least squares
60// solvers. It assumes that the input linear system Ax = b can be
61// partitioned into
62//
63// E y + F z = b
64//
65// Where x = [y;z] is a partition of the variables. The paritioning
66// of the variables is such that, E'E is a block diagonal
67// matrix. Further, the rows of A are ordered so that for every
68// variable block in y, all the rows containing that variable block
69// occur as a vertically contiguous block. i.e the matrix A looks like
70//
71// E F
72// A = [ y1 0 0 0 | z1 0 0 0 z5]
73// [ y1 0 0 0 | z1 z2 0 0 0]
74// [ 0 y2 0 0 | 0 0 z3 0 0]
75// [ 0 0 y3 0 | z1 z2 z3 z4 z5]
76// [ 0 0 y3 0 | z1 0 0 0 z5]
77// [ 0 0 0 y4 | 0 0 0 0 z5]
78// [ 0 0 0 y4 | 0 z2 0 0 0]
79// [ 0 0 0 y4 | 0 0 0 0 0]
80// [ 0 0 0 0 | z1 0 0 0 0]
81// [ 0 0 0 0 | 0 0 z3 z4 z5]
82//
83// This structure should be reflected in the corresponding
84// CompressedRowBlockStructure object associated with A. The linear
85// system Ax = b should either be well posed or the array D below
86// should be non-null and the diagonal matrix corresponding to it
87// should be non-singular.
88//
89// SchurComplementSolver has two sub-classes.
90//
91// DenseSchurComplementSolver: For problems where the Schur complement
92// matrix is small and dense, or if CHOLMOD/SuiteSparse is not
93// installed. For structure from motion problems, this is solver can
94// be used for problems with upto a few hundred cameras.
95//
96// SparseSchurComplementSolver: For problems where the Schur
97// complement matrix is large and sparse. It requires that
98// CHOLMOD/SuiteSparse be installed, as it uses CHOLMOD to find a
99// sparse Cholesky factorization of the Schur complement. This solver
100// can be used for solving structure from motion problems with tens of
101// thousands of cameras, though depending on the exact sparsity
102// structure, it maybe better to use an iterative solver.
103//
104// The two solvers can be instantiated by calling
105// LinearSolver::CreateLinearSolver with LinearSolver::Options::type
106// set to DENSE_SCHUR and SPARSE_SCHUR
107// respectively. LinearSolver::Options::elimination_groups[0] should be
108// at least 1.
Sascha Haeberling1d2624a2013-07-23 19:00:21 -0700109class SchurComplementSolver : public BlockSparseMatrixSolver {
Angus Kong0ae28bd2013-02-13 14:56:04 -0800110 public:
111 explicit SchurComplementSolver(const LinearSolver::Options& options)
112 : options_(options) {
113 CHECK_GT(options.elimination_groups.size(), 1);
114 CHECK_GT(options.elimination_groups[0], 0);
115 }
116
117 // LinearSolver methods
118 virtual ~SchurComplementSolver() {}
119 virtual LinearSolver::Summary SolveImpl(
Sascha Haeberling1d2624a2013-07-23 19:00:21 -0700120 BlockSparseMatrix* A,
Angus Kong0ae28bd2013-02-13 14:56:04 -0800121 const double* b,
122 const LinearSolver::PerSolveOptions& per_solve_options,
123 double* x);
124
125 protected:
126 const LinearSolver::Options& options() const { return options_; }
127
128 const BlockRandomAccessMatrix* lhs() const { return lhs_.get(); }
129 void set_lhs(BlockRandomAccessMatrix* lhs) { lhs_.reset(lhs); }
130 const double* rhs() const { return rhs_.get(); }
131 void set_rhs(double* rhs) { rhs_.reset(rhs); }
132
133 private:
134 virtual void InitStorage(const CompressedRowBlockStructure* bs) = 0;
Carlos Hernandez79397c22014-08-07 17:51:38 -0700135 virtual LinearSolver::Summary SolveReducedLinearSystem(
136 double* solution) = 0;
Angus Kong0ae28bd2013-02-13 14:56:04 -0800137
138 LinearSolver::Options options_;
139
140 scoped_ptr<SchurEliminatorBase> eliminator_;
141 scoped_ptr<BlockRandomAccessMatrix> lhs_;
142 scoped_array<double> rhs_;
143
144 CERES_DISALLOW_COPY_AND_ASSIGN(SchurComplementSolver);
145};
146
147// Dense Cholesky factorization based solver.
148class DenseSchurComplementSolver : public SchurComplementSolver {
149 public:
150 explicit DenseSchurComplementSolver(const LinearSolver::Options& options)
151 : SchurComplementSolver(options) {}
152 virtual ~DenseSchurComplementSolver() {}
153
154 private:
155 virtual void InitStorage(const CompressedRowBlockStructure* bs);
Carlos Hernandez79397c22014-08-07 17:51:38 -0700156 virtual LinearSolver::Summary SolveReducedLinearSystem(
157 double* solution);
Angus Kong0ae28bd2013-02-13 14:56:04 -0800158
159 CERES_DISALLOW_COPY_AND_ASSIGN(DenseSchurComplementSolver);
160};
161
Angus Kong0ae28bd2013-02-13 14:56:04 -0800162// Sparse Cholesky factorization based solver.
163class SparseSchurComplementSolver : public SchurComplementSolver {
164 public:
165 explicit SparseSchurComplementSolver(const LinearSolver::Options& options);
166 virtual ~SparseSchurComplementSolver();
167
168 private:
169 virtual void InitStorage(const CompressedRowBlockStructure* bs);
Carlos Hernandez79397c22014-08-07 17:51:38 -0700170 virtual LinearSolver::Summary SolveReducedLinearSystem(
171 double* solution);
172 LinearSolver::Summary SolveReducedLinearSystemUsingSuiteSparse(
173 double* solution);
174 LinearSolver::Summary SolveReducedLinearSystemUsingCXSparse(
175 double* solution);
176 LinearSolver::Summary SolveReducedLinearSystemUsingEigen(
177 double* solution);
Angus Kong0ae28bd2013-02-13 14:56:04 -0800178
179 // Size of the blocks in the Schur complement.
180 vector<int> blocks_;
181
Angus Kong0ae28bd2013-02-13 14:56:04 -0800182 SuiteSparse ss_;
183 // Symbolic factorization of the reduced linear system. Precomputed
184 // once and reused in subsequent calls.
185 cholmod_factor* factor_;
Angus Kong0ae28bd2013-02-13 14:56:04 -0800186
Angus Kong0ae28bd2013-02-13 14:56:04 -0800187 CXSparse cxsparse_;
188 // Cached factorization
189 cs_dis* cxsparse_factor_;
Carlos Hernandez79397c22014-08-07 17:51:38 -0700190
191#ifdef CERES_USE_EIGEN_SPARSE
192 typedef Eigen::SimplicialLDLT<Eigen::SparseMatrix<double> > SimplicialLDLT;
193 scoped_ptr<SimplicialLDLT> simplicial_ldlt_;
194#endif
195
Angus Kong0ae28bd2013-02-13 14:56:04 -0800196 CERES_DISALLOW_COPY_AND_ASSIGN(SparseSchurComplementSolver);
197};
198
Angus Kong0ae28bd2013-02-13 14:56:04 -0800199} // namespace internal
200} // namespace ceres
201
202#endif // CERES_INTERNAL_SCHUR_COMPLEMENT_SOLVER_H_