blob: 733f26ed5883e8d97bcd88aaceafcfdb219aa739 [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: keir@google.com (Keir Mierle)
30//
31// This is the implementation of the public Problem API. The pointer to
32// implementation (PIMPL) idiom makes it possible for Ceres internal code to
33// refer to the private data members without needing to exposing it to the
34// world. An alternative to PIMPL is to have a factory which returns instances
35// of a virtual base class; while that approach would work, it requires clients
36// to always put a Problem object into a scoped pointer; this needlessly muddies
37// client code for little benefit. Therefore, the PIMPL comprise was chosen.
38
39#ifndef CERES_PUBLIC_PROBLEM_IMPL_H_
40#define CERES_PUBLIC_PROBLEM_IMPL_H_
41
42#include <array>
43#include <map>
44#include <memory>
Austin Schuh3de38b02024-06-25 18:25:10 -070045#include <unordered_map>
Austin Schuh70cc9552019-01-21 19:46:48 -080046#include <unordered_set>
47#include <vector>
48
49#include "ceres/context_impl.h"
Austin Schuh3de38b02024-06-25 18:25:10 -070050#include "ceres/internal/disable_warnings.h"
51#include "ceres/internal/export.h"
Austin Schuh70cc9552019-01-21 19:46:48 -080052#include "ceres/internal/port.h"
Austin Schuh3de38b02024-06-25 18:25:10 -070053#include "ceres/manifold.h"
Austin Schuh70cc9552019-01-21 19:46:48 -080054#include "ceres/problem.h"
55#include "ceres/types.h"
56
57namespace ceres {
58
59class CostFunction;
Austin Schuh1d1e6ea2020-12-23 21:56:30 -080060class EvaluationCallback;
Austin Schuh70cc9552019-01-21 19:46:48 -080061class LossFunction;
Austin Schuh70cc9552019-01-21 19:46:48 -080062struct CRSMatrix;
63
64namespace internal {
65
66class Program;
67class ResidualBlock;
68
Austin Schuh3de38b02024-06-25 18:25:10 -070069class CERES_NO_EXPORT ProblemImpl {
Austin Schuh70cc9552019-01-21 19:46:48 -080070 public:
Austin Schuh3de38b02024-06-25 18:25:10 -070071 using ParameterMap = std::map<double*, ParameterBlock*>;
72 using ResidualBlockSet = std::unordered_set<ResidualBlock*>;
73 using CostFunctionRefCount = std::map<CostFunction*, int>;
74 using LossFunctionRefCount = std::map<LossFunction*, int>;
Austin Schuh70cc9552019-01-21 19:46:48 -080075
76 ProblemImpl();
77 explicit ProblemImpl(const Problem::Options& options);
78 ProblemImpl(const ProblemImpl&) = delete;
79 void operator=(const ProblemImpl&) = delete;
80
81 ~ProblemImpl();
82
83 // See the public problem.h file for description of these methods.
Austin Schuh1d1e6ea2020-12-23 21:56:30 -080084 ResidualBlockId AddResidualBlock(CostFunction* cost_function,
85 LossFunction* loss_function,
86 double* const* const parameter_blocks,
87 int num_parameter_blocks);
Austin Schuh70cc9552019-01-21 19:46:48 -080088
89 template <typename... Ts>
90 ResidualBlockId AddResidualBlock(CostFunction* cost_function,
91 LossFunction* loss_function,
92 double* x0,
93 Ts*... xs) {
94 const std::array<double*, sizeof...(Ts) + 1> parameter_blocks{{x0, xs...}};
95 return AddResidualBlock(cost_function,
96 loss_function,
97 parameter_blocks.data(),
98 static_cast<int>(parameter_blocks.size()));
99 }
100
101 void AddParameterBlock(double* values, int size);
Austin Schuh3de38b02024-06-25 18:25:10 -0700102 void AddParameterBlock(double* values, int size, Manifold* manifold);
Austin Schuh70cc9552019-01-21 19:46:48 -0800103
104 void RemoveResidualBlock(ResidualBlock* residual_block);
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800105 void RemoveParameterBlock(const double* values);
Austin Schuh70cc9552019-01-21 19:46:48 -0800106
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800107 void SetParameterBlockConstant(const double* values);
Austin Schuh70cc9552019-01-21 19:46:48 -0800108 void SetParameterBlockVariable(double* values);
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800109 bool IsParameterBlockConstant(const double* values) const;
Austin Schuh70cc9552019-01-21 19:46:48 -0800110
Austin Schuh3de38b02024-06-25 18:25:10 -0700111 void SetManifold(double* values, Manifold* manifold);
112 const Manifold* GetManifold(const double* values) const;
113 bool HasManifold(const double* values) const;
Austin Schuh70cc9552019-01-21 19:46:48 -0800114
115 void SetParameterLowerBound(double* values, int index, double lower_bound);
116 void SetParameterUpperBound(double* values, int index, double upper_bound);
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800117 double GetParameterLowerBound(const double* values, int index) const;
118 double GetParameterUpperBound(const double* values, int index) const;
Austin Schuh70cc9552019-01-21 19:46:48 -0800119
120 bool Evaluate(const Problem::EvaluateOptions& options,
121 double* cost,
122 std::vector<double>* residuals,
123 std::vector<double>* gradient,
124 CRSMatrix* jacobian);
125
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800126 bool EvaluateResidualBlock(ResidualBlock* residual_block,
127 bool apply_loss_function,
128 bool new_point,
129 double* cost,
130 double* residuals,
131 double** jacobians) const;
132
Austin Schuh70cc9552019-01-21 19:46:48 -0800133 int NumParameterBlocks() const;
134 int NumParameters() const;
135 int NumResidualBlocks() const;
136 int NumResiduals() const;
137
Austin Schuh3de38b02024-06-25 18:25:10 -0700138 int ParameterBlockSize(const double* values) const;
139 int ParameterBlockTangentSize(const double* values) const;
Austin Schuh70cc9552019-01-21 19:46:48 -0800140
Austin Schuh3de38b02024-06-25 18:25:10 -0700141 bool HasParameterBlock(const double* values) const;
Austin Schuh70cc9552019-01-21 19:46:48 -0800142
143 void GetParameterBlocks(std::vector<double*>* parameter_blocks) const;
144 void GetResidualBlocks(std::vector<ResidualBlockId>* residual_blocks) const;
145
146 void GetParameterBlocksForResidualBlock(
147 const ResidualBlockId residual_block,
148 std::vector<double*>* parameter_blocks) const;
149
150 const CostFunction* GetCostFunctionForResidualBlock(
151 const ResidualBlockId residual_block) const;
152 const LossFunction* GetLossFunctionForResidualBlock(
153 const ResidualBlockId residual_block) const;
154
155 void GetResidualBlocksForParameterBlock(
156 const double* values,
157 std::vector<ResidualBlockId>* residual_blocks) const;
158
159 const Program& program() const { return *program_; }
160 Program* mutable_program() { return program_.get(); }
161
162 const ParameterMap& parameter_map() const { return parameter_block_map_; }
163 const ResidualBlockSet& residual_block_set() const {
164 CHECK(options_.enable_fast_removal)
165 << "Fast removal not enabled, residual_block_set is not maintained.";
166 return residual_block_set_;
167 }
168
Austin Schuh3de38b02024-06-25 18:25:10 -0700169 const Problem::Options& options() const { return options_; }
170
Austin Schuh70cc9552019-01-21 19:46:48 -0800171 ContextImpl* context() { return context_impl_; }
172
173 private:
174 ParameterBlock* InternalAddParameterBlock(double* values, int size);
Austin Schuh3de38b02024-06-25 18:25:10 -0700175 void InternalSetManifold(double* values,
176 ParameterBlock* parameter_block,
177 Manifold* manifold);
178
Austin Schuh70cc9552019-01-21 19:46:48 -0800179 void InternalRemoveResidualBlock(ResidualBlock* residual_block);
180
181 // Delete the arguments in question. These differ from the Remove* functions
182 // in that they do not clean up references to the block to delete; they
183 // merely delete them.
184 template <typename Block>
185 void DeleteBlockInVector(std::vector<Block*>* mutable_blocks,
186 Block* block_to_remove);
187 void DeleteBlock(ResidualBlock* residual_block);
188 void DeleteBlock(ParameterBlock* parameter_block);
189
190 const Problem::Options options_;
191
192 bool context_impl_owned_;
193 ContextImpl* context_impl_;
194
195 // The mapping from user pointers to parameter blocks.
196 ParameterMap parameter_block_map_;
197
198 // Iff enable_fast_removal is enabled, contains the current residual blocks.
199 ResidualBlockSet residual_block_set_;
200
201 // The actual parameter and residual blocks.
202 std::unique_ptr<internal::Program> program_;
203
Austin Schuh3de38b02024-06-25 18:25:10 -0700204 // TODO(sameeragarwal): Unify the shared object handling across object types.
205 // Right now we are using vectors for Manifold objects and reference counting
206 // for CostFunctions and LossFunctions. Ideally this should be done uniformly.
207
208 // When removing parameter blocks, manifolds have ambiguous
Austin Schuh70cc9552019-01-21 19:46:48 -0800209 // ownership. Instead of scanning the entire problem to see if the
Austin Schuh3de38b02024-06-25 18:25:10 -0700210 // manifold is shared with other parameter blocks, buffer
Austin Schuh70cc9552019-01-21 19:46:48 -0800211 // them until destruction.
Austin Schuh3de38b02024-06-25 18:25:10 -0700212 std::vector<Manifold*> manifolds_to_delete_;
Austin Schuh70cc9552019-01-21 19:46:48 -0800213
214 // For each cost function and loss function in the problem, a count
215 // of the number of residual blocks that refer to them. When the
216 // count goes to zero and the problem owns these objects, they are
217 // destroyed.
218 CostFunctionRefCount cost_function_ref_count_;
219 LossFunctionRefCount loss_function_ref_count_;
220};
221
222} // namespace internal
223} // namespace ceres
224
Austin Schuh3de38b02024-06-25 18:25:10 -0700225#include "ceres/internal/reenable_warnings.h"
226
Austin Schuh70cc9552019-01-21 19:46:48 -0800227#endif // CERES_PUBLIC_PROBLEM_IMPL_H_