• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/
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 #define EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD 10
32 
33 #include "ceres/partitioned_matrix_view.h"
34 
35 #include <algorithm>
36 #include <cstring>
37 #include <vector>
38 #include "ceres/block_sparse_matrix.h"
39 #include "ceres/block_structure.h"
40 #include "ceres/internal/eigen.h"
41 #include "ceres/small_blas.h"
42 #include "glog/logging.h"
43 
44 namespace ceres {
45 namespace internal {
46 
PartitionedMatrixView(const BlockSparseMatrix & matrix,int num_col_blocks_a)47 PartitionedMatrixView::PartitionedMatrixView(
48     const BlockSparseMatrix& matrix,
49     int num_col_blocks_a)
50     : matrix_(matrix),
51       num_col_blocks_e_(num_col_blocks_a) {
52   const CompressedRowBlockStructure* bs = matrix_.block_structure();
53   CHECK_NOTNULL(bs);
54 
55   num_col_blocks_f_ = bs->cols.size() - num_col_blocks_a;
56 
57   // Compute the number of row blocks in E. The number of row blocks
58   // in E maybe less than the number of row blocks in the input matrix
59   // as some of the row blocks at the bottom may not have any
60   // e_blocks. For a definition of what an e_block is, please see
61   // explicit_schur_complement_solver.h
62   num_row_blocks_e_ = 0;
63   for (int r = 0; r < bs->rows.size(); ++r) {
64     const vector<Cell>& cells = bs->rows[r].cells;
65     if (cells[0].block_id < num_col_blocks_a) {
66       ++num_row_blocks_e_;
67     }
68   }
69 
70   // Compute the number of columns in E and F.
71   num_cols_e_ = 0;
72   num_cols_f_ = 0;
73 
74   for (int c = 0; c < bs->cols.size(); ++c) {
75     const Block& block = bs->cols[c];
76     if (c < num_col_blocks_a) {
77       num_cols_e_ += block.size;
78     } else {
79       num_cols_f_ += block.size;
80     }
81   }
82 
83   CHECK_EQ(num_cols_e_ + num_cols_f_, matrix_.num_cols());
84 }
85 
~PartitionedMatrixView()86 PartitionedMatrixView::~PartitionedMatrixView() {
87 }
88 
89 // The next four methods don't seem to be particularly cache
90 // friendly. This is an artifact of how the BlockStructure of the
91 // input matrix is constructed. These methods will benefit from
92 // multithreading as well as improved data layout.
93 
RightMultiplyE(const double * x,double * y) const94 void PartitionedMatrixView::RightMultiplyE(const double* x, double* y) const {
95   const CompressedRowBlockStructure* bs = matrix_.block_structure();
96 
97   // Iterate over the first num_row_blocks_e_ row blocks, and multiply
98   // by the first cell in each row block.
99   const double* values = matrix_.values();
100   for (int r = 0; r < num_row_blocks_e_; ++r) {
101     const Cell& cell = bs->rows[r].cells[0];
102     const int row_block_pos = bs->rows[r].block.position;
103     const int row_block_size = bs->rows[r].block.size;
104     const int col_block_id = cell.block_id;
105     const int col_block_pos = bs->cols[col_block_id].position;
106     const int col_block_size = bs->cols[col_block_id].size;
107     MatrixVectorMultiply<Eigen::Dynamic, Eigen::Dynamic, 1>(
108         values + cell.position, row_block_size, col_block_size,
109         x + col_block_pos,
110         y + row_block_pos);
111   }
112 }
113 
RightMultiplyF(const double * x,double * y) const114 void PartitionedMatrixView::RightMultiplyF(const double* x, double* y) const {
115   const CompressedRowBlockStructure* bs = matrix_.block_structure();
116 
117   // Iterate over row blocks, and if the row block is in E, then
118   // multiply by all the cells except the first one which is of type
119   // E. If the row block is not in E (i.e its in the bottom
120   // num_row_blocks - num_row_blocks_e row blocks), then all the cells
121   // are of type F and multiply by them all.
122   const double* values = matrix_.values();
123   for (int r = 0; r < bs->rows.size(); ++r) {
124     const int row_block_pos = bs->rows[r].block.position;
125     const int row_block_size = bs->rows[r].block.size;
126     const vector<Cell>& cells = bs->rows[r].cells;
127     for (int c = (r < num_row_blocks_e_) ? 1 : 0; c < cells.size(); ++c) {
128       const int col_block_id = cells[c].block_id;
129       const int col_block_pos = bs->cols[col_block_id].position;
130       const int col_block_size = bs->cols[col_block_id].size;
131       MatrixVectorMultiply<Eigen::Dynamic, Eigen::Dynamic, 1>(
132           values + cells[c].position, row_block_size, col_block_size,
133           x + col_block_pos - num_cols_e(),
134           y + row_block_pos);
135     }
136   }
137 }
138 
LeftMultiplyE(const double * x,double * y) const139 void PartitionedMatrixView::LeftMultiplyE(const double* x, double* y) const {
140   const CompressedRowBlockStructure* bs = matrix_.block_structure();
141 
142   // Iterate over the first num_row_blocks_e_ row blocks, and multiply
143   // by the first cell in each row block.
144   const double* values = matrix_.values();
145   for (int r = 0; r < num_row_blocks_e_; ++r) {
146     const Cell& cell = bs->rows[r].cells[0];
147     const int row_block_pos = bs->rows[r].block.position;
148     const int row_block_size = bs->rows[r].block.size;
149     const int col_block_id = cell.block_id;
150     const int col_block_pos = bs->cols[col_block_id].position;
151     const int col_block_size = bs->cols[col_block_id].size;
152     MatrixTransposeVectorMultiply<Eigen::Dynamic, Eigen::Dynamic, 1>(
153         values + cell.position, row_block_size, col_block_size,
154         x + row_block_pos,
155         y + col_block_pos);
156   }
157 }
158 
LeftMultiplyF(const double * x,double * y) const159 void PartitionedMatrixView::LeftMultiplyF(const double* x, double* y) const {
160   const CompressedRowBlockStructure* bs = matrix_.block_structure();
161 
162   // Iterate over row blocks, and if the row block is in E, then
163   // multiply by all the cells except the first one which is of type
164   // E. If the row block is not in E (i.e its in the bottom
165   // num_row_blocks - num_row_blocks_e row blocks), then all the cells
166   // are of type F and multiply by them all.
167   const double* values = matrix_.values();
168   for (int r = 0; r < bs->rows.size(); ++r) {
169     const int row_block_pos = bs->rows[r].block.position;
170     const int row_block_size = bs->rows[r].block.size;
171     const vector<Cell>& cells = bs->rows[r].cells;
172     for (int c = (r < num_row_blocks_e_) ? 1 : 0; c < cells.size(); ++c) {
173       const int col_block_id = cells[c].block_id;
174       const int col_block_pos = bs->cols[col_block_id].position;
175       const int col_block_size = bs->cols[col_block_id].size;
176       MatrixTransposeVectorMultiply<Eigen::Dynamic, Eigen::Dynamic, 1>(
177         values + cells[c].position, row_block_size, col_block_size,
178         x + row_block_pos,
179         y + col_block_pos - num_cols_e());
180     }
181   }
182 }
183 
184 // Given a range of columns blocks of a matrix m, compute the block
185 // structure of the block diagonal of the matrix m(:,
186 // start_col_block:end_col_block)'m(:, start_col_block:end_col_block)
187 // and return a BlockSparseMatrix with the this block structure. The
188 // caller owns the result.
CreateBlockDiagonalMatrixLayout(int start_col_block,int end_col_block) const189 BlockSparseMatrix* PartitionedMatrixView::CreateBlockDiagonalMatrixLayout(
190     int start_col_block, int end_col_block) const {
191   const CompressedRowBlockStructure* bs = matrix_.block_structure();
192   CompressedRowBlockStructure* block_diagonal_structure =
193       new CompressedRowBlockStructure;
194 
195   int block_position = 0;
196   int diagonal_cell_position = 0;
197 
198   // Iterate over the column blocks, creating a new diagonal block for
199   // each column block.
200   for (int c = start_col_block; c < end_col_block; ++c) {
201     const Block& block = bs->cols[c];
202     block_diagonal_structure->cols.push_back(Block());
203     Block& diagonal_block = block_diagonal_structure->cols.back();
204     diagonal_block.size = block.size;
205     diagonal_block.position = block_position;
206 
207     block_diagonal_structure->rows.push_back(CompressedRow());
208     CompressedRow& row = block_diagonal_structure->rows.back();
209     row.block = diagonal_block;
210 
211     row.cells.push_back(Cell());
212     Cell& cell = row.cells.back();
213     cell.block_id = c - start_col_block;
214     cell.position = diagonal_cell_position;
215 
216     block_position += block.size;
217     diagonal_cell_position += block.size * block.size;
218   }
219 
220   // Build a BlockSparseMatrix with the just computed block
221   // structure.
222   return new BlockSparseMatrix(block_diagonal_structure);
223 }
224 
CreateBlockDiagonalEtE() const225 BlockSparseMatrix* PartitionedMatrixView::CreateBlockDiagonalEtE() const {
226   BlockSparseMatrix* block_diagonal =
227       CreateBlockDiagonalMatrixLayout(0, num_col_blocks_e_);
228   UpdateBlockDiagonalEtE(block_diagonal);
229   return block_diagonal;
230 }
231 
CreateBlockDiagonalFtF() const232 BlockSparseMatrix* PartitionedMatrixView::CreateBlockDiagonalFtF() const {
233   BlockSparseMatrix* block_diagonal =
234       CreateBlockDiagonalMatrixLayout(
235           num_col_blocks_e_, num_col_blocks_e_ + num_col_blocks_f_);
236   UpdateBlockDiagonalFtF(block_diagonal);
237   return block_diagonal;
238 }
239 
240 // Similar to the code in RightMultiplyE, except instead of the matrix
241 // vector multiply its an outer product.
242 //
243 //    block_diagonal = block_diagonal(E'E)
UpdateBlockDiagonalEtE(BlockSparseMatrix * block_diagonal) const244 void PartitionedMatrixView::UpdateBlockDiagonalEtE(
245     BlockSparseMatrix* block_diagonal) const {
246   const CompressedRowBlockStructure* bs = matrix_.block_structure();
247   const CompressedRowBlockStructure* block_diagonal_structure =
248       block_diagonal->block_structure();
249 
250   block_diagonal->SetZero();
251   const double* values = matrix_.values();
252   for (int r = 0; r < num_row_blocks_e_ ; ++r) {
253     const Cell& cell = bs->rows[r].cells[0];
254     const int row_block_size = bs->rows[r].block.size;
255     const int block_id = cell.block_id;
256     const int col_block_size = bs->cols[block_id].size;
257     const int cell_position =
258         block_diagonal_structure->rows[block_id].cells[0].position;
259 
260     MatrixTransposeMatrixMultiply
261         <Eigen::Dynamic, Eigen::Dynamic, Eigen::Dynamic, Eigen::Dynamic, 1>(
262             values + cell.position, row_block_size, col_block_size,
263             values + cell.position, row_block_size, col_block_size,
264             block_diagonal->mutable_values() + cell_position,
265             0, 0, col_block_size, col_block_size);
266   }
267 }
268 
269 // Similar to the code in RightMultiplyF, except instead of the matrix
270 // vector multiply its an outer product.
271 //
272 //   block_diagonal = block_diagonal(F'F)
273 //
UpdateBlockDiagonalFtF(BlockSparseMatrix * block_diagonal) const274 void PartitionedMatrixView::UpdateBlockDiagonalFtF(
275     BlockSparseMatrix* block_diagonal) const {
276   const CompressedRowBlockStructure* bs = matrix_.block_structure();
277   const CompressedRowBlockStructure* block_diagonal_structure =
278       block_diagonal->block_structure();
279 
280   block_diagonal->SetZero();
281   const double* values = matrix_.values();
282   for (int r = 0; r < bs->rows.size(); ++r) {
283     const int row_block_size = bs->rows[r].block.size;
284     const vector<Cell>& cells = bs->rows[r].cells;
285     for (int c = (r < num_row_blocks_e_) ? 1 : 0; c < cells.size(); ++c) {
286       const int col_block_id = cells[c].block_id;
287       const int col_block_size = bs->cols[col_block_id].size;
288       const int diagonal_block_id = col_block_id - num_col_blocks_e_;
289       const int cell_position =
290           block_diagonal_structure->rows[diagonal_block_id].cells[0].position;
291 
292       MatrixTransposeMatrixMultiply
293           <Eigen::Dynamic, Eigen::Dynamic, Eigen::Dynamic, Eigen::Dynamic, 1>(
294               values + cells[c].position, row_block_size, col_block_size,
295               values + cells[c].position, row_block_size, col_block_size,
296               block_diagonal->mutable_values() + cell_position,
297               0, 0, col_block_size, col_block_size);
298     }
299   }
300 }
301 
302 }  // namespace internal
303 }  // namespace ceres
304