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#include "ceres/partitioned_matrix_view.h"
32
33#include <algorithm>
34#include <cstring>
35#include <vector>
36#include "ceres/block_sparse_matrix.h"
37#include "ceres/block_structure.h"
38#include "ceres/internal/eigen.h"
39#include "ceres/small_blas.h"
40#include "glog/logging.h"
41
42namespace ceres {
43namespace internal {
44
45template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
46PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
47PartitionedMatrixView(
48    const BlockSparseMatrix& matrix,
49    int num_col_blocks_e)
50    : matrix_(matrix),
51      num_col_blocks_e_(num_col_blocks_e) {
52  const CompressedRowBlockStructure* bs = matrix_.block_structure();
53  CHECK_NOTNULL(bs);
54
55  num_col_blocks_f_ = bs->cols.size() - num_col_blocks_e_;
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_e_) {
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_e_) {
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
86template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
87PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
88~PartitionedMatrixView() {
89}
90
91// The next four methods don't seem to be particularly cache
92// friendly. This is an artifact of how the BlockStructure of the
93// input matrix is constructed. These methods will benefit from
94// multithreading as well as improved data layout.
95
96template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
97void
98PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
99RightMultiplyE(const double* x, double* y) const {
100  const CompressedRowBlockStructure* bs = matrix_.block_structure();
101
102  // Iterate over the first num_row_blocks_e_ row blocks, and multiply
103  // by the first cell in each row block.
104  const double* values = matrix_.values();
105  for (int r = 0; r < num_row_blocks_e_; ++r) {
106    const Cell& cell = bs->rows[r].cells[0];
107    const int row_block_pos = bs->rows[r].block.position;
108    const int row_block_size = bs->rows[r].block.size;
109    const int col_block_id = cell.block_id;
110    const int col_block_pos = bs->cols[col_block_id].position;
111    const int col_block_size = bs->cols[col_block_id].size;
112    MatrixVectorMultiply<kRowBlockSize, kEBlockSize, 1>(
113        values + cell.position, row_block_size, col_block_size,
114        x + col_block_pos,
115        y + row_block_pos);
116  }
117}
118
119template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
120void
121PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
122RightMultiplyF(const double* x, double* y) const {
123  const CompressedRowBlockStructure* bs = matrix_.block_structure();
124
125  // Iterate over row blocks, and if the row block is in E, then
126  // multiply by all the cells except the first one which is of type
127  // E. If the row block is not in E (i.e its in the bottom
128  // num_row_blocks - num_row_blocks_e row blocks), then all the cells
129  // are of type F and multiply by them all.
130  const double* values = matrix_.values();
131  for (int r = 0; r < num_row_blocks_e_; ++r) {
132    const int row_block_pos = bs->rows[r].block.position;
133    const int row_block_size = bs->rows[r].block.size;
134    const vector<Cell>& cells = bs->rows[r].cells;
135    for (int c = 1; c < cells.size(); ++c) {
136      const int col_block_id = cells[c].block_id;
137      const int col_block_pos = bs->cols[col_block_id].position;
138      const int col_block_size = bs->cols[col_block_id].size;
139      MatrixVectorMultiply<kRowBlockSize, kFBlockSize, 1>(
140          values + cells[c].position, row_block_size, col_block_size,
141          x + col_block_pos - num_cols_e_,
142          y + row_block_pos);
143    }
144  }
145
146  for (int r = num_row_blocks_e_; r < bs->rows.size(); ++r) {
147    const int row_block_pos = bs->rows[r].block.position;
148    const int row_block_size = bs->rows[r].block.size;
149    const vector<Cell>& cells = bs->rows[r].cells;
150    for (int c = 0; c < cells.size(); ++c) {
151      const int col_block_id = cells[c].block_id;
152      const int col_block_pos = bs->cols[col_block_id].position;
153      const int col_block_size = bs->cols[col_block_id].size;
154      MatrixVectorMultiply<Eigen::Dynamic, Eigen::Dynamic, 1>(
155          values + cells[c].position, row_block_size, col_block_size,
156          x + col_block_pos - num_cols_e_,
157          y + row_block_pos);
158    }
159  }
160}
161
162template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
163void
164PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
165LeftMultiplyE(const double* x, double* y) const {
166  const CompressedRowBlockStructure* bs = matrix_.block_structure();
167
168  // Iterate over the first num_row_blocks_e_ row blocks, and multiply
169  // by the first cell in each row block.
170  const double* values = matrix_.values();
171  for (int r = 0; r < num_row_blocks_e_; ++r) {
172    const Cell& cell = bs->rows[r].cells[0];
173    const int row_block_pos = bs->rows[r].block.position;
174    const int row_block_size = bs->rows[r].block.size;
175    const int col_block_id = cell.block_id;
176    const int col_block_pos = bs->cols[col_block_id].position;
177    const int col_block_size = bs->cols[col_block_id].size;
178    MatrixTransposeVectorMultiply<kRowBlockSize, kEBlockSize, 1>(
179        values + cell.position, row_block_size, col_block_size,
180        x + row_block_pos,
181        y + col_block_pos);
182  }
183}
184
185template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
186void
187PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
188LeftMultiplyF(const double* x, double* y) const {
189  const CompressedRowBlockStructure* bs = matrix_.block_structure();
190
191  // Iterate over row blocks, and if the row block is in E, then
192  // multiply by all the cells except the first one which is of type
193  // E. If the row block is not in E (i.e its in the bottom
194  // num_row_blocks - num_row_blocks_e row blocks), then all the cells
195  // are of type F and multiply by them all.
196  const double* values = matrix_.values();
197  for (int r = 0; r < num_row_blocks_e_; ++r) {
198    const int row_block_pos = bs->rows[r].block.position;
199    const int row_block_size = bs->rows[r].block.size;
200    const vector<Cell>& cells = bs->rows[r].cells;
201    for (int c = 1; c < cells.size(); ++c) {
202      const int col_block_id = cells[c].block_id;
203      const int col_block_pos = bs->cols[col_block_id].position;
204      const int col_block_size = bs->cols[col_block_id].size;
205      MatrixTransposeVectorMultiply<kRowBlockSize, kFBlockSize, 1>(
206        values + cells[c].position, row_block_size, col_block_size,
207        x + row_block_pos,
208        y + col_block_pos - num_cols_e_);
209    }
210  }
211
212  for (int r = num_row_blocks_e_; r < bs->rows.size(); ++r) {
213    const int row_block_pos = bs->rows[r].block.position;
214    const int row_block_size = bs->rows[r].block.size;
215    const vector<Cell>& cells = bs->rows[r].cells;
216    for (int c = 0; c < cells.size(); ++c) {
217      const int col_block_id = cells[c].block_id;
218      const int col_block_pos = bs->cols[col_block_id].position;
219      const int col_block_size = bs->cols[col_block_id].size;
220      MatrixTransposeVectorMultiply<Eigen::Dynamic, Eigen::Dynamic, 1>(
221        values + cells[c].position, row_block_size, col_block_size,
222        x + row_block_pos,
223        y + col_block_pos - num_cols_e_);
224    }
225  }
226}
227
228// Given a range of columns blocks of a matrix m, compute the block
229// structure of the block diagonal of the matrix m(:,
230// start_col_block:end_col_block)'m(:, start_col_block:end_col_block)
231// and return a BlockSparseMatrix with the this block structure. The
232// caller owns the result.
233template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
234BlockSparseMatrix*
235PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
236CreateBlockDiagonalMatrixLayout(int start_col_block, int end_col_block) const {
237  const CompressedRowBlockStructure* bs = matrix_.block_structure();
238  CompressedRowBlockStructure* block_diagonal_structure =
239      new CompressedRowBlockStructure;
240
241  int block_position = 0;
242  int diagonal_cell_position = 0;
243
244  // Iterate over the column blocks, creating a new diagonal block for
245  // each column block.
246  for (int c = start_col_block; c < end_col_block; ++c) {
247    const Block& block = bs->cols[c];
248    block_diagonal_structure->cols.push_back(Block());
249    Block& diagonal_block = block_diagonal_structure->cols.back();
250    diagonal_block.size = block.size;
251    diagonal_block.position = block_position;
252
253    block_diagonal_structure->rows.push_back(CompressedRow());
254    CompressedRow& row = block_diagonal_structure->rows.back();
255    row.block = diagonal_block;
256
257    row.cells.push_back(Cell());
258    Cell& cell = row.cells.back();
259    cell.block_id = c - start_col_block;
260    cell.position = diagonal_cell_position;
261
262    block_position += block.size;
263    diagonal_cell_position += block.size * block.size;
264  }
265
266  // Build a BlockSparseMatrix with the just computed block
267  // structure.
268  return new BlockSparseMatrix(block_diagonal_structure);
269}
270
271template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
272BlockSparseMatrix*
273PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
274CreateBlockDiagonalEtE() const {
275  BlockSparseMatrix* block_diagonal =
276      CreateBlockDiagonalMatrixLayout(0, num_col_blocks_e_);
277  UpdateBlockDiagonalEtE(block_diagonal);
278  return block_diagonal;
279}
280
281template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
282BlockSparseMatrix*
283PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
284CreateBlockDiagonalFtF() const {
285  BlockSparseMatrix* block_diagonal =
286      CreateBlockDiagonalMatrixLayout(
287          num_col_blocks_e_, num_col_blocks_e_ + num_col_blocks_f_);
288  UpdateBlockDiagonalFtF(block_diagonal);
289  return block_diagonal;
290}
291
292// Similar to the code in RightMultiplyE, except instead of the matrix
293// vector multiply its an outer product.
294//
295//    block_diagonal = block_diagonal(E'E)
296//
297template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
298void
299PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
300UpdateBlockDiagonalEtE(
301    BlockSparseMatrix* block_diagonal) const {
302  const CompressedRowBlockStructure* bs = matrix_.block_structure();
303  const CompressedRowBlockStructure* block_diagonal_structure =
304      block_diagonal->block_structure();
305
306  block_diagonal->SetZero();
307  const double* values = matrix_.values();
308  for (int r = 0; r < num_row_blocks_e_ ; ++r) {
309    const Cell& cell = bs->rows[r].cells[0];
310    const int row_block_size = bs->rows[r].block.size;
311    const int block_id = cell.block_id;
312    const int col_block_size = bs->cols[block_id].size;
313    const int cell_position =
314        block_diagonal_structure->rows[block_id].cells[0].position;
315
316    MatrixTransposeMatrixMultiply
317        <kRowBlockSize, kEBlockSize, kRowBlockSize, kEBlockSize, 1>(
318            values + cell.position, row_block_size, col_block_size,
319            values + cell.position, row_block_size, col_block_size,
320            block_diagonal->mutable_values() + cell_position,
321            0, 0, col_block_size, col_block_size);
322  }
323}
324
325// Similar to the code in RightMultiplyF, except instead of the matrix
326// vector multiply its an outer product.
327//
328//   block_diagonal = block_diagonal(F'F)
329//
330template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
331void
332PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
333UpdateBlockDiagonalFtF(BlockSparseMatrix* block_diagonal) const {
334  const CompressedRowBlockStructure* bs = matrix_.block_structure();
335  const CompressedRowBlockStructure* block_diagonal_structure =
336      block_diagonal->block_structure();
337
338  block_diagonal->SetZero();
339  const double* values = matrix_.values();
340  for (int r = 0; r < num_row_blocks_e_; ++r) {
341    const int row_block_size = bs->rows[r].block.size;
342    const vector<Cell>& cells = bs->rows[r].cells;
343    for (int c = 1; c < cells.size(); ++c) {
344      const int col_block_id = cells[c].block_id;
345      const int col_block_size = bs->cols[col_block_id].size;
346      const int diagonal_block_id = col_block_id - num_col_blocks_e_;
347      const int cell_position =
348          block_diagonal_structure->rows[diagonal_block_id].cells[0].position;
349
350      MatrixTransposeMatrixMultiply
351          <kRowBlockSize, kFBlockSize, kRowBlockSize, kFBlockSize, 1>(
352              values + cells[c].position, row_block_size, col_block_size,
353              values + cells[c].position, row_block_size, col_block_size,
354              block_diagonal->mutable_values() + cell_position,
355              0, 0, col_block_size, col_block_size);
356    }
357  }
358
359  for (int r = num_row_blocks_e_; r < bs->rows.size(); ++r) {
360    const int row_block_size = bs->rows[r].block.size;
361    const vector<Cell>& cells = bs->rows[r].cells;
362    for (int c = 0; c < cells.size(); ++c) {
363      const int col_block_id = cells[c].block_id;
364      const int col_block_size = bs->cols[col_block_id].size;
365      const int diagonal_block_id = col_block_id - num_col_blocks_e_;
366      const int cell_position =
367          block_diagonal_structure->rows[diagonal_block_id].cells[0].position;
368
369      MatrixTransposeMatrixMultiply
370          <Eigen::Dynamic, Eigen::Dynamic, Eigen::Dynamic, Eigen::Dynamic, 1>(
371              values + cells[c].position, row_block_size, col_block_size,
372              values + cells[c].position, row_block_size, col_block_size,
373              block_diagonal->mutable_values() + cell_position,
374              0, 0, col_block_size, col_block_size);
375    }
376  }
377}
378
379}  // namespace internal
380}  // namespace ceres
381