blob: 9500fbb13abbfaea128995f7f9d0b879b0fe09d9 [file] [log] [blame]
Austin Schuh70cc9552019-01-21 19:46:48 -08001// Ceres Solver - A fast non-linear least squares minimizer
Austin Schuh3de38b02024-06-25 18:25:10 -07002// Copyright 2023 Google Inc. All rights reserved.
Austin Schuh70cc9552019-01-21 19:46:48 -08003// http://ceres-solver.org/
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@google.com (Sameer Agarwal)
30//
31// Block structure objects are used to carry information about the
32// dense block structure of sparse matrices. The BlockSparseMatrix
33// object uses the BlockStructure objects to keep track of the matrix
34// structure and operate upon it. This allows us to use more cache
35// friendly block oriented linear algebra operations on the matrix
36// instead of accessing it one scalar entry at a time.
37
38#ifndef CERES_INTERNAL_BLOCK_STRUCTURE_H_
39#define CERES_INTERNAL_BLOCK_STRUCTURE_H_
40
41#include <cstdint>
42#include <vector>
Austin Schuh1d1e6ea2020-12-23 21:56:30 -080043
Austin Schuh3de38b02024-06-25 18:25:10 -070044#include "ceres/internal/export.h"
Austin Schuh70cc9552019-01-21 19:46:48 -080045
Austin Schuh3de38b02024-06-25 18:25:10 -070046// This file is being included into source files that are compiled with nvcc.
47// nvcc shipped with ubuntu 20.04 does not support some features of c++17,
48// including nested namespace definitions
Austin Schuh70cc9552019-01-21 19:46:48 -080049namespace ceres {
50namespace internal {
51
Austin Schuh3de38b02024-06-25 18:25:10 -070052using BlockSize = int32_t;
Austin Schuh70cc9552019-01-21 19:46:48 -080053
Austin Schuh3de38b02024-06-25 18:25:10 -070054struct CERES_NO_EXPORT Block {
55 Block() = default;
56 Block(int size_, int position_) noexcept : size(size_), position(position_) {}
Austin Schuh70cc9552019-01-21 19:46:48 -080057
Austin Schuh3de38b02024-06-25 18:25:10 -070058 BlockSize size{-1};
59 int position{-1}; // Position along the row/column.
Austin Schuh70cc9552019-01-21 19:46:48 -080060};
61
Austin Schuh3de38b02024-06-25 18:25:10 -070062inline bool operator==(const Block& left, const Block& right) noexcept {
63 return (left.size == right.size) && (left.position == right.position);
64}
65
66struct CERES_NO_EXPORT Cell {
67 Cell() = default;
68 Cell(int block_id_, int position_) noexcept
Austin Schuh70cc9552019-01-21 19:46:48 -080069 : block_id(block_id_), position(position_) {}
70
71 // Column or row block id as the case maybe.
Austin Schuh3de38b02024-06-25 18:25:10 -070072 int block_id{-1};
Austin Schuh70cc9552019-01-21 19:46:48 -080073 // Where in the values array of the jacobian is this cell located.
Austin Schuh3de38b02024-06-25 18:25:10 -070074 int position{-1};
Austin Schuh70cc9552019-01-21 19:46:48 -080075};
76
77// Order cell by their block_id;
Austin Schuh3de38b02024-06-25 18:25:10 -070078CERES_NO_EXPORT bool CellLessThan(const Cell& lhs, const Cell& rhs);
Austin Schuh70cc9552019-01-21 19:46:48 -080079
Austin Schuh3de38b02024-06-25 18:25:10 -070080struct CERES_NO_EXPORT CompressedList {
81 CompressedList() = default;
Austin Schuh70cc9552019-01-21 19:46:48 -080082
83 // Construct a CompressedList with the cells containing num_cells
84 // entries.
Austin Schuh3de38b02024-06-25 18:25:10 -070085 explicit CompressedList(int num_cells) noexcept : cells(num_cells) {}
Austin Schuh70cc9552019-01-21 19:46:48 -080086 Block block;
87 std::vector<Cell> cells;
Austin Schuh3de38b02024-06-25 18:25:10 -070088 // Number of non-zeros in cells of this row block
89 int nnz{-1};
90 // Number of non-zeros in cells of this and every preceeding row block in
91 // block-sparse matrix
92 int cumulative_nnz{-1};
Austin Schuh70cc9552019-01-21 19:46:48 -080093};
94
Austin Schuh3de38b02024-06-25 18:25:10 -070095using CompressedRow = CompressedList;
96using CompressedColumn = CompressedList;
Austin Schuh70cc9552019-01-21 19:46:48 -080097
Austin Schuh3de38b02024-06-25 18:25:10 -070098// CompressedRowBlockStructure specifies the storage structure of a row block
99// sparse matrix.
100//
101// Consider the following matrix A:
102// A = [A_11 A_12 ...
103// A_21 A_22 ...
104// ...
105// A_m1 A_m2 ... ]
106//
107// A row block sparse matrix is a matrix where the following properties hold:
108// 1. The number of rows in every block A_ij and A_ik are the same.
109// 2. The number of columns in every block A_ij and A_kj are the same.
110// 3. The number of rows in A_ij and A_kj may be different (i != k).
111// 4. The number of columns in A_ij and A_ik may be different (j != k).
112// 5. Any block A_ij may be all 0s, in which case the block is not stored.
113//
114// The structure of the matrix is stored as follows:
115//
116// The `rows' array contains the following information for each row block:
117// - rows[i].block.size: The number of rows in each block A_ij in the row block.
118// - rows[i].block.position: The starting row in the full matrix A of the
119// row block i.
120// - rows[i].cells[j].block_id: The index into the `cols' array corresponding to
121// the non-zero blocks A_ij.
122// - rows[i].cells[j].position: The index in the `values' array for the contents
123// of block A_ij.
124//
125// The `cols' array contains the following information for block:
126// - cols[.].size: The number of columns spanned by the block.
127// - cols[.].position: The starting column in the full matrix A of the block.
128//
129//
130// Example of a row block sparse matrix:
131// block_id: | 0 |1|2 |3 |
132// rows[0]: [ 1 2 0 3 4 0 ]
133// [ 5 6 0 7 8 0 ]
134// rows[1]: [ 0 0 9 0 0 0 ]
135//
136// This matrix is stored as follows:
137//
138// There are four column blocks:
139// cols[0].size = 2
140// cols[0].position = 0
141// cols[1].size = 1
142// cols[1].position = 2
143// cols[2].size = 2
144// cols[2].position = 3
145// cols[3].size = 1
146// cols[3].position = 5
147
148// The first row block spans two rows, starting at row 0:
149// rows[0].block.size = 2 // This row block spans two rows.
150// rows[0].block.position = 0 // It starts at row 0.
151// rows[0] has two cells, at column blocks 0 and 2:
152// rows[0].cells[0].block_id = 0 // This cell is in column block 0.
153// rows[0].cells[0].position = 0 // See below for an explanation of this.
154// rows[0].cells[1].block_id = 2 // This cell is in column block 2.
155// rows[0].cells[1].position = 4 // See below for an explanation of this.
156//
157// The second row block spans two rows, starting at row 2:
158// rows[1].block.size = 1 // This row block spans one row.
159// rows[1].block.position = 2 // It starts at row 2.
160// rows[1] has one cell at column block 1:
161// rows[1].cells[0].block_id = 1 // This cell is in column block 1.
162// rows[1].cells[0].position = 8 // See below for an explanation of this.
163//
164// The values in each blocks are stored contiguously in row major order.
165// However, there is no unique way to order the blocks -- it is usually
166// optimized to promote cache coherent access, e.g. ordering it so that
167// Jacobian blocks of parameters of the same type are stored nearby.
168// This is one possible way to store the values of the blocks in a values array:
169// values = { 1, 2, 5, 6, 3, 4, 7, 8, 9 }
170// | | | | // The three blocks.
171// ^ rows[0].cells[0].position = 0
172// ^ rows[0].cells[1].position = 4
173// ^ rows[1].cells[0].position = 8
174struct CERES_NO_EXPORT CompressedRowBlockStructure {
Austin Schuh70cc9552019-01-21 19:46:48 -0800175 std::vector<Block> cols;
176 std::vector<CompressedRow> rows;
177};
178
Austin Schuh3de38b02024-06-25 18:25:10 -0700179struct CERES_NO_EXPORT CompressedColumnBlockStructure {
Austin Schuh70cc9552019-01-21 19:46:48 -0800180 std::vector<Block> rows;
181 std::vector<CompressedColumn> cols;
182};
183
Austin Schuh3de38b02024-06-25 18:25:10 -0700184inline int NumScalarEntries(const std::vector<Block>& blocks) {
185 if (blocks.empty()) {
186 return 0;
187 }
188
189 auto& block = blocks.back();
190 return block.position + block.size;
191}
192
193std::vector<Block> Tail(const std::vector<Block>& blocks, int n);
194int SumSquaredSizes(const std::vector<Block>& blocks);
195
Austin Schuh70cc9552019-01-21 19:46:48 -0800196} // namespace internal
197} // namespace ceres
198
199#endif // CERES_INTERNAL_BLOCK_STRUCTURE_H_