Home | History | Annotate | Download | only in ceres
      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 (at) 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 
     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 
     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 
     94 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 
    114 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 
    139 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 
    159 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.
    189 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 
    225 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 
    232 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)
    244 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 //
    274 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