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