blob: e4549c54b433c2c54a3526492e9819e4308a6b20 [file] [log] [blame]
Keir Mierle3130b3c2013-02-11 19:39:29 -08001// Ceres Solver - A fast non-linear least squares minimizer
2// Copyright 2012 Google Inc. All rights reserved.
3// http://code.google.com/p/ceres-solver/
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: mierle@gmail.com (Keir Mierle)
30// sameeragarwal@google.com (Sameer Agarwal)
31// thadh@gmail.com (Thad Hughes)
32//
33// This autodiff implementation differs from the one found in
34// autodiff_cost_function.h by supporting autodiff on cost functions with
35// variable numbers of parameters with variable sizes. With the other
36// implementation, all the sizes (both the number of parameter blocks and the
37// size of each block) must be fixed at compile time.
38//
39// The functor API differs slightly from the API for fixed size autodiff; the
40// expected interface for the cost functors is:
41//
42// struct MyCostFunctor {
43// template<typename T>
Sameer Agarwalefb47f32013-02-14 19:44:11 -080044// bool operator()(T const* const* parameters, T* residuals) const {
Keir Mierle3130b3c2013-02-11 19:39:29 -080045// // Use parameters[i] to access the i'th parameter block.
46// }
47// }
48//
49// Since the sizing of the parameters is done at runtime, you must also specify
50// the sizes after creating the dynamic autodiff cost function. For example:
51//
52// DynamicAutoDiffCostFunction<MyCostFunctor, 3> cost_function(
53// new MyCostFunctor());
54// cost_function.AddParameterBlock(5);
55// cost_function.AddParameterBlock(10);
56// cost_function.SetNumResiduals(21);
57//
58// Under the hood, the implementation evaluates the cost function multiple
59// times, computing a small set of the derivatives (four by default, controlled
60// by the Stride template parameter) with each pass. There is a tradeoff with
61// the size of the passes; you may want to experiment with the stride.
62
63#ifndef CERES_PUBLIC_DYNAMIC_AUTODIFF_COST_FUNCTION_H_
64#define CERES_PUBLIC_DYNAMIC_AUTODIFF_COST_FUNCTION_H_
65
66#include <cmath>
67#include <numeric>
Sameer Agarwal509f68c2013-02-20 01:39:03 -080068#include <vector>
69
Keir Mierle3130b3c2013-02-11 19:39:29 -080070#include "ceres/cost_function.h"
71#include "ceres/internal/scoped_ptr.h"
72#include "ceres/jet.h"
Sameer Agarwal509f68c2013-02-20 01:39:03 -080073#include "glog/logging.h"
Keir Mierle3130b3c2013-02-11 19:39:29 -080074
75namespace ceres {
76
77template <typename CostFunctor, int Stride = 4>
78class DynamicAutoDiffCostFunction : public CostFunction {
79 public:
Sameer Agarwal509f68c2013-02-20 01:39:03 -080080 explicit DynamicAutoDiffCostFunction(CostFunctor* functor)
Sameer Agarwal931c3092013-02-25 09:46:21 -080081 : functor_(functor) {}
Keir Mierle3130b3c2013-02-11 19:39:29 -080082
83 virtual ~DynamicAutoDiffCostFunction() {}
84
85 void AddParameterBlock(int size) {
86 mutable_parameter_block_sizes()->push_back(size);
87 }
88
89 void SetNumResiduals(int num_residuals) {
90 set_num_residuals(num_residuals);
91 }
92
93 virtual bool Evaluate(double const* const* parameters,
94 double* residuals,
95 double** jacobians) const {
96 CHECK_GT(num_residuals(), 0)
97 << "You must call DynamicAutoDiffCostFunction::SetNumResiduals() "
98 << "before DynamicAutoDiffCostFunction::Evaluate().";
99
100 if (jacobians == NULL) {
101 return (*functor_)(parameters, residuals);
102 }
103
104 // The difficulty with Jets, as implemented in Ceres, is that they were
105 // originally designed for strictly compile-sized use. At this point, there
106 // is a large body of code that assumes inside a cost functor it is
107 // acceptable to do e.g. T(1.5) and get an appropriately sized jet back.
108 //
109 // Unfortunately, it is impossible to communicate the expected size of a
110 // dynamically sized jet to the static instantiations that existing code
111 // depends on.
112 //
113 // To work around this issue, the solution here is to evaluate the
114 // jacobians in a series of passes, each one computing Stripe *
115 // num_residuals() derivatives. This is done with small, fixed-size jets.
116 const int num_parameter_blocks = parameter_block_sizes().size();
117 const int num_parameters = std::accumulate(parameter_block_sizes().begin(),
118 parameter_block_sizes().end(),
119 0);
120
121 // Allocate scratch space for the strided evaluation.
122 vector<Jet<double, Stride> > input_jets(num_parameters);
123 vector<Jet<double, Stride> > output_jets(num_residuals());
124
125 // Make the parameter pack that is sent to the functor (reused).
Sameer Agarwal974513a2013-02-12 14:22:40 -0800126 vector<Jet<double, Stride>* > jet_parameters(num_parameter_blocks, NULL);
127 int num_active_parameters = 0;
128 int start_derivative_section = -1;
Keir Mierle3130b3c2013-02-11 19:39:29 -0800129 for (int i = 0, parameter_cursor = 0; i < num_parameter_blocks; ++i) {
130 jet_parameters[i] = &input_jets[parameter_cursor];
Sameer Agarwal974513a2013-02-12 14:22:40 -0800131
132 const int parameter_block_size = parameter_block_sizes()[i];
133 if (jacobians[i] != NULL) {
134 start_derivative_section =
135 (start_derivative_section == -1)
136 ? parameter_cursor
137 : start_derivative_section;
138 num_active_parameters += parameter_block_size;
139 }
140
141 for (int j = 0; j < parameter_block_size; ++j, parameter_cursor++) {
Keir Mierle3130b3c2013-02-11 19:39:29 -0800142 input_jets[parameter_cursor].a = parameters[i][j];
143 }
144 }
145
146 // Evaluate all of the strides. Each stride is a chunk of the derivative to
147 // evaluate, typically some size proportional to the size of the SIMD
148 // registers of the CPU.
Sameer Agarwal509f68c2013-02-20 01:39:03 -0800149 int num_strides = static_cast<int>(ceil(num_active_parameters /
150 static_cast<float>(Stride)));
151
Keir Mierle3130b3c2013-02-11 19:39:29 -0800152 for (int pass = 0; pass < num_strides; ++pass) {
Sameer Agarwal974513a2013-02-12 14:22:40 -0800153 // Set most of the jet components to zero, except for
154 // non-constant #Stride parameters.
155 int active_parameter_count = 0;
156 int end_derivative_section = start_derivative_section;
Keir Mierle3130b3c2013-02-11 19:39:29 -0800157 for (int i = 0, parameter_cursor = 0; i < num_parameter_blocks; ++i) {
158 for (int j = 0; j < parameter_block_sizes()[i];
159 ++j, parameter_cursor++) {
160 input_jets[parameter_cursor].v.setZero();
161 if (parameter_cursor >= start_derivative_section &&
Sameer Agarwal974513a2013-02-12 14:22:40 -0800162 active_parameter_count < Stride) {
163 if (jacobians[i] != NULL) {
164 input_jets[parameter_cursor]
165 .v[parameter_cursor - start_derivative_section] = 1.0;
166 ++active_parameter_count;
167 }
168 ++end_derivative_section;
Keir Mierle3130b3c2013-02-11 19:39:29 -0800169 }
170 }
171 }
172
173 if (!(*functor_)(&jet_parameters[0], &output_jets[0])) {
174 return false;
175 }
176
177 // Copy the pieces of the jacobians into their final place.
Sameer Agarwal974513a2013-02-12 14:22:40 -0800178 active_parameter_count = 0;
Keir Mierle3130b3c2013-02-11 19:39:29 -0800179 for (int i = 0, parameter_cursor = 0; i < num_parameter_blocks; ++i) {
180 for (int j = 0; j < parameter_block_sizes()[i];
181 ++j, parameter_cursor++) {
182 if (parameter_cursor >= start_derivative_section &&
Sameer Agarwal974513a2013-02-12 14:22:40 -0800183 active_parameter_count < Stride) {
184 if (jacobians[i] != NULL) {
185 for (int k = 0; k < num_residuals(); ++k) {
186 jacobians[i][k * parameter_block_sizes()[i] + j] =
Sameer Agarwal509f68c2013-02-20 01:39:03 -0800187 output_jets[k].v[parameter_cursor -
188 start_derivative_section];
Sameer Agarwal974513a2013-02-12 14:22:40 -0800189 }
190 ++active_parameter_count;
Keir Mierle3130b3c2013-02-11 19:39:29 -0800191 }
192 }
193 }
194 }
195
196 // Only copy the residuals over once (even though we compute them on
197 // every loop).
198 if (pass == num_strides - 1) {
199 for (int k = 0; k < num_residuals(); ++k) {
200 residuals[k] = output_jets[k].a;
201 }
202 }
Sameer Agarwal974513a2013-02-12 14:22:40 -0800203
204 start_derivative_section = end_derivative_section;
Keir Mierle3130b3c2013-02-11 19:39:29 -0800205 }
206 return true;
207 }
208
209 private:
210 internal::scoped_ptr<CostFunctor> functor_;
211};
212
213} // namespace ceres
214
215#endif // CERES_PUBLIC_DYNAMIC_AUTODIFF_COST_FUNCTION_H_