Blame internal/ceres/partitioned_matrix_view_impl.h

Packit ea1746
// Ceres Solver - A fast non-linear least squares minimizer
Packit ea1746
// Copyright 2015 Google Inc. All rights reserved.
Packit ea1746
// http://ceres-solver.org/
Packit ea1746
//
Packit ea1746
// Redistribution and use in source and binary forms, with or without
Packit ea1746
// modification, are permitted provided that the following conditions are met:
Packit ea1746
//
Packit ea1746
// * Redistributions of source code must retain the above copyright notice,
Packit ea1746
//   this list of conditions and the following disclaimer.
Packit ea1746
// * Redistributions in binary form must reproduce the above copyright notice,
Packit ea1746
//   this list of conditions and the following disclaimer in the documentation
Packit ea1746
//   and/or other materials provided with the distribution.
Packit ea1746
// * Neither the name of Google Inc. nor the names of its contributors may be
Packit ea1746
//   used to endorse or promote products derived from this software without
Packit ea1746
//   specific prior written permission.
Packit ea1746
//
Packit ea1746
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
Packit ea1746
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
Packit ea1746
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
Packit ea1746
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
Packit ea1746
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
Packit ea1746
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
Packit ea1746
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
Packit ea1746
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
Packit ea1746
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
Packit ea1746
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
Packit ea1746
// POSSIBILITY OF SUCH DAMAGE.
Packit ea1746
//
Packit ea1746
// Author: sameeragarwal@google.com (Sameer Agarwal)
Packit ea1746
Packit ea1746
#include "ceres/partitioned_matrix_view.h"
Packit ea1746
Packit ea1746
#include <algorithm>
Packit ea1746
#include <cstring>
Packit ea1746
#include <vector>
Packit ea1746
#include "ceres/block_sparse_matrix.h"
Packit ea1746
#include "ceres/block_structure.h"
Packit ea1746
#include "ceres/internal/eigen.h"
Packit ea1746
#include "ceres/small_blas.h"
Packit ea1746
#include "glog/logging.h"
Packit ea1746
Packit ea1746
namespace ceres {
Packit ea1746
namespace internal {
Packit ea1746
Packit ea1746
template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
Packit ea1746
PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
Packit ea1746
PartitionedMatrixView(
Packit ea1746
    const BlockSparseMatrix& matrix,
Packit ea1746
    int num_col_blocks_e)
Packit ea1746
    : matrix_(matrix),
Packit ea1746
      num_col_blocks_e_(num_col_blocks_e) {
Packit ea1746
  const CompressedRowBlockStructure* bs = matrix_.block_structure();
Packit ea1746
  CHECK_NOTNULL(bs);
Packit ea1746
Packit ea1746
  num_col_blocks_f_ = bs->cols.size() - num_col_blocks_e_;
Packit ea1746
Packit ea1746
  // Compute the number of row blocks in E. The number of row blocks
Packit ea1746
  // in E maybe less than the number of row blocks in the input matrix
Packit ea1746
  // as some of the row blocks at the bottom may not have any
Packit ea1746
  // e_blocks. For a definition of what an e_block is, please see
Packit ea1746
  // explicit_schur_complement_solver.h
Packit ea1746
  num_row_blocks_e_ = 0;
Packit ea1746
  for (int r = 0; r < bs->rows.size(); ++r) {
Packit ea1746
    const std::vector<Cell>& cells = bs->rows[r].cells;
Packit ea1746
    if (cells[0].block_id < num_col_blocks_e_) {
Packit ea1746
      ++num_row_blocks_e_;
Packit ea1746
    }
Packit ea1746
  }
Packit ea1746
Packit ea1746
  // Compute the number of columns in E and F.
Packit ea1746
  num_cols_e_ = 0;
Packit ea1746
  num_cols_f_ = 0;
Packit ea1746
Packit ea1746
  for (int c = 0; c < bs->cols.size(); ++c) {
Packit ea1746
    const Block& block = bs->cols[c];
Packit ea1746
    if (c < num_col_blocks_e_) {
Packit ea1746
      num_cols_e_ += block.size;
Packit ea1746
    } else {
Packit ea1746
      num_cols_f_ += block.size;
Packit ea1746
    }
Packit ea1746
  }
Packit ea1746
Packit ea1746
  CHECK_EQ(num_cols_e_ + num_cols_f_, matrix_.num_cols());
Packit ea1746
}
Packit ea1746
Packit ea1746
template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
Packit ea1746
PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
Packit ea1746
~PartitionedMatrixView() {
Packit ea1746
}
Packit ea1746
Packit ea1746
// The next four methods don't seem to be particularly cache
Packit ea1746
// friendly. This is an artifact of how the BlockStructure of the
Packit ea1746
// input matrix is constructed. These methods will benefit from
Packit ea1746
// multithreading as well as improved data layout.
Packit ea1746
Packit ea1746
template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
Packit ea1746
void
Packit ea1746
PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
Packit ea1746
RightMultiplyE(const double* x, double* y) const {
Packit ea1746
  const CompressedRowBlockStructure* bs = matrix_.block_structure();
Packit ea1746
Packit ea1746
  // Iterate over the first num_row_blocks_e_ row blocks, and multiply
Packit ea1746
  // by the first cell in each row block.
Packit ea1746
  const double* values = matrix_.values();
Packit ea1746
  for (int r = 0; r < num_row_blocks_e_; ++r) {
Packit ea1746
    const Cell& cell = bs->rows[r].cells[0];
Packit ea1746
    const int row_block_pos = bs->rows[r].block.position;
Packit ea1746
    const int row_block_size = bs->rows[r].block.size;
Packit ea1746
    const int col_block_id = cell.block_id;
Packit ea1746
    const int col_block_pos = bs->cols[col_block_id].position;
Packit ea1746
    const int col_block_size = bs->cols[col_block_id].size;
Packit ea1746
    MatrixVectorMultiply<kRowBlockSize, kEBlockSize, 1>(
Packit ea1746
        values + cell.position, row_block_size, col_block_size,
Packit ea1746
        x + col_block_pos,
Packit ea1746
        y + row_block_pos);
Packit ea1746
  }
Packit ea1746
}
Packit ea1746
Packit ea1746
template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
Packit ea1746
void
Packit ea1746
PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
Packit ea1746
RightMultiplyF(const double* x, double* y) const {
Packit ea1746
  const CompressedRowBlockStructure* bs = matrix_.block_structure();
Packit ea1746
Packit ea1746
  // Iterate over row blocks, and if the row block is in E, then
Packit ea1746
  // multiply by all the cells except the first one which is of type
Packit ea1746
  // E. If the row block is not in E (i.e its in the bottom
Packit ea1746
  // num_row_blocks - num_row_blocks_e row blocks), then all the cells
Packit ea1746
  // are of type F and multiply by them all.
Packit ea1746
  const double* values = matrix_.values();
Packit ea1746
  for (int r = 0; r < num_row_blocks_e_; ++r) {
Packit ea1746
    const int row_block_pos = bs->rows[r].block.position;
Packit ea1746
    const int row_block_size = bs->rows[r].block.size;
Packit ea1746
    const std::vector<Cell>& cells = bs->rows[r].cells;
Packit ea1746
    for (int c = 1; c < cells.size(); ++c) {
Packit ea1746
      const int col_block_id = cells[c].block_id;
Packit ea1746
      const int col_block_pos = bs->cols[col_block_id].position;
Packit ea1746
      const int col_block_size = bs->cols[col_block_id].size;
Packit ea1746
      MatrixVectorMultiply<kRowBlockSize, kFBlockSize, 1>(
Packit ea1746
          values + cells[c].position, row_block_size, col_block_size,
Packit ea1746
          x + col_block_pos - num_cols_e_,
Packit ea1746
          y + row_block_pos);
Packit ea1746
    }
Packit ea1746
  }
Packit ea1746
Packit ea1746
  for (int r = num_row_blocks_e_; r < bs->rows.size(); ++r) {
Packit ea1746
    const int row_block_pos = bs->rows[r].block.position;
Packit ea1746
    const int row_block_size = bs->rows[r].block.size;
Packit ea1746
    const std::vector<Cell>& cells = bs->rows[r].cells;
Packit ea1746
    for (int c = 0; c < cells.size(); ++c) {
Packit ea1746
      const int col_block_id = cells[c].block_id;
Packit ea1746
      const int col_block_pos = bs->cols[col_block_id].position;
Packit ea1746
      const int col_block_size = bs->cols[col_block_id].size;
Packit ea1746
      MatrixVectorMultiply<Eigen::Dynamic, Eigen::Dynamic, 1>(
Packit ea1746
          values + cells[c].position, row_block_size, col_block_size,
Packit ea1746
          x + col_block_pos - num_cols_e_,
Packit ea1746
          y + row_block_pos);
Packit ea1746
    }
Packit ea1746
  }
Packit ea1746
}
Packit ea1746
Packit ea1746
template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
Packit ea1746
void
Packit ea1746
PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
Packit ea1746
LeftMultiplyE(const double* x, double* y) const {
Packit ea1746
  const CompressedRowBlockStructure* bs = matrix_.block_structure();
Packit ea1746
Packit ea1746
  // Iterate over the first num_row_blocks_e_ row blocks, and multiply
Packit ea1746
  // by the first cell in each row block.
Packit ea1746
  const double* values = matrix_.values();
Packit ea1746
  for (int r = 0; r < num_row_blocks_e_; ++r) {
Packit ea1746
    const Cell& cell = bs->rows[r].cells[0];
Packit ea1746
    const int row_block_pos = bs->rows[r].block.position;
Packit ea1746
    const int row_block_size = bs->rows[r].block.size;
Packit ea1746
    const int col_block_id = cell.block_id;
Packit ea1746
    const int col_block_pos = bs->cols[col_block_id].position;
Packit ea1746
    const int col_block_size = bs->cols[col_block_id].size;
Packit ea1746
    MatrixTransposeVectorMultiply<kRowBlockSize, kEBlockSize, 1>(
Packit ea1746
        values + cell.position, row_block_size, col_block_size,
Packit ea1746
        x + row_block_pos,
Packit ea1746
        y + col_block_pos);
Packit ea1746
  }
Packit ea1746
}
Packit ea1746
Packit ea1746
template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
Packit ea1746
void
Packit ea1746
PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
Packit ea1746
LeftMultiplyF(const double* x, double* y) const {
Packit ea1746
  const CompressedRowBlockStructure* bs = matrix_.block_structure();
Packit ea1746
Packit ea1746
  // Iterate over row blocks, and if the row block is in E, then
Packit ea1746
  // multiply by all the cells except the first one which is of type
Packit ea1746
  // E. If the row block is not in E (i.e its in the bottom
Packit ea1746
  // num_row_blocks - num_row_blocks_e row blocks), then all the cells
Packit ea1746
  // are of type F and multiply by them all.
Packit ea1746
  const double* values = matrix_.values();
Packit ea1746
  for (int r = 0; r < num_row_blocks_e_; ++r) {
Packit ea1746
    const int row_block_pos = bs->rows[r].block.position;
Packit ea1746
    const int row_block_size = bs->rows[r].block.size;
Packit ea1746
    const std::vector<Cell>& cells = bs->rows[r].cells;
Packit ea1746
    for (int c = 1; c < cells.size(); ++c) {
Packit ea1746
      const int col_block_id = cells[c].block_id;
Packit ea1746
      const int col_block_pos = bs->cols[col_block_id].position;
Packit ea1746
      const int col_block_size = bs->cols[col_block_id].size;
Packit ea1746
      MatrixTransposeVectorMultiply<kRowBlockSize, kFBlockSize, 1>(
Packit ea1746
        values + cells[c].position, row_block_size, col_block_size,
Packit ea1746
        x + row_block_pos,
Packit ea1746
        y + col_block_pos - num_cols_e_);
Packit ea1746
    }
Packit ea1746
  }
Packit ea1746
Packit ea1746
  for (int r = num_row_blocks_e_; r < bs->rows.size(); ++r) {
Packit ea1746
    const int row_block_pos = bs->rows[r].block.position;
Packit ea1746
    const int row_block_size = bs->rows[r].block.size;
Packit ea1746
    const std::vector<Cell>& cells = bs->rows[r].cells;
Packit ea1746
    for (int c = 0; c < cells.size(); ++c) {
Packit ea1746
      const int col_block_id = cells[c].block_id;
Packit ea1746
      const int col_block_pos = bs->cols[col_block_id].position;
Packit ea1746
      const int col_block_size = bs->cols[col_block_id].size;
Packit ea1746
      MatrixTransposeVectorMultiply<Eigen::Dynamic, Eigen::Dynamic, 1>(
Packit ea1746
        values + cells[c].position, row_block_size, col_block_size,
Packit ea1746
        x + row_block_pos,
Packit ea1746
        y + col_block_pos - num_cols_e_);
Packit ea1746
    }
Packit ea1746
  }
Packit ea1746
}
Packit ea1746
Packit ea1746
// Given a range of columns blocks of a matrix m, compute the block
Packit ea1746
// structure of the block diagonal of the matrix m(:,
Packit ea1746
// start_col_block:end_col_block)'m(:, start_col_block:end_col_block)
Packit ea1746
// and return a BlockSparseMatrix with the this block structure. The
Packit ea1746
// caller owns the result.
Packit ea1746
template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
Packit ea1746
BlockSparseMatrix*
Packit ea1746
PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
Packit ea1746
CreateBlockDiagonalMatrixLayout(int start_col_block, int end_col_block) const {
Packit ea1746
  const CompressedRowBlockStructure* bs = matrix_.block_structure();
Packit ea1746
  CompressedRowBlockStructure* block_diagonal_structure =
Packit ea1746
      new CompressedRowBlockStructure;
Packit ea1746
Packit ea1746
  int block_position = 0;
Packit ea1746
  int diagonal_cell_position = 0;
Packit ea1746
Packit ea1746
  // Iterate over the column blocks, creating a new diagonal block for
Packit ea1746
  // each column block.
Packit ea1746
  for (int c = start_col_block; c < end_col_block; ++c) {
Packit ea1746
    const Block& block = bs->cols[c];
Packit ea1746
    block_diagonal_structure->cols.push_back(Block());
Packit ea1746
    Block& diagonal_block = block_diagonal_structure->cols.back();
Packit ea1746
    diagonal_block.size = block.size;
Packit ea1746
    diagonal_block.position = block_position;
Packit ea1746
Packit ea1746
    block_diagonal_structure->rows.push_back(CompressedRow());
Packit ea1746
    CompressedRow& row = block_diagonal_structure->rows.back();
Packit ea1746
    row.block = diagonal_block;
Packit ea1746
Packit ea1746
    row.cells.push_back(Cell());
Packit ea1746
    Cell& cell = row.cells.back();
Packit ea1746
    cell.block_id = c - start_col_block;
Packit ea1746
    cell.position = diagonal_cell_position;
Packit ea1746
Packit ea1746
    block_position += block.size;
Packit ea1746
    diagonal_cell_position += block.size * block.size;
Packit ea1746
  }
Packit ea1746
Packit ea1746
  // Build a BlockSparseMatrix with the just computed block
Packit ea1746
  // structure.
Packit ea1746
  return new BlockSparseMatrix(block_diagonal_structure);
Packit ea1746
}
Packit ea1746
Packit ea1746
template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
Packit ea1746
BlockSparseMatrix*
Packit ea1746
PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
Packit ea1746
CreateBlockDiagonalEtE() const {
Packit ea1746
  BlockSparseMatrix* block_diagonal =
Packit ea1746
      CreateBlockDiagonalMatrixLayout(0, num_col_blocks_e_);
Packit ea1746
  UpdateBlockDiagonalEtE(block_diagonal);
Packit ea1746
  return block_diagonal;
Packit ea1746
}
Packit ea1746
Packit ea1746
template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
Packit ea1746
BlockSparseMatrix*
Packit ea1746
PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
Packit ea1746
CreateBlockDiagonalFtF() const {
Packit ea1746
  BlockSparseMatrix* block_diagonal =
Packit ea1746
      CreateBlockDiagonalMatrixLayout(
Packit ea1746
          num_col_blocks_e_, num_col_blocks_e_ + num_col_blocks_f_);
Packit ea1746
  UpdateBlockDiagonalFtF(block_diagonal);
Packit ea1746
  return block_diagonal;
Packit ea1746
}
Packit ea1746
Packit ea1746
// Similar to the code in RightMultiplyE, except instead of the matrix
Packit ea1746
// vector multiply its an outer product.
Packit ea1746
//
Packit ea1746
//    block_diagonal = block_diagonal(E'E)
Packit ea1746
//
Packit ea1746
template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
Packit ea1746
void
Packit ea1746
PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
Packit ea1746
UpdateBlockDiagonalEtE(
Packit ea1746
    BlockSparseMatrix* block_diagonal) const {
Packit ea1746
  const CompressedRowBlockStructure* bs = matrix_.block_structure();
Packit ea1746
  const CompressedRowBlockStructure* block_diagonal_structure =
Packit ea1746
      block_diagonal->block_structure();
Packit ea1746
Packit ea1746
  block_diagonal->SetZero();
Packit ea1746
  const double* values = matrix_.values();
Packit ea1746
  for (int r = 0; r < num_row_blocks_e_ ; ++r) {
Packit ea1746
    const Cell& cell = bs->rows[r].cells[0];
Packit ea1746
    const int row_block_size = bs->rows[r].block.size;
Packit ea1746
    const int block_id = cell.block_id;
Packit ea1746
    const int col_block_size = bs->cols[block_id].size;
Packit ea1746
    const int cell_position =
Packit ea1746
        block_diagonal_structure->rows[block_id].cells[0].position;
Packit ea1746
Packit ea1746
    MatrixTransposeMatrixMultiply
Packit ea1746
        <kRowBlockSize, kEBlockSize, kRowBlockSize, kEBlockSize, 1>(
Packit ea1746
            values + cell.position, row_block_size, col_block_size,
Packit ea1746
            values + cell.position, row_block_size, col_block_size,
Packit ea1746
            block_diagonal->mutable_values() + cell_position,
Packit ea1746
            0, 0, col_block_size, col_block_size);
Packit ea1746
  }
Packit ea1746
}
Packit ea1746
Packit ea1746
// Similar to the code in RightMultiplyF, except instead of the matrix
Packit ea1746
// vector multiply its an outer product.
Packit ea1746
//
Packit ea1746
//   block_diagonal = block_diagonal(F'F)
Packit ea1746
//
Packit ea1746
template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
Packit ea1746
void
Packit ea1746
PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
Packit ea1746
UpdateBlockDiagonalFtF(BlockSparseMatrix* block_diagonal) const {
Packit ea1746
  const CompressedRowBlockStructure* bs = matrix_.block_structure();
Packit ea1746
  const CompressedRowBlockStructure* block_diagonal_structure =
Packit ea1746
      block_diagonal->block_structure();
Packit ea1746
Packit ea1746
  block_diagonal->SetZero();
Packit ea1746
  const double* values = matrix_.values();
Packit ea1746
  for (int r = 0; r < num_row_blocks_e_; ++r) {
Packit ea1746
    const int row_block_size = bs->rows[r].block.size;
Packit ea1746
    const std::vector<Cell>& cells = bs->rows[r].cells;
Packit ea1746
    for (int c = 1; c < cells.size(); ++c) {
Packit ea1746
      const int col_block_id = cells[c].block_id;
Packit ea1746
      const int col_block_size = bs->cols[col_block_id].size;
Packit ea1746
      const int diagonal_block_id = col_block_id - num_col_blocks_e_;
Packit ea1746
      const int cell_position =
Packit ea1746
          block_diagonal_structure->rows[diagonal_block_id].cells[0].position;
Packit ea1746
Packit ea1746
      MatrixTransposeMatrixMultiply
Packit ea1746
          <kRowBlockSize, kFBlockSize, kRowBlockSize, kFBlockSize, 1>(
Packit ea1746
              values + cells[c].position, row_block_size, col_block_size,
Packit ea1746
              values + cells[c].position, row_block_size, col_block_size,
Packit ea1746
              block_diagonal->mutable_values() + cell_position,
Packit ea1746
              0, 0, col_block_size, col_block_size);
Packit ea1746
    }
Packit ea1746
  }
Packit ea1746
Packit ea1746
  for (int r = num_row_blocks_e_; r < bs->rows.size(); ++r) {
Packit ea1746
    const int row_block_size = bs->rows[r].block.size;
Packit ea1746
    const std::vector<Cell>& cells = bs->rows[r].cells;
Packit ea1746
    for (int c = 0; c < cells.size(); ++c) {
Packit ea1746
      const int col_block_id = cells[c].block_id;
Packit ea1746
      const int col_block_size = bs->cols[col_block_id].size;
Packit ea1746
      const int diagonal_block_id = col_block_id - num_col_blocks_e_;
Packit ea1746
      const int cell_position =
Packit ea1746
          block_diagonal_structure->rows[diagonal_block_id].cells[0].position;
Packit ea1746
Packit ea1746
      MatrixTransposeMatrixMultiply
Packit ea1746
          <Eigen::Dynamic, Eigen::Dynamic, Eigen::Dynamic, Eigen::Dynamic, 1>(
Packit ea1746
              values + cells[c].position, row_block_size, col_block_size,
Packit ea1746
              values + cells[c].position, row_block_size, col_block_size,
Packit ea1746
              block_diagonal->mutable_values() + cell_position,
Packit ea1746
              0, 0, col_block_size, col_block_size);
Packit ea1746
    }
Packit ea1746
  }
Packit ea1746
}
Packit ea1746
Packit ea1746
}  // namespace internal
Packit ea1746
}  // namespace ceres