mirror of
https://github.com/ceres-solver/ceres-solver.git
synced 2026-08-30 00:50:37 +08:00
6685e629f9
Add structure of transposed matrix to BlockSparseMatrix Number of non-zero values per row block and cumulative non-zero values count are maintained for transposed structure Change-Id: Icf38bb7a734ca695c788579eece1c92d36d78e54
195 lines
7.4 KiB
C++
195 lines
7.4 KiB
C++
// Ceres Solver - A fast non-linear least squares minimizer
|
|
// Copyright 2015 Google Inc. All rights reserved.
|
|
// http://ceres-solver.org/
|
|
//
|
|
// Redistribution and use in source and binary forms, with or without
|
|
// modification, are permitted provided that the following conditions are met:
|
|
//
|
|
// * Redistributions of source code must retain the above copyright notice,
|
|
// this list of conditions and the following disclaimer.
|
|
// * Redistributions in binary form must reproduce the above copyright notice,
|
|
// this list of conditions and the following disclaimer in the documentation
|
|
// and/or other materials provided with the distribution.
|
|
// * Neither the name of Google Inc. nor the names of its contributors may be
|
|
// used to endorse or promote products derived from this software without
|
|
// specific prior written permission.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
// POSSIBILITY OF SUCH DAMAGE.
|
|
//
|
|
// Author: sameeragarwal@google.com (Sameer Agarwal)
|
|
//
|
|
// Block structure objects are used to carry information about the
|
|
// dense block structure of sparse matrices. The BlockSparseMatrix
|
|
// object uses the BlockStructure objects to keep track of the matrix
|
|
// structure and operate upon it. This allows us to use more cache
|
|
// friendly block oriented linear algebra operations on the matrix
|
|
// instead of accessing it one scalar entry at a time.
|
|
|
|
#ifndef CERES_INTERNAL_BLOCK_STRUCTURE_H_
|
|
#define CERES_INTERNAL_BLOCK_STRUCTURE_H_
|
|
|
|
#include <cstdint>
|
|
#include <vector>
|
|
|
|
#include "ceres/internal/export.h"
|
|
|
|
namespace ceres::internal {
|
|
|
|
using BlockSize = int32_t;
|
|
|
|
struct CERES_NO_EXPORT Block {
|
|
Block() = default;
|
|
Block(int size_, int position_) noexcept : size(size_), position(position_) {}
|
|
|
|
BlockSize size{-1};
|
|
int position{-1}; // Position along the row/column.
|
|
};
|
|
|
|
inline bool operator==(const Block& left, const Block& right) noexcept {
|
|
return (left.size == right.size) && (left.position == right.position);
|
|
}
|
|
|
|
struct CERES_NO_EXPORT Cell {
|
|
Cell() = default;
|
|
Cell(int block_id_, int position_) noexcept
|
|
: block_id(block_id_), position(position_) {}
|
|
|
|
// Column or row block id as the case maybe.
|
|
int block_id{-1};
|
|
// Where in the values array of the jacobian is this cell located.
|
|
int position{-1};
|
|
};
|
|
|
|
// Order cell by their block_id;
|
|
CERES_NO_EXPORT bool CellLessThan(const Cell& lhs, const Cell& rhs);
|
|
|
|
struct CERES_NO_EXPORT CompressedList {
|
|
CompressedList() = default;
|
|
|
|
// Construct a CompressedList with the cells containing num_cells
|
|
// entries.
|
|
explicit CompressedList(int num_cells) noexcept : cells(num_cells) {}
|
|
Block block;
|
|
std::vector<Cell> cells;
|
|
// Number of non-zeros in cells of this row block
|
|
int nnz{-1};
|
|
// Number of non-zeros in cells of this and every preceeding row block in
|
|
// block-sparse matrix
|
|
int cumulative_nnz{-1};
|
|
};
|
|
|
|
using CompressedRow = CompressedList;
|
|
using CompressedColumn = CompressedList;
|
|
|
|
// CompressedRowBlockStructure specifies the storage structure of a row block
|
|
// sparse matrix.
|
|
//
|
|
// Consider the following matrix A:
|
|
// A = [A_11 A_12 ...
|
|
// A_21 A_22 ...
|
|
// ...
|
|
// A_m1 A_m2 ... ]
|
|
//
|
|
// A row block sparse matrix is a matrix where the following properties hold:
|
|
// 1. The number of rows in every block A_ij and A_ik are the same.
|
|
// 2. The number of columns in every block A_ij and A_kj are the same.
|
|
// 3. The number of rows in A_ij and A_kj may be different (i != k).
|
|
// 4. The number of columns in A_ij and A_ik may be different (j != k).
|
|
// 5. Any block A_ij may be all 0s, in which case the block is not stored.
|
|
//
|
|
// The structure of the matrix is stored as follows:
|
|
//
|
|
// The `rows' array contains the following information for each row block:
|
|
// - rows[i].block.size: The number of rows in each block A_ij in the row block.
|
|
// - rows[i].block.position: The starting row in the full matrix A of the
|
|
// row block i.
|
|
// - rows[i].cells[j].block_id: The index into the `cols' array corresponding to
|
|
// the non-zero blocks A_ij.
|
|
// - rows[i].cells[j].position: The index in the `values' array for the contents
|
|
// of block A_ij.
|
|
//
|
|
// The `cols' array contains the following information for block:
|
|
// - cols[.].size: The number of columns spanned by the block.
|
|
// - cols[.].position: The starting column in the full matrix A of the block.
|
|
//
|
|
//
|
|
// Example of a row block sparse matrix:
|
|
// block_id: | 0 |1|2 |3 |
|
|
// rows[0]: [ 1 2 0 3 4 0 ]
|
|
// [ 5 6 0 7 8 0 ]
|
|
// rows[1]: [ 0 0 9 0 0 0 ]
|
|
//
|
|
// This matrix is stored as follows:
|
|
//
|
|
// There are four column blocks:
|
|
// cols[0].size = 2
|
|
// cols[0].position = 0
|
|
// cols[1].size = 1
|
|
// cols[1].position = 2
|
|
// cols[2].size = 2
|
|
// cols[2].position = 3
|
|
// cols[3].size = 1
|
|
// cols[3].position = 5
|
|
|
|
// The first row block spans two rows, starting at row 0:
|
|
// rows[0].block.size = 2 // This row block spans two rows.
|
|
// rows[0].block.position = 0 // It starts at row 0.
|
|
// rows[0] has two cells, at column blocks 0 and 2:
|
|
// rows[0].cells[0].block_id = 0 // This cell is in column block 0.
|
|
// rows[0].cells[0].position = 0 // See below for an explanation of this.
|
|
// rows[0].cells[1].block_id = 2 // This cell is in column block 2.
|
|
// rows[0].cells[1].position = 4 // See below for an explanation of this.
|
|
//
|
|
// The second row block spans two rows, starting at row 2:
|
|
// rows[1].block.size = 1 // This row block spans one row.
|
|
// rows[1].block.position = 2 // It starts at row 2.
|
|
// rows[1] has one cell at column block 1:
|
|
// rows[1].cells[0].block_id = 1 // This cell is in column block 1.
|
|
// rows[1].cells[0].position = 8 // See below for an explanation of this.
|
|
//
|
|
// The values in each blocks are stored contiguously in row major order.
|
|
// However, there is no unique way to order the blocks -- it is usually
|
|
// optimized to promote cache coherent access, e.g. ordering it so that
|
|
// Jacobian blocks of parameters of the same type are stored nearby.
|
|
// This is one possible way to store the values of the blocks in a values array:
|
|
// values = { 1, 2, 5, 6, 3, 4, 7, 8, 9 }
|
|
// | | | | // The three blocks.
|
|
// ^ rows[0].cells[0].position = 0
|
|
// ^ rows[0].cells[1].position = 4
|
|
// ^ rows[1].cells[0].position = 8
|
|
struct CERES_NO_EXPORT CompressedRowBlockStructure {
|
|
std::vector<Block> cols;
|
|
std::vector<CompressedRow> rows;
|
|
};
|
|
|
|
struct CERES_NO_EXPORT CompressedColumnBlockStructure {
|
|
std::vector<Block> rows;
|
|
std::vector<CompressedColumn> cols;
|
|
};
|
|
|
|
inline int NumScalarEntries(const std::vector<Block>& blocks) {
|
|
if (blocks.empty()) {
|
|
return 0;
|
|
}
|
|
|
|
auto& block = blocks.back();
|
|
return block.position + block.size;
|
|
}
|
|
|
|
std::vector<Block> Tail(const std::vector<Block>& blocks, int n);
|
|
int SumSquaredSizes(const std::vector<Block>& blocks);
|
|
|
|
} // namespace ceres::internal
|
|
|
|
#endif // CERES_INTERNAL_BLOCK_STRUCTURE_H_
|