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
#define EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD 10
33
#include "ceres/partitioned_matrix_view.h"
38
#include "ceres/block_sparse_matrix.h"
39
#include "ceres/block_structure.h"
40
#include "ceres/internal/eigen.h"
41
#include "glog/logging.h"
46
PartitionedMatrixView::PartitionedMatrixView(
47
const BlockSparseMatrixBase& matrix,
50
num_col_blocks_e_(num_col_blocks_a) {
51
const CompressedRowBlockStructure* bs = matrix_.block_structure();
54
num_col_blocks_f_ = bs->cols.size() - num_col_blocks_a;
56
// Compute the number of row blocks in E. The number of row blocks
57
// in E maybe less than the number of row blocks in the input matrix
58
// as some of the row blocks at the bottom may not have any
59
// e_blocks. For a definition of what an e_block is, please see
60
// explicit_schur_complement_solver.h
61
num_row_blocks_e_ = 0;
62
for (int r = 0; r < bs->rows.size(); ++r) {
63
const vector<Cell>& cells = bs->rows[r].cells;
64
if (cells[0].block_id < num_col_blocks_a) {
69
// Compute the number of columns in E and F.
73
for (int c = 0; c < bs->cols.size(); ++c) {
74
const Block& block = bs->cols[c];
75
if (c < num_col_blocks_a) {
76
num_cols_e_ += block.size;
78
num_cols_f_ += block.size;
82
CHECK_EQ(num_cols_e_ + num_cols_f_, matrix_.num_cols());
85
PartitionedMatrixView::~PartitionedMatrixView() {
88
// The next four methods don't seem to be particularly cache
89
// friendly. This is an artifact of how the BlockStructure of the
90
// input matrix is constructed. These methods will benefit from
91
// multithreading as well as improved data layout.
93
void PartitionedMatrixView::RightMultiplyE(const double* x, double* y) const {
94
const CompressedRowBlockStructure* bs = matrix_.block_structure();
96
// Iterate over the first num_row_blocks_e_ row blocks, and multiply
97
// by the first cell in each row block.
98
for (int r = 0; r < num_row_blocks_e_; ++r) {
99
const double* row_values = matrix_.RowBlockValues(r);
100
const Cell& cell = bs->rows[r].cells[0];
101
const int row_block_pos = bs->rows[r].block.position;
102
const int row_block_size = bs->rows[r].block.size;
103
const int col_block_id = cell.block_id;
104
const int col_block_pos = bs->cols[col_block_id].position;
105
const int col_block_size = bs->cols[col_block_id].size;
107
ConstVectorRef xref(x + col_block_pos, col_block_size);
108
VectorRef yref(y + row_block_pos, row_block_size);
109
ConstMatrixRef m(row_values + cell.position,
112
yref += m.lazyProduct(xref);
116
void PartitionedMatrixView::RightMultiplyF(const double* x, double* y) const {
117
const CompressedRowBlockStructure* bs = matrix_.block_structure();
119
// Iterate over row blocks, and if the row block is in E, then
120
// multiply by all the cells except the first one which is of type
121
// E. If the row block is not in E (i.e its in the bottom
122
// num_row_blocks - num_row_blocks_e row blocks), then all the cells
123
// are of type F and multiply by them all.
124
for (int r = 0; r < bs->rows.size(); ++r) {
125
const int row_block_pos = bs->rows[r].block.position;
126
const int row_block_size = bs->rows[r].block.size;
127
VectorRef yref(y + row_block_pos, row_block_size);
128
const vector<Cell>& cells = bs->rows[r].cells;
129
for (int c = (r < num_row_blocks_e_) ? 1 : 0; c < cells.size(); ++c) {
130
const double* row_values = matrix_.RowBlockValues(r);
131
const int col_block_id = cells[c].block_id;
132
const int col_block_pos = bs->cols[col_block_id].position;
133
const int col_block_size = bs->cols[col_block_id].size;
135
ConstVectorRef xref(x + col_block_pos - num_cols_e(),
137
ConstMatrixRef m(row_values + cells[c].position,
140
yref += m.lazyProduct(xref);
145
void PartitionedMatrixView::LeftMultiplyE(const double* x, double* y) const {
146
const CompressedRowBlockStructure* bs = matrix_.block_structure();
148
// Iterate over the first num_row_blocks_e_ row blocks, and multiply
149
// by the first cell in each row block.
150
for (int r = 0; r < num_row_blocks_e_; ++r) {
151
const Cell& cell = bs->rows[r].cells[0];
152
const double* row_values = matrix_.RowBlockValues(r);
153
const int row_block_pos = bs->rows[r].block.position;
154
const int row_block_size = bs->rows[r].block.size;
155
const int col_block_id = cell.block_id;
156
const int col_block_pos = bs->cols[col_block_id].position;
157
const int col_block_size = bs->cols[col_block_id].size;
159
ConstVectorRef xref(x + row_block_pos, row_block_size);
160
VectorRef yref(y + col_block_pos, col_block_size);
161
ConstMatrixRef m(row_values + cell.position,
164
yref += m.transpose().lazyProduct(xref);
168
void PartitionedMatrixView::LeftMultiplyF(const double* x, double* y) const {
169
const CompressedRowBlockStructure* bs = matrix_.block_structure();
171
// Iterate over row blocks, and if the row block is in E, then
172
// multiply by all the cells except the first one which is of type
173
// E. If the row block is not in E (i.e its in the bottom
174
// num_row_blocks - num_row_blocks_e row blocks), then all the cells
175
// are of type F and multiply by them all.
176
for (int r = 0; r < bs->rows.size(); ++r) {
177
const int row_block_pos = bs->rows[r].block.position;
178
const int row_block_size = bs->rows[r].block.size;
179
ConstVectorRef xref(x + row_block_pos, row_block_size);
180
const vector<Cell>& cells = bs->rows[r].cells;
181
for (int c = (r < num_row_blocks_e_) ? 1 : 0; c < cells.size(); ++c) {
182
const double* row_values = matrix_.RowBlockValues(r);
183
const int col_block_id = cells[c].block_id;
184
const int col_block_pos = bs->cols[col_block_id].position;
185
const int col_block_size = bs->cols[col_block_id].size;
187
VectorRef yref(y + col_block_pos - num_cols_e(), col_block_size);
188
ConstMatrixRef m(row_values + cells[c].position,
191
yref += m.transpose().lazyProduct(xref);
196
// Given a range of columns blocks of a matrix m, compute the block
197
// structure of the block diagonal of the matrix m(:,
198
// start_col_block:end_col_block)'m(:, start_col_block:end_col_block)
199
// and return a BlockSparseMatrix with the this block structure. The
200
// caller owns the result.
201
BlockSparseMatrix* PartitionedMatrixView::CreateBlockDiagonalMatrixLayout(
202
int start_col_block, int end_col_block) const {
203
const CompressedRowBlockStructure* bs = matrix_.block_structure();
204
CompressedRowBlockStructure* block_diagonal_structure =
205
new CompressedRowBlockStructure;
207
int block_position = 0;
208
int diagonal_cell_position = 0;
210
// Iterate over the column blocks, creating a new diagonal block for
211
// each column block.
212
for (int c = start_col_block; c < end_col_block; ++c) {
213
const Block& block = bs->cols[c];
214
block_diagonal_structure->cols.push_back(Block());
215
Block& diagonal_block = block_diagonal_structure->cols.back();
216
diagonal_block.size = block.size;
217
diagonal_block.position = block_position;
219
block_diagonal_structure->rows.push_back(CompressedRow());
220
CompressedRow& row = block_diagonal_structure->rows.back();
221
row.block = diagonal_block;
223
row.cells.push_back(Cell());
224
Cell& cell = row.cells.back();
225
cell.block_id = c - start_col_block;
226
cell.position = diagonal_cell_position;
228
block_position += block.size;
229
diagonal_cell_position += block.size * block.size;
232
// Build a BlockSparseMatrix with the just computed block
234
return new BlockSparseMatrix(block_diagonal_structure);
237
BlockSparseMatrix* PartitionedMatrixView::CreateBlockDiagonalEtE() const {
238
BlockSparseMatrix* block_diagonal =
239
CreateBlockDiagonalMatrixLayout(0, num_col_blocks_e_);
240
UpdateBlockDiagonalEtE(block_diagonal);
241
return block_diagonal;
244
BlockSparseMatrix* PartitionedMatrixView::CreateBlockDiagonalFtF() const {
245
BlockSparseMatrix* block_diagonal =
246
CreateBlockDiagonalMatrixLayout(
247
num_col_blocks_e_, num_col_blocks_e_ + num_col_blocks_f_);
248
UpdateBlockDiagonalFtF(block_diagonal);
249
return block_diagonal;
252
// Similar to the code in RightMultiplyE, except instead of the matrix
253
// vector multiply its an outer product.
255
// block_diagonal = block_diagonal(E'E)
256
void PartitionedMatrixView::UpdateBlockDiagonalEtE(
257
BlockSparseMatrix* block_diagonal) const {
258
const CompressedRowBlockStructure* bs = matrix_.block_structure();
259
const CompressedRowBlockStructure* block_diagonal_structure =
260
block_diagonal->block_structure();
262
block_diagonal->SetZero();
264
for (int r = 0; r < num_row_blocks_e_ ; ++r) {
265
const double* row_values = matrix_.RowBlockValues(r);
266
const Cell& cell = bs->rows[r].cells[0];
267
const int row_block_size = bs->rows[r].block.size;
268
const int block_id = cell.block_id;
269
const int col_block_size = bs->cols[block_id].size;
270
ConstMatrixRef m(row_values + cell.position,
274
const int cell_position =
275
block_diagonal_structure->rows[block_id].cells[0].position;
277
MatrixRef(block_diagonal->mutable_values() + cell_position,
278
col_block_size, col_block_size).noalias() += m.transpose() * m;
282
// Similar to the code in RightMultiplyF, except instead of the matrix
283
// vector multiply its an outer product.
285
// block_diagonal = block_diagonal(F'F)
287
void PartitionedMatrixView::UpdateBlockDiagonalFtF(
288
BlockSparseMatrix* block_diagonal) const {
289
const CompressedRowBlockStructure* bs = matrix_.block_structure();
290
const CompressedRowBlockStructure* block_diagonal_structure =
291
block_diagonal->block_structure();
293
block_diagonal->SetZero();
294
for (int r = 0; r < bs->rows.size(); ++r) {
295
const int row_block_size = bs->rows[r].block.size;
296
const vector<Cell>& cells = bs->rows[r].cells;
297
const double* row_values = matrix_.RowBlockValues(r);
298
for (int c = (r < num_row_blocks_e_) ? 1 : 0; c < cells.size(); ++c) {
299
const int col_block_id = cells[c].block_id;
300
const int col_block_size = bs->cols[col_block_id].size;
301
ConstMatrixRef m(row_values + cells[c].position,
304
const int diagonal_block_id = col_block_id - num_col_blocks_e_;
305
const int cell_position =
306
block_diagonal_structure->rows[diagonal_block_id].cells[0].position;
308
MatrixRef(block_diagonal->mutable_values() + cell_position,
309
col_block_size, col_block_size).noalias() += m.transpose() * m;
314
} // namespace internal