123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336 |
- #include "ceres/inner_product_computer.h"
- #include <algorithm>
- #include <memory>
- #include "ceres/small_blas.h"
- namespace ceres::internal {
- std::unique_ptr<CompressedRowSparseMatrix>
- InnerProductComputer::CreateResultMatrix(
- const CompressedRowSparseMatrix::StorageType storage_type,
- const int num_nonzeros) {
- auto matrix = std::make_unique<CompressedRowSparseMatrix>(
- m_.num_cols(), m_.num_cols(), num_nonzeros);
- matrix->set_storage_type(storage_type);
- const CompressedRowBlockStructure* bs = m_.block_structure();
- *matrix->mutable_row_blocks() = bs->cols;
- *matrix->mutable_col_blocks() = bs->cols;
- return matrix;
- }
- int InnerProductComputer::ComputeNonzeros(
- const std::vector<InnerProductComputer::ProductTerm>& product_terms,
- std::vector<int>* row_nnz) {
- const CompressedRowBlockStructure* bs = m_.block_structure();
- const std::vector<Block>& blocks = bs->cols;
- row_nnz->resize(blocks.size());
- std::fill(row_nnz->begin(), row_nnz->end(), 0);
- if (product_terms.empty()) {
- return 0;
- }
-
- (*row_nnz)[product_terms[0].row] = blocks[product_terms[0].col].size;
- int num_nonzeros =
- blocks[product_terms[0].row].size * blocks[product_terms[0].col].size;
-
- for (int i = 1; i < product_terms.size(); ++i) {
- const ProductTerm& previous = product_terms[i - 1];
- const ProductTerm& current = product_terms[i];
-
-
- if (current.row != previous.row || current.col != previous.col) {
- (*row_nnz)[current.row] += blocks[current.col].size;
- num_nonzeros += blocks[current.row].size * blocks[current.col].size;
- }
- }
- return num_nonzeros;
- }
- InnerProductComputer::InnerProductComputer(const BlockSparseMatrix& m,
- const int start_row_block,
- const int end_row_block)
- : m_(m), start_row_block_(start_row_block), end_row_block_(end_row_block) {}
- std::unique_ptr<InnerProductComputer> InnerProductComputer::Create(
- const BlockSparseMatrix& m,
- CompressedRowSparseMatrix::StorageType product_storage_type) {
- return InnerProductComputer::Create(
- m, 0, m.block_structure()->rows.size(), product_storage_type);
- }
- std::unique_ptr<InnerProductComputer> InnerProductComputer::Create(
- const BlockSparseMatrix& m,
- const int start_row_block,
- const int end_row_block,
- CompressedRowSparseMatrix::StorageType product_storage_type) {
- CHECK(product_storage_type ==
- CompressedRowSparseMatrix::StorageType::LOWER_TRIANGULAR ||
- product_storage_type ==
- CompressedRowSparseMatrix::StorageType::UPPER_TRIANGULAR);
- CHECK_GT(m.num_nonzeros(), 0)
- << "Congratulations, you found a bug in Ceres. Please report it.";
- std::unique_ptr<InnerProductComputer> inner_product_computer(
- new InnerProductComputer(m, start_row_block, end_row_block));
- inner_product_computer->Init(product_storage_type);
- return inner_product_computer;
- }
- void InnerProductComputer::Init(
- const CompressedRowSparseMatrix::StorageType product_storage_type) {
- std::vector<InnerProductComputer::ProductTerm> product_terms;
- const CompressedRowBlockStructure* bs = m_.block_structure();
-
-
-
-
-
-
- for (int row_block = start_row_block_; row_block < end_row_block_;
- ++row_block) {
- const CompressedRow& row = bs->rows[row_block];
- for (int c1 = 0; c1 < row.cells.size(); ++c1) {
- const Cell& cell1 = row.cells[c1];
- int c2_begin, c2_end;
- if (product_storage_type ==
- CompressedRowSparseMatrix::StorageType::LOWER_TRIANGULAR) {
- c2_begin = 0;
- c2_end = c1 + 1;
- } else {
- c2_begin = c1;
- c2_end = row.cells.size();
- }
- for (int c2 = c2_begin; c2 < c2_end; ++c2) {
- const Cell& cell2 = row.cells[c2];
- product_terms.emplace_back(
- cell1.block_id, cell2.block_id, product_terms.size());
- }
- }
- }
- std::sort(product_terms.begin(), product_terms.end());
- ComputeOffsetsAndCreateResultMatrix(product_storage_type, product_terms);
- }
- void InnerProductComputer::ComputeOffsetsAndCreateResultMatrix(
- const CompressedRowSparseMatrix::StorageType product_storage_type,
- const std::vector<InnerProductComputer::ProductTerm>& product_terms) {
- const std::vector<Block>& col_blocks = m_.block_structure()->cols;
- std::vector<int> row_block_nnz;
- const int num_nonzeros = ComputeNonzeros(product_terms, &row_block_nnz);
- result_ = CreateResultMatrix(product_storage_type, num_nonzeros);
-
- int* crsm_rows = result_->mutable_rows();
- crsm_rows[0] = 0;
- for (int i = 0; i < col_blocks.size(); ++i) {
- for (int j = 0; j < col_blocks[i].size; ++j, ++crsm_rows) {
- *(crsm_rows + 1) = *crsm_rows + row_block_nnz[i];
- }
- }
- result_offsets_.resize(product_terms.size());
- if (num_nonzeros == 0) {
- return;
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- #define FILL_CRSM_COL_BLOCK \
- const int row_block = current->row; \
- const int col_block = current->col; \
- const int nnz_in_row = row_block_nnz[row_block]; \
- int* crsm_cols = result_->mutable_cols(); \
- result_offsets_[current->index] = nnz + col_nnz; \
- for (int j = 0; j < col_blocks[row_block].size; ++j) { \
- for (int k = 0; k < col_blocks[col_block].size; ++k) { \
- crsm_cols[nnz + j * nnz_in_row + col_nnz + k] = \
- col_blocks[col_block].position + k; \
- } \
- }
- int col_nnz = 0;
- int nnz = 0;
-
- const InnerProductComputer::ProductTerm* current = product_terms.data();
- FILL_CRSM_COL_BLOCK;
-
- for (int i = 1; i < product_terms.size(); ++i) {
- current = &product_terms[i];
- const InnerProductComputer::ProductTerm* previous = &product_terms[i - 1];
-
-
- if (previous->row == current->row && previous->col == current->col) {
- result_offsets_[current->index] = result_offsets_[previous->index];
- continue;
- }
- if (previous->row == current->row) {
-
-
-
- col_nnz += col_blocks[previous->col].size;
- } else {
-
-
- col_nnz = 0;
- nnz += row_block_nnz[previous->row] * col_blocks[previous->row].size;
- }
- FILL_CRSM_COL_BLOCK;
- }
- }
- void InnerProductComputer::Compute() {
- const double* m_values = m_.values();
- const CompressedRowBlockStructure* bs = m_.block_structure();
- const CompressedRowSparseMatrix::StorageType storage_type =
- result_->storage_type();
- result_->SetZero();
- double* values = result_->mutable_values();
- const int* rows = result_->rows();
- int cursor = 0;
-
- for (int r = start_row_block_; r < end_row_block_; ++r) {
- const CompressedRow& m_row = bs->rows[r];
- for (int c1 = 0; c1 < m_row.cells.size(); ++c1) {
- const Cell& cell1 = m_row.cells[c1];
- const int c1_size = bs->cols[cell1.block_id].size;
- const int row_nnz = rows[bs->cols[cell1.block_id].position + 1] -
- rows[bs->cols[cell1.block_id].position];
- int c2_begin, c2_end;
- if (storage_type ==
- CompressedRowSparseMatrix::StorageType::LOWER_TRIANGULAR) {
- c2_begin = 0;
- c2_end = c1 + 1;
- } else {
- c2_begin = c1;
- c2_end = m_row.cells.size();
- }
- for (int c2 = c2_begin; c2 < c2_end; ++c2, ++cursor) {
- const Cell& cell2 = m_row.cells[c2];
- const int c2_size = bs->cols[cell2.block_id].size;
-
- MatrixTransposeMatrixMultiply<Eigen::Dynamic, Eigen::Dynamic,
- Eigen::Dynamic, Eigen::Dynamic, 1>(
- m_values + cell1.position,
- m_row.block.size, c1_size,
- m_values + cell2.position,
- m_row.block.size, c2_size,
- values + result_offsets_[cursor],
- 0, 0, c1_size, row_nnz);
-
- }
- }
- }
- CHECK_EQ(cursor, result_offsets_.size());
- }
- }
|