1 // Ceres Solver - A fast non-linear least squares minimizer
2 // Copyright 2010, 2011, 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: keir@google.com (Keir Mierle)
30 //         sameeragarwal@google.com (Sameer Agarwal)
31 //
32 // Create CostFunctions as needed by the least squares framework with jacobians
33 // computed via numeric (a.k.a. finite) differentiation. For more details see
34 // http://en.wikipedia.org/wiki/Numerical_differentiation.
35 //
36 // To get an numerically differentiated cost function, you must define
37 // a class with a operator() (a functor) that computes the residuals.
38 //
39 // The function must write the computed value in the last argument
40 // (the only non-const one) and return true to indicate success.
41 // Please see cost_function.h for details on how the return value
42 // maybe used to impose simple constraints on the parameter block.
43 //
44 // For example, consider a scalar error e = k - x'y, where both x and y are
45 // two-dimensional column vector parameters, the prime sign indicates
46 // transposition, and k is a constant. The form of this error, which is the
47 // difference between a constant and an expression, is a common pattern in least
48 // squares problems. For example, the value x'y might be the model expectation
49 // for a series of measurements, where there is an instance of the cost function
50 // for each measurement k.
51 //
52 // The actual cost added to the total problem is e^2, or (k - x'k)^2; however,
53 // the squaring is implicitly done by the optimization framework.
54 //
55 // To write an numerically-differentiable cost function for the above model, first
56 // define the object
57 //
58 //   class MyScalarCostFunctor {
59 //     MyScalarCostFunctor(double k): k_(k) {}
60 //
61 //     bool operator()(const double* const x,
62 //                     const double* const y,
63 //                     double* residuals) const {
64 //       residuals[0] = k_ - x[0] * y[0] + x[1] * y[1];
65 //       return true;
66 //     }
67 //
68 //    private:
69 //     double k_;
70 //   };
71 //
72 // Note that in the declaration of operator() the input parameters x
73 // and y come first, and are passed as const pointers to arrays of
74 // doubles. If there were three input parameters, then the third input
75 // parameter would come after y. The output is always the last
76 // parameter, and is also a pointer to an array. In the example above,
77 // the residual is a scalar, so only residuals[0] is set.
78 //
79 // Then given this class definition, the numerically differentiated
80 // cost function with central differences used for computing the
81 // derivative can be constructed as follows.
82 //
83 //   CostFunction* cost_function
84 //       = new NumericDiffCostFunction<MyScalarCostFunctor, CENTRAL, 1, 2, 2>(
85 //           new MyScalarCostFunctor(1.0));                    ^     ^  ^  ^
86 //                                                             |     |  |  |
87 //                                 Finite Differencing Scheme -+     |  |  |
88 //                                 Dimension of residual ------------+  |  |
89 //                                 Dimension of x ----------------------+  |
90 //                                 Dimension of y -------------------------+
91 //
92 // In this example, there is usually an instance for each measurement of k.
93 //
94 // In the instantiation above, the template parameters following
95 // "MyScalarCostFunctor", "1, 2, 2", describe the functor as computing
96 // a 1-dimensional output from two arguments, both 2-dimensional.
97 //
98 // NumericDiffCostFunction also supports cost functions with a
99 // runtime-determined number of residuals. For example:
100 //
101 //   CostFunction* cost_function
102 //       = new NumericDiffCostFunction<MyScalarCostFunctor, CENTRAL, DYNAMIC, 2, 2>(
103 //           new CostFunctorWithDynamicNumResiduals(1.0),               ^     ^  ^
104 //           TAKE_OWNERSHIP,                                            |     |  |
105 //           runtime_number_of_residuals); <----+                       |     |  |
106 //                                              |                       |     |  |
107 //                                              |                       |     |  |
108 //             Actual number of residuals ------+                       |     |  |
109 //             Indicate dynamic number of residuals --------------------+     |  |
110 //             Dimension of x ------------------------------------------------+  |
111 //             Dimension of y ---------------------------------------------------+
112 //
113 // The framework can currently accommodate cost functions of up to 10
114 // independent variables, and there is no limit on the dimensionality
115 // of each of them.
116 //
117 // The central difference method is considerably more accurate at the cost of
118 // twice as many function evaluations than forward difference. Consider using
119 // central differences begin with, and only after that works, trying forward
120 // difference to improve performance.
121 //
122 // WARNING #1: A common beginner's error when first using
123 // NumericDiffCostFunction is to get the sizing wrong. In particular,
124 // there is a tendency to set the template parameters to (dimension of
125 // residual, number of parameters) instead of passing a dimension
126 // parameter for *every parameter*. In the example above, that would
127 // be <MyScalarCostFunctor, 1, 2>, which is missing the last '2'
128 // argument. Please be careful when setting the size parameters.
129 //
130 ////////////////////////////////////////////////////////////////////////////
131 ////////////////////////////////////////////////////////////////////////////
132 //
133 // ALTERNATE INTERFACE
134 //
135 // For a variety of reason, including compatibility with legacy code,
136 // NumericDiffCostFunction can also take CostFunction objects as
137 // input. The following describes how.
138 //
139 // To get a numerically differentiated cost function, define a
140 // subclass of CostFunction such that the Evaluate() function ignores
141 // the jacobian parameter. The numeric differentiation wrapper will
142 // fill in the jacobian parameter if necessary by repeatedly calling
143 // the Evaluate() function with small changes to the appropriate
144 // parameters, and computing the slope. For performance, the numeric
145 // differentiation wrapper class is templated on the concrete cost
146 // function, even though it could be implemented only in terms of the
147 // virtual CostFunction interface.
148 //
149 // The numerically differentiated version of a cost function for a cost function
150 // can be constructed as follows:
151 //
152 //   CostFunction* cost_function
153 //       = new NumericDiffCostFunction<MyCostFunction, CENTRAL, 1, 4, 8>(
154 //           new MyCostFunction(...), TAKE_OWNERSHIP);
155 //
156 // where MyCostFunction has 1 residual and 2 parameter blocks with sizes 4 and 8
157 // respectively. Look at the tests for a more detailed example.
158 //
159 // TODO(keir): Characterize accuracy; mention pitfalls; provide alternatives.
160 
161 #ifndef CERES_PUBLIC_NUMERIC_DIFF_COST_FUNCTION_H_
162 #define CERES_PUBLIC_NUMERIC_DIFF_COST_FUNCTION_H_
163 
164 #include "Eigen/Dense"
165 #include "ceres/cost_function.h"
166 #include "ceres/internal/numeric_diff.h"
167 #include "ceres/internal/scoped_ptr.h"
168 #include "ceres/sized_cost_function.h"
169 #include "ceres/types.h"
170 #include "glog/logging.h"
171 
172 namespace ceres {
173 
174 template <typename CostFunctor,
175           NumericDiffMethod method = CENTRAL,
176           int kNumResiduals = 0,  // Number of residuals, or ceres::DYNAMIC
177           int N0 = 0,   // Number of parameters in block 0.
178           int N1 = 0,   // Number of parameters in block 1.
179           int N2 = 0,   // Number of parameters in block 2.
180           int N3 = 0,   // Number of parameters in block 3.
181           int N4 = 0,   // Number of parameters in block 4.
182           int N5 = 0,   // Number of parameters in block 5.
183           int N6 = 0,   // Number of parameters in block 6.
184           int N7 = 0,   // Number of parameters in block 7.
185           int N8 = 0,   // Number of parameters in block 8.
186           int N9 = 0>   // Number of parameters in block 9.
187 class NumericDiffCostFunction
188     : public SizedCostFunction<kNumResiduals,
189                                N0, N1, N2, N3, N4,
190                                N5, N6, N7, N8, N9> {
191  public:
192   NumericDiffCostFunction(CostFunctor* functor,
193                           Ownership ownership = TAKE_OWNERSHIP,
194                           int num_residuals = kNumResiduals,
195                           const double relative_step_size = 1e-6)
functor_(functor)196       :functor_(functor),
197        ownership_(ownership),
198        relative_step_size_(relative_step_size) {
199     if (kNumResiduals == DYNAMIC) {
200       SizedCostFunction<kNumResiduals,
201                         N0, N1, N2, N3, N4,
202                         N5, N6, N7, N8, N9>
203           ::set_num_residuals(num_residuals);
204     }
205   }
206 
~NumericDiffCostFunction()207   ~NumericDiffCostFunction() {
208     if (ownership_ != TAKE_OWNERSHIP) {
209       functor_.release();
210     }
211   }
212 
Evaluate(double const * const * parameters,double * residuals,double ** jacobians)213   virtual bool Evaluate(double const* const* parameters,
214                         double* residuals,
215                         double** jacobians) const {
216     using internal::FixedArray;
217     using internal::NumericDiff;
218 
219     const int kNumParameters = N0 + N1 + N2 + N3 + N4 + N5 + N6 + N7 + N8 + N9;
220     const int kNumParameterBlocks =
221         (N0 > 0) + (N1 > 0) + (N2 > 0) + (N3 > 0) + (N4 > 0) +
222         (N5 > 0) + (N6 > 0) + (N7 > 0) + (N8 > 0) + (N9 > 0);
223 
224     // Get the function value (residuals) at the the point to evaluate.
225     if (!internal::EvaluateImpl<CostFunctor,
226                                 N0, N1, N2, N3, N4, N5, N6, N7, N8, N9>(
227                                     functor_.get(),
228                                     parameters,
229                                     residuals,
230                                     functor_.get())) {
231       return false;
232     }
233 
234     if (jacobians == NULL) {
235       return true;
236     }
237 
238     // Create a copy of the parameters which will get mutated.
239     FixedArray<double> parameters_copy(kNumParameters);
240     FixedArray<double*> parameters_reference_copy(kNumParameterBlocks);
241 
242     parameters_reference_copy[0] = parameters_copy.get();
243     if (N1) parameters_reference_copy[1] = parameters_reference_copy[0] + N0;
244     if (N2) parameters_reference_copy[2] = parameters_reference_copy[1] + N1;
245     if (N3) parameters_reference_copy[3] = parameters_reference_copy[2] + N2;
246     if (N4) parameters_reference_copy[4] = parameters_reference_copy[3] + N3;
247     if (N5) parameters_reference_copy[5] = parameters_reference_copy[4] + N4;
248     if (N6) parameters_reference_copy[6] = parameters_reference_copy[5] + N5;
249     if (N7) parameters_reference_copy[7] = parameters_reference_copy[6] + N6;
250     if (N8) parameters_reference_copy[8] = parameters_reference_copy[7] + N7;
251     if (N9) parameters_reference_copy[9] = parameters_reference_copy[8] + N8;
252 
253 #define COPY_PARAMETER_BLOCK(block)                                     \
254   if (N ## block) memcpy(parameters_reference_copy[block],              \
255                          parameters[block],                             \
256                          sizeof(double) * N ## block);  // NOLINT
257 
258     COPY_PARAMETER_BLOCK(0);
259     COPY_PARAMETER_BLOCK(1);
260     COPY_PARAMETER_BLOCK(2);
261     COPY_PARAMETER_BLOCK(3);
262     COPY_PARAMETER_BLOCK(4);
263     COPY_PARAMETER_BLOCK(5);
264     COPY_PARAMETER_BLOCK(6);
265     COPY_PARAMETER_BLOCK(7);
266     COPY_PARAMETER_BLOCK(8);
267     COPY_PARAMETER_BLOCK(9);
268 
269 #undef COPY_PARAMETER_BLOCK
270 
271 #define EVALUATE_JACOBIAN_FOR_BLOCK(block)                              \
272     if (N ## block && jacobians[block] != NULL) {                       \
273       if (!NumericDiff<CostFunctor,                                     \
274                        method,                                          \
275                        kNumResiduals,                                   \
276                        N0, N1, N2, N3, N4, N5, N6, N7, N8, N9,          \
277                        block,                                           \
278                        N ## block >::EvaluateJacobianForParameterBlock( \
279                            functor_.get(),                              \
280                            residuals,                                   \
281                            relative_step_size_,                         \
282                           SizedCostFunction<kNumResiduals,              \
283                            N0, N1, N2, N3, N4,                          \
284                            N5, N6, N7, N8, N9>::num_residuals(),        \
285                            parameters_reference_copy.get(),             \
286                            jacobians[block])) {                         \
287         return false;                                                   \
288       }                                                                 \
289     }
290 
291     EVALUATE_JACOBIAN_FOR_BLOCK(0);
292     EVALUATE_JACOBIAN_FOR_BLOCK(1);
293     EVALUATE_JACOBIAN_FOR_BLOCK(2);
294     EVALUATE_JACOBIAN_FOR_BLOCK(3);
295     EVALUATE_JACOBIAN_FOR_BLOCK(4);
296     EVALUATE_JACOBIAN_FOR_BLOCK(5);
297     EVALUATE_JACOBIAN_FOR_BLOCK(6);
298     EVALUATE_JACOBIAN_FOR_BLOCK(7);
299     EVALUATE_JACOBIAN_FOR_BLOCK(8);
300     EVALUATE_JACOBIAN_FOR_BLOCK(9);
301 
302 #undef EVALUATE_JACOBIAN_FOR_BLOCK
303 
304     return true;
305   }
306 
307  private:
308   internal::scoped_ptr<CostFunctor> functor_;
309   Ownership ownership_;
310   const double relative_step_size_;
311 };
312 
313 }  // namespace ceres
314 
315 #endif  // CERES_PUBLIC_NUMERIC_DIFF_COST_FUNCTION_H_
316