blob: 5f478758af2fb11fa13540764a4ccc2560e2346a [file] [log] [blame]
David Gossow2a1dfd22015-06-16 14:10:56 -07001// Ceres Solver - A fast non-linear least squares minimizer
Sameer Agarwal4362a212019-12-02 13:52:31 -08002// Copyright 2019 Google Inc. All rights reserved.
David Gossow2a1dfd22015-06-16 14:10:56 -07003// 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// dgossow@google.com (David Gossow)
Sameer Agarwal78abf0c2016-10-27 21:15:15 -070031
32#ifndef CERES_PUBLIC_DYNAMIC_COST_FUNCTION_TO_FUNCTOR_H_
33#define CERES_PUBLIC_DYNAMIC_COST_FUNCTION_TO_FUNCTOR_H_
34
Keir Mierle7c4e8a42018-03-30 16:16:59 -070035#include <memory>
Sameer Agarwal78abf0c2016-10-27 21:15:15 -070036#include <numeric>
37#include <vector>
38
39#include "ceres/dynamic_cost_function.h"
40#include "ceres/internal/fixed_array.h"
41#include "ceres/internal/port.h"
Sameer Agarwal97873ea2021-01-21 13:49:38 -080042#include "glog/logging.h"
Sameer Agarwal78abf0c2016-10-27 21:15:15 -070043
44namespace ceres {
45
David Gossow2a1dfd22015-06-16 14:10:56 -070046// DynamicCostFunctionToFunctor allows users to use CostFunction
47// objects in templated functors which are to be used for automatic
48// differentiation. It works similar to CostFunctionToFunctor, with the
49// difference that it allows you to wrap a cost function with dynamic numbers
50// of parameters and residuals.
51//
52// For example, let us assume that
53//
54// class IntrinsicProjection : public CostFunction {
55// public:
56// IntrinsicProjection(const double* observation);
Sameer Agarwale4577dd2019-07-13 11:19:27 +020057// bool Evaluate(double const* const* parameters,
58// double* residuals,
59// double** jacobians) const override;
David Gossow2a1dfd22015-06-16 14:10:56 -070060// };
61//
62// is a cost function that implements the projection of a point in its
63// local coordinate system onto its image plane and subtracts it from
64// the observed point projection. It can compute its residual and
65// either via analytic or numerical differentiation can compute its
66// jacobians. The intrinsics are passed in as parameters[0] and the point as
67// parameters[1].
68//
69// Now we would like to compose the action of this CostFunction with
70// the action of camera extrinsics, i.e., rotation and
71// translation. Say we have a templated function
72//
73// template<typename T>
74// void RotateAndTranslatePoint(double const* const* parameters,
75// double* residuals);
76//
77// Then we can now do the following,
78//
79// struct CameraProjection {
80// CameraProjection(const double* observation)
81// : intrinsic_projection_.(new IntrinsicProjection(observation)) {
82// }
83// template <typename T>
84// bool operator()(T const* const* parameters,
85// T* residual) const {
86// const T* rotation = parameters[0];
87// const T* translation = parameters[1];
88// const T* intrinsics = parameters[2];
89// const T* point = parameters[3];
90// T transformed_point[3];
91// RotateAndTranslatePoint(rotation, translation, point, transformed_point);
92//
93// // Note that we call intrinsic_projection_, just like it was
94// // any other templated functor.
95// const T* projection_parameters[2];
96// projection_parameters[0] = intrinsics;
97// projection_parameters[1] = transformed_point;
98// return intrinsic_projection_(projection_parameters, residual);
99// }
100//
101// private:
102// DynamicCostFunctionToFunctor intrinsic_projection_;
103// };
David Gossow2a1dfd22015-06-16 14:10:56 -0700104class DynamicCostFunctionToFunctor {
105 public:
106 // Takes ownership of cost_function.
107 explicit DynamicCostFunctionToFunctor(CostFunction* cost_function)
108 : cost_function_(cost_function) {
Sameer Agarwal94712db2018-08-27 07:12:43 -0700109 CHECK(cost_function != nullptr);
David Gossow2a1dfd22015-06-16 14:10:56 -0700110 }
111
112 bool operator()(double const* const* parameters, double* residuals) const {
113 return cost_function_->Evaluate(parameters, residuals, NULL);
114 }
115
116 template <typename JetT>
117 bool operator()(JetT const* const* inputs, JetT* output) const {
Sameer Agarwale82e1282018-08-08 04:27:24 -0700118 const std::vector<int32_t>& parameter_block_sizes =
David Gossow2a1dfd22015-06-16 14:10:56 -0700119 cost_function_->parameter_block_sizes();
Sameer Agarwal39388bd2017-05-09 17:23:43 -0700120 const int num_parameter_blocks =
121 static_cast<int>(parameter_block_sizes.size());
David Gossow2a1dfd22015-06-16 14:10:56 -0700122 const int num_residuals = cost_function_->num_residuals();
Sameer Agarwal4362a212019-12-02 13:52:31 -0800123 const int num_parameters = std::accumulate(
124 parameter_block_sizes.begin(), parameter_block_sizes.end(), 0);
David Gossow2a1dfd22015-06-16 14:10:56 -0700125
126 internal::FixedArray<double> parameters(num_parameters);
127 internal::FixedArray<double*> parameter_blocks(num_parameter_blocks);
128 internal::FixedArray<double> jacobians(num_residuals * num_parameters);
129 internal::FixedArray<double*> jacobian_blocks(num_parameter_blocks);
130 internal::FixedArray<double> residuals(num_residuals);
131
132 // Build a set of arrays to get the residuals and jacobians from
133 // the CostFunction wrapped by this functor.
Johannes Beck25e1cdb2019-03-17 21:35:49 +0100134 double* parameter_ptr = parameters.data();
135 double* jacobian_ptr = jacobians.data();
David Gossow2a1dfd22015-06-16 14:10:56 -0700136 for (int i = 0; i < num_parameter_blocks; ++i) {
137 parameter_blocks[i] = parameter_ptr;
138 jacobian_blocks[i] = jacobian_ptr;
139 for (int j = 0; j < parameter_block_sizes[i]; ++j) {
140 *parameter_ptr++ = inputs[i][j].a;
141 }
142 jacobian_ptr += num_residuals * parameter_block_sizes[i];
143 }
144
Johannes Beck25e1cdb2019-03-17 21:35:49 +0100145 if (!cost_function_->Evaluate(parameter_blocks.data(),
146 residuals.data(),
147 jacobian_blocks.data())) {
David Gossow2a1dfd22015-06-16 14:10:56 -0700148 return false;
149 }
150
151 // Now that we have the incoming Jets, which are carrying the
152 // partial derivatives of each of the inputs w.r.t to some other
153 // underlying parameters. The derivative of the outputs of the
154 // cost function w.r.t to the same underlying parameters can now
155 // be computed by applying the chain rule.
156 //
157 // d output[i] d output[i] d input[j]
158 // -------------- = sum_j ----------- * ------------
159 // d parameter[k] d input[j] d parameter[k]
160 //
161 // d input[j]
162 // -------------- = inputs[j], so
163 // d parameter[k]
164 //
165 // outputJet[i] = sum_k jacobian[i][k] * inputJet[k]
166 //
167 // The following loop, iterates over the residuals, computing one
168 // output jet at a time.
169 for (int i = 0; i < num_residuals; ++i) {
170 output[i].a = residuals[i];
171 output[i].v.setZero();
172
173 for (int j = 0; j < num_parameter_blocks; ++j) {
Sameer Agarwale82e1282018-08-08 04:27:24 -0700174 const int32_t block_size = parameter_block_sizes[j];
David Gossow2a1dfd22015-06-16 14:10:56 -0700175 for (int k = 0; k < parameter_block_sizes[j]; ++k) {
176 output[i].v +=
177 jacobian_blocks[j][i * block_size + k] * inputs[j][k].v;
178 }
179 }
180 }
181
182 return true;
183 }
184
185 private:
Keir Mierle7c4e8a42018-03-30 16:16:59 -0700186 std::unique_ptr<CostFunction> cost_function_;
David Gossow2a1dfd22015-06-16 14:10:56 -0700187};
188
189} // namespace ceres
190
191#endif // CERES_PUBLIC_DYNAMIC_COST_FUNCTION_TO_FUNCTOR_H_