blob: 2b8bf6e10f28bcbaab1e369e2f0123e3c4fe4fcb [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#include "ceres/parameter_block_ordering.h"
32
Austin Schuh3de38b02024-06-25 18:25:10 -070033#include <map>
Austin Schuh70cc9552019-01-21 19:46:48 -080034#include <memory>
Austin Schuh3de38b02024-06-25 18:25:10 -070035#include <set>
Austin Schuh70cc9552019-01-21 19:46:48 -080036#include <unordered_set>
Austin Schuh3de38b02024-06-25 18:25:10 -070037#include <vector>
Austin Schuh70cc9552019-01-21 19:46:48 -080038
39#include "ceres/graph.h"
40#include "ceres/graph_algorithms.h"
41#include "ceres/map_util.h"
42#include "ceres/parameter_block.h"
43#include "ceres/program.h"
44#include "ceres/residual_block.h"
45#include "ceres/wall_time.h"
46#include "glog/logging.h"
47
Austin Schuh3de38b02024-06-25 18:25:10 -070048namespace ceres::internal {
Austin Schuh70cc9552019-01-21 19:46:48 -080049
50int ComputeStableSchurOrdering(const Program& program,
Austin Schuh3de38b02024-06-25 18:25:10 -070051 std::vector<ParameterBlock*>* ordering) {
Austin Schuh70cc9552019-01-21 19:46:48 -080052 CHECK(ordering != nullptr);
53 ordering->clear();
54 EventLogger event_logger("ComputeStableSchurOrdering");
Austin Schuh3de38b02024-06-25 18:25:10 -070055 auto graph = CreateHessianGraph(program);
Austin Schuh70cc9552019-01-21 19:46:48 -080056 event_logger.AddEvent("CreateHessianGraph");
57
Austin Schuh3de38b02024-06-25 18:25:10 -070058 const std::vector<ParameterBlock*>& parameter_blocks =
59 program.parameter_blocks();
Austin Schuh70cc9552019-01-21 19:46:48 -080060 const std::unordered_set<ParameterBlock*>& vertices = graph->vertices();
Austin Schuh3de38b02024-06-25 18:25:10 -070061 for (auto* parameter_block : parameter_blocks) {
62 if (vertices.count(parameter_block) > 0) {
63 ordering->push_back(parameter_block);
Austin Schuh70cc9552019-01-21 19:46:48 -080064 }
65 }
66 event_logger.AddEvent("Preordering");
67
68 int independent_set_size = StableIndependentSetOrdering(*graph, ordering);
69 event_logger.AddEvent("StableIndependentSet");
70
71 // Add the excluded blocks to back of the ordering vector.
Austin Schuh3de38b02024-06-25 18:25:10 -070072 for (auto* parameter_block : parameter_blocks) {
Austin Schuh70cc9552019-01-21 19:46:48 -080073 if (parameter_block->IsConstant()) {
74 ordering->push_back(parameter_block);
75 }
76 }
77 event_logger.AddEvent("ConstantParameterBlocks");
78
79 return independent_set_size;
80}
81
82int ComputeSchurOrdering(const Program& program,
Austin Schuh3de38b02024-06-25 18:25:10 -070083 std::vector<ParameterBlock*>* ordering) {
Austin Schuh70cc9552019-01-21 19:46:48 -080084 CHECK(ordering != nullptr);
85 ordering->clear();
86
Austin Schuh3de38b02024-06-25 18:25:10 -070087 auto graph = CreateHessianGraph(program);
Austin Schuh70cc9552019-01-21 19:46:48 -080088 int independent_set_size = IndependentSetOrdering(*graph, ordering);
Austin Schuh3de38b02024-06-25 18:25:10 -070089 const std::vector<ParameterBlock*>& parameter_blocks =
90 program.parameter_blocks();
Austin Schuh70cc9552019-01-21 19:46:48 -080091
92 // Add the excluded blocks to back of the ordering vector.
Austin Schuh3de38b02024-06-25 18:25:10 -070093 for (auto* parameter_block : parameter_blocks) {
Austin Schuh70cc9552019-01-21 19:46:48 -080094 if (parameter_block->IsConstant()) {
95 ordering->push_back(parameter_block);
96 }
97 }
98
99 return independent_set_size;
100}
101
102void ComputeRecursiveIndependentSetOrdering(const Program& program,
103 ParameterBlockOrdering* ordering) {
104 CHECK(ordering != nullptr);
105 ordering->Clear();
Austin Schuh3de38b02024-06-25 18:25:10 -0700106 const std::vector<ParameterBlock*> parameter_blocks =
107 program.parameter_blocks();
108 auto graph = CreateHessianGraph(program);
Austin Schuh70cc9552019-01-21 19:46:48 -0800109
110 int num_covered = 0;
111 int round = 0;
112 while (num_covered < parameter_blocks.size()) {
Austin Schuh3de38b02024-06-25 18:25:10 -0700113 std::vector<ParameterBlock*> independent_set_ordering;
Austin Schuh70cc9552019-01-21 19:46:48 -0800114 const int independent_set_size =
115 IndependentSetOrdering(*graph, &independent_set_ordering);
116 for (int i = 0; i < independent_set_size; ++i) {
117 ParameterBlock* parameter_block = independent_set_ordering[i];
118 ordering->AddElementToGroup(parameter_block->mutable_user_state(), round);
119 graph->RemoveVertex(parameter_block);
120 }
121 num_covered += independent_set_size;
122 ++round;
123 }
124}
125
Austin Schuh3de38b02024-06-25 18:25:10 -0700126std::unique_ptr<Graph<ParameterBlock*>> CreateHessianGraph(
127 const Program& program) {
128 auto graph = std::make_unique<Graph<ParameterBlock*>>();
Austin Schuh70cc9552019-01-21 19:46:48 -0800129 CHECK(graph != nullptr);
Austin Schuh3de38b02024-06-25 18:25:10 -0700130 const std::vector<ParameterBlock*>& parameter_blocks =
131 program.parameter_blocks();
132 for (auto* parameter_block : parameter_blocks) {
Austin Schuh70cc9552019-01-21 19:46:48 -0800133 if (!parameter_block->IsConstant()) {
134 graph->AddVertex(parameter_block);
135 }
136 }
137
Austin Schuh3de38b02024-06-25 18:25:10 -0700138 const std::vector<ResidualBlock*>& residual_blocks =
139 program.residual_blocks();
140 for (auto* residual_block : residual_blocks) {
Austin Schuh70cc9552019-01-21 19:46:48 -0800141 const int num_parameter_blocks = residual_block->NumParameterBlocks();
142 ParameterBlock* const* parameter_blocks =
143 residual_block->parameter_blocks();
144 for (int j = 0; j < num_parameter_blocks; ++j) {
145 if (parameter_blocks[j]->IsConstant()) {
146 continue;
147 }
148
149 for (int k = j + 1; k < num_parameter_blocks; ++k) {
150 if (parameter_blocks[k]->IsConstant()) {
151 continue;
152 }
153
154 graph->AddEdge(parameter_blocks[j], parameter_blocks[k]);
155 }
156 }
157 }
158
159 return graph;
160}
161
162void OrderingToGroupSizes(const ParameterBlockOrdering* ordering,
Austin Schuh3de38b02024-06-25 18:25:10 -0700163 std::vector<int>* group_sizes) {
Austin Schuh70cc9552019-01-21 19:46:48 -0800164 CHECK(group_sizes != nullptr);
165 group_sizes->clear();
Austin Schuh3de38b02024-06-25 18:25:10 -0700166 if (ordering == nullptr) {
Austin Schuh70cc9552019-01-21 19:46:48 -0800167 return;
168 }
169
Austin Schuh3de38b02024-06-25 18:25:10 -0700170 // TODO(sameeragarwal): Investigate if this should be a set or an
171 // unordered_set.
172 const std::map<int, std::set<double*>>& group_to_elements =
Austin Schuh70cc9552019-01-21 19:46:48 -0800173 ordering->group_to_elements();
174 for (const auto& g_t_e : group_to_elements) {
175 group_sizes->push_back(g_t_e.second.size());
176 }
177}
178
Austin Schuh3de38b02024-06-25 18:25:10 -0700179} // namespace ceres::internal