blob: 31ba1713c96fa893c4c3b42ae93501f05f88b654 [file] [log] [blame]
Austin Schuh70cc9552019-01-21 19:46:48 -08001// Ceres Solver - A fast non-linear least squares minimizer
2// Copyright 2017 Google Inc. All rights reserved.
3// http://ceres-solver.org/
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// Preconditioners for linear systems that arise in Structure from
32// Motion problems. VisibilityBasedPreconditioner implements:
33//
34// CLUSTER_JACOBI
35// CLUSTER_TRIDIAGONAL
36//
37// Detailed descriptions of these preconditions beyond what is
38// documented here can be found in
39//
40// Visibility Based Preconditioning for Bundle Adjustment
41// A. Kushal & S. Agarwal, CVPR 2012.
42//
43// http://www.cs.washington.edu/homes/sagarwal/vbp.pdf
44//
45// The two preconditioners share enough code that its most efficient
46// to implement them as part of the same code base.
47
48#ifndef CERES_INTERNAL_VISIBILITY_BASED_PRECONDITIONER_H_
49#define CERES_INTERNAL_VISIBILITY_BASED_PRECONDITIONER_H_
50
51#include <memory>
52#include <set>
53#include <unordered_map>
54#include <unordered_set>
55#include <utility>
56#include <vector>
57
58#include "ceres/graph.h"
59#include "ceres/linear_solver.h"
60#include "ceres/pair_hash.h"
61#include "ceres/preconditioner.h"
62#include "ceres/sparse_cholesky.h"
63
64namespace ceres {
65namespace internal {
66
67class BlockRandomAccessSparseMatrix;
68class BlockSparseMatrix;
69struct CompressedRowBlockStructure;
70class SchurEliminatorBase;
71
72// This class implements visibility based preconditioners for
73// Structure from Motion/Bundle Adjustment problems. The name
74// VisibilityBasedPreconditioner comes from the fact that the sparsity
75// structure of the preconditioner matrix is determined by analyzing
76// the visibility structure of the scene, i.e. which cameras see which
77// points.
78//
79// The key idea of visibility based preconditioning is to identify
80// cameras that we expect have strong interactions, and then using the
81// entries in the Schur complement matrix corresponding to these
82// camera pairs as an approximation to the full Schur complement.
83//
84// CLUSTER_JACOBI identifies these camera pairs by clustering cameras,
85// and considering all non-zero camera pairs within each cluster. The
86// clustering in the current implementation is done using the
87// Canonical Views algorithm of Simon et al. (see
88// canonical_views_clustering.h). For the purposes of clustering, the
89// similarity or the degree of interaction between a pair of cameras
90// is measured by counting the number of points visible in both the
91// cameras. Thus the name VisibilityBasedPreconditioner. Further, if we
92// were to permute the parameter blocks such that all the cameras in
93// the same cluster occur contiguously, the preconditioner matrix will
94// be a block diagonal matrix with blocks corresponding to the
95// clusters. Thus in analogy with the Jacobi preconditioner we refer
96// to this as the CLUSTER_JACOBI preconditioner.
97//
98// CLUSTER_TRIDIAGONAL adds more mass to the CLUSTER_JACOBI
99// preconditioner by considering the interaction between clusters and
100// identifying strong interactions between cluster pairs. This is done
101// by constructing a weighted graph on the clusters, with the weight
102// on the edges connecting two clusters proportional to the number of
103// 3D points visible to cameras in both the clusters. A degree-2
104// maximum spanning forest is identified in this graph and the camera
105// pairs contained in the edges of this forest are added to the
106// preconditioner. The detailed reasoning for this construction is
107// explained in the paper mentioned above.
108//
109// Degree-2 spanning trees and forests have the property that they
110// correspond to tri-diagonal matrices. Thus there exist a permutation
111// of the camera blocks under which the CLUSTER_TRIDIAGONAL
112// preconditioner matrix is a block tridiagonal matrix, and thus the
113// name for the preconditioner.
114//
115// Thread Safety: This class is NOT thread safe.
116//
117// Example usage:
118//
119// LinearSolver::Options options;
120// options.preconditioner_type = CLUSTER_JACOBI;
121// options.elimination_groups.push_back(num_points);
122// options.elimination_groups.push_back(num_cameras);
123// VisibilityBasedPreconditioner preconditioner(
124// *A.block_structure(), options);
125// preconditioner.Update(A, NULL);
126// preconditioner.RightMultiply(x, y);
127class VisibilityBasedPreconditioner : public BlockSparseMatrixPreconditioner {
128 public:
129 // Initialize the symbolic structure of the preconditioner. bs is
130 // the block structure of the linear system to be solved. It is used
131 // to determine the sparsity structure of the preconditioner matrix.
132 //
133 // It has the same structural requirement as other Schur complement
134 // based solvers. Please see schur_eliminator.h for more details.
135 VisibilityBasedPreconditioner(const CompressedRowBlockStructure& bs,
136 const Preconditioner::Options& options);
137 VisibilityBasedPreconditioner(const VisibilityBasedPreconditioner&) = delete;
138 void operator=(const VisibilityBasedPreconditioner&) = delete;
139
140 virtual ~VisibilityBasedPreconditioner();
141
142 // Preconditioner interface
143 virtual void RightMultiply(const double* x, double* y) const;
144 virtual int num_rows() const;
145
146 friend class VisibilityBasedPreconditionerTest;
147
148 private:
149 virtual bool UpdateImpl(const BlockSparseMatrix& A, const double* D);
150 void ComputeClusterJacobiSparsity(const CompressedRowBlockStructure& bs);
151 void ComputeClusterTridiagonalSparsity(const CompressedRowBlockStructure& bs);
152 void InitStorage(const CompressedRowBlockStructure& bs);
153 void InitEliminator(const CompressedRowBlockStructure& bs);
154 LinearSolverTerminationType Factorize();
155 void ScaleOffDiagonalCells();
156
157 void ClusterCameras(const std::vector<std::set<int>>& visibility);
158 void FlattenMembershipMap(const std::unordered_map<int, int>& membership_map,
159 std::vector<int>* membership_vector) const;
160 void ComputeClusterVisibility(
161 const std::vector<std::set<int>>& visibility,
162 std::vector<std::set<int>>* cluster_visibility) const;
163 WeightedGraph<int>* CreateClusterGraph(
164 const std::vector<std::set<int>>& visibility) const;
165 void ForestToClusterPairs(const WeightedGraph<int>& forest,
166 std::unordered_set<std::pair<int, int>, pair_hash>* cluster_pairs) const;
167 void ComputeBlockPairsInPreconditioner(const CompressedRowBlockStructure& bs);
168 bool IsBlockPairInPreconditioner(int block1, int block2) const;
169 bool IsBlockPairOffDiagonal(int block1, int block2) const;
170
171 Preconditioner::Options options_;
172
173 // Number of parameter blocks in the schur complement.
174 int num_blocks_;
175 int num_clusters_;
176
177 // Sizes of the blocks in the schur complement.
178 std::vector<int> block_size_;
179
180 // Mapping from cameras to clusters.
181 std::vector<int> cluster_membership_;
182
183 // Non-zero camera pairs from the schur complement matrix that are
184 // present in the preconditioner, sorted by row (first element of
185 // each pair), then column (second).
186 std::set<std::pair<int, int>> block_pairs_;
187
188 // Set of cluster pairs (including self pairs (i,i)) in the
189 // preconditioner.
190 std::unordered_set<std::pair<int, int>, pair_hash> cluster_pairs_;
191 std::unique_ptr<SchurEliminatorBase> eliminator_;
192
193 // Preconditioner matrix.
194 std::unique_ptr<BlockRandomAccessSparseMatrix> m_;
195 std::unique_ptr<SparseCholesky> sparse_cholesky_;
196};
197
198} // namespace internal
199} // namespace ceres
200
201#endif // CERES_INTERNAL_VISIBILITY_BASED_PRECONDITIONER_H_