1 // Ceres Solver - A fast non-linear least squares minimizer
2 // Copyright 2015 Google Inc. All rights reserved.
3 // http://ceres-solver.org/
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are met:
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.
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.
29 // Author: keir@google.com (Keir Mierle)
30 // tbennun@gmail.com (Tal Ben-Nun)
32 #include "ceres/numeric_diff_cost_function.h"
38 #include "ceres/internal/macros.h"
39 #include "ceres/internal/scoped_ptr.h"
40 #include "ceres/array_utils.h"
41 #include "ceres/numeric_diff_test_utils.h"
42 #include "ceres/test_util.h"
43 #include "ceres/types.h"
44 #include "glog/logging.h"
45 #include "gtest/gtest.h"
50 TEST(NumericDiffCostFunction, EasyCaseFunctorCentralDifferences) {
51 internal::scoped_ptr<CostFunction> cost_function;
53 new NumericDiffCostFunction<EasyFunctor,
55 3, /* number of residuals */
60 functor.ExpectCostFunctionEvaluationIsNearlyCorrect(*cost_function, CENTRAL);
63 TEST(NumericDiffCostFunction, EasyCaseFunctorForwardDifferences) {
64 internal::scoped_ptr<CostFunction> cost_function;
66 new NumericDiffCostFunction<EasyFunctor,
68 3, /* number of residuals */
73 functor.ExpectCostFunctionEvaluationIsNearlyCorrect(*cost_function, FORWARD);
76 TEST(NumericDiffCostFunction, EasyCaseFunctorRidders) {
77 internal::scoped_ptr<CostFunction> cost_function;
79 new NumericDiffCostFunction<EasyFunctor,
81 3, /* number of residuals */
86 functor.ExpectCostFunctionEvaluationIsNearlyCorrect(*cost_function, RIDDERS);
89 TEST(NumericDiffCostFunction, EasyCaseCostFunctionCentralDifferences) {
90 internal::scoped_ptr<CostFunction> cost_function;
92 new NumericDiffCostFunction<EasyCostFunction,
94 3, /* number of residuals */
97 new EasyCostFunction, TAKE_OWNERSHIP));
99 functor.ExpectCostFunctionEvaluationIsNearlyCorrect(*cost_function, CENTRAL);
102 TEST(NumericDiffCostFunction, EasyCaseCostFunctionForwardDifferences) {
103 internal::scoped_ptr<CostFunction> cost_function;
105 new NumericDiffCostFunction<EasyCostFunction,
107 3, /* number of residuals */
110 new EasyCostFunction, TAKE_OWNERSHIP));
112 functor.ExpectCostFunctionEvaluationIsNearlyCorrect(*cost_function, FORWARD);
115 TEST(NumericDiffCostFunction, EasyCaseCostFunctionRidders) {
116 internal::scoped_ptr<CostFunction> cost_function;
118 new NumericDiffCostFunction<EasyCostFunction,
120 3, /* number of residuals */
123 new EasyCostFunction, TAKE_OWNERSHIP));
125 functor.ExpectCostFunctionEvaluationIsNearlyCorrect(*cost_function, RIDDERS);
128 TEST(NumericDiffCostFunction,
129 TranscendentalCaseFunctorCentralDifferences) {
130 internal::scoped_ptr<CostFunction> cost_function;
132 new NumericDiffCostFunction<TranscendentalFunctor,
134 2, /* number of residuals */
137 new TranscendentalFunctor));
138 TranscendentalFunctor functor;
139 functor.ExpectCostFunctionEvaluationIsNearlyCorrect(*cost_function, CENTRAL);
142 TEST(NumericDiffCostFunction,
143 TranscendentalCaseFunctorForwardDifferences) {
144 internal::scoped_ptr<CostFunction> cost_function;
146 new NumericDiffCostFunction<TranscendentalFunctor,
148 2, /* number of residuals */
151 new TranscendentalFunctor));
152 TranscendentalFunctor functor;
153 functor.ExpectCostFunctionEvaluationIsNearlyCorrect(*cost_function, FORWARD);
156 TEST(NumericDiffCostFunction,
157 TranscendentalCaseFunctorRidders) {
158 NumericDiffOptions options;
160 // Using a smaller initial step size to overcome oscillatory function
162 options.ridders_relative_initial_step_size = 1e-3;
164 internal::scoped_ptr<CostFunction> cost_function;
166 new NumericDiffCostFunction<TranscendentalFunctor,
168 2, /* number of residuals */
171 new TranscendentalFunctor, TAKE_OWNERSHIP, 2, options));
172 TranscendentalFunctor functor;
173 functor.ExpectCostFunctionEvaluationIsNearlyCorrect(*cost_function, RIDDERS);
176 TEST(NumericDiffCostFunction,
177 TranscendentalCaseCostFunctionCentralDifferences) {
178 internal::scoped_ptr<CostFunction> cost_function;
180 new NumericDiffCostFunction<TranscendentalCostFunction,
182 2, /* number of residuals */
185 new TranscendentalCostFunction, TAKE_OWNERSHIP));
186 TranscendentalFunctor functor;
187 functor.ExpectCostFunctionEvaluationIsNearlyCorrect(*cost_function, CENTRAL);
190 TEST(NumericDiffCostFunction,
191 TranscendentalCaseCostFunctionForwardDifferences) {
192 internal::scoped_ptr<CostFunction> cost_function;
194 new NumericDiffCostFunction<TranscendentalCostFunction,
196 2, /* number of residuals */
199 new TranscendentalCostFunction, TAKE_OWNERSHIP));
200 TranscendentalFunctor functor;
201 functor.ExpectCostFunctionEvaluationIsNearlyCorrect(*cost_function, FORWARD);
204 TEST(NumericDiffCostFunction,
205 TranscendentalCaseCostFunctionRidders) {
206 NumericDiffOptions options;
208 // Using a smaller initial step size to overcome oscillatory function
210 options.ridders_relative_initial_step_size = 1e-3;
212 internal::scoped_ptr<CostFunction> cost_function;
214 new NumericDiffCostFunction<TranscendentalCostFunction,
216 2, /* number of residuals */
219 new TranscendentalCostFunction, TAKE_OWNERSHIP, 2, options));
220 TranscendentalFunctor functor;
221 functor.ExpectCostFunctionEvaluationIsNearlyCorrect(*cost_function, RIDDERS);
224 template<int num_rows, int num_cols>
225 class SizeTestingCostFunction : public SizedCostFunction<num_rows, num_cols> {
227 virtual bool Evaluate(double const* const* parameters,
229 double** jacobians) const {
235 // http://forum.kde.org/viewtopic.php?f=74&t=98536#p210774
236 // Eigen3 has restrictions on the Row/Column major storage of vectors,
237 // depending on their dimensions. This test ensures that the correct
238 // templates are instantiated for various shapes of the Jacobian
240 TEST(NumericDiffCostFunction, EigenRowMajorColMajorTest) {
241 scoped_ptr<CostFunction> cost_function;
243 new NumericDiffCostFunction<SizeTestingCostFunction<1,1>, CENTRAL, 1, 1>(
244 new SizeTestingCostFunction<1,1>, ceres::TAKE_OWNERSHIP));
247 new NumericDiffCostFunction<SizeTestingCostFunction<2,1>, CENTRAL, 2, 1>(
248 new SizeTestingCostFunction<2,1>, ceres::TAKE_OWNERSHIP));
251 new NumericDiffCostFunction<SizeTestingCostFunction<1,2>, CENTRAL, 1, 2>(
252 new SizeTestingCostFunction<1,2>, ceres::TAKE_OWNERSHIP));
255 new NumericDiffCostFunction<SizeTestingCostFunction<2,2>, CENTRAL, 2, 2>(
256 new SizeTestingCostFunction<2,2>, ceres::TAKE_OWNERSHIP));
259 new NumericDiffCostFunction<EasyFunctor, CENTRAL, ceres::DYNAMIC, 1, 1>(
260 new EasyFunctor, TAKE_OWNERSHIP, 1));
263 new NumericDiffCostFunction<EasyFunctor, CENTRAL, ceres::DYNAMIC, 1, 1>(
264 new EasyFunctor, TAKE_OWNERSHIP, 2));
267 new NumericDiffCostFunction<EasyFunctor, CENTRAL, ceres::DYNAMIC, 1, 2>(
268 new EasyFunctor, TAKE_OWNERSHIP, 1));
271 new NumericDiffCostFunction<EasyFunctor, CENTRAL, ceres::DYNAMIC, 1, 2>(
272 new EasyFunctor, TAKE_OWNERSHIP, 2));
275 new NumericDiffCostFunction<EasyFunctor, CENTRAL, ceres::DYNAMIC, 2, 1>(
276 new EasyFunctor, TAKE_OWNERSHIP, 1));
279 new NumericDiffCostFunction<EasyFunctor, CENTRAL, ceres::DYNAMIC, 2, 1>(
280 new EasyFunctor, TAKE_OWNERSHIP, 2));
283 TEST(NumericDiffCostFunction,
284 EasyCaseFunctorCentralDifferencesAndDynamicNumResiduals) {
285 internal::scoped_ptr<CostFunction> cost_function;
287 new NumericDiffCostFunction<EasyFunctor,
292 new EasyFunctor, TAKE_OWNERSHIP, 3));
294 functor.ExpectCostFunctionEvaluationIsNearlyCorrect(*cost_function, CENTRAL);
297 TEST(NumericDiffCostFunction, ExponentialFunctorRidders) {
298 internal::scoped_ptr<CostFunction> cost_function;
300 new NumericDiffCostFunction<ExponentialFunctor,
302 1, /* number of residuals */
304 new ExponentialFunctor));
305 ExponentialFunctor functor;
306 functor.ExpectCostFunctionEvaluationIsNearlyCorrect(*cost_function);
309 TEST(NumericDiffCostFunction, ExponentialCostFunctionRidders) {
310 internal::scoped_ptr<CostFunction> cost_function;
312 new NumericDiffCostFunction<ExponentialCostFunction,
314 1, /* number of residuals */
316 new ExponentialCostFunction));
317 ExponentialFunctor functor;
318 functor.ExpectCostFunctionEvaluationIsNearlyCorrect(*cost_function);
321 TEST(NumericDiffCostFunction, RandomizedFunctorRidders) {
322 internal::scoped_ptr<CostFunction> cost_function;
323 NumericDiffOptions options;
324 // Larger initial step size is chosen to produce robust results in the
325 // presence of random noise.
326 options.ridders_relative_initial_step_size = 10.0;
329 new NumericDiffCostFunction<RandomizedFunctor,
331 1, /* number of residuals */
333 new RandomizedFunctor(kNoiseFactor, kRandomSeed), TAKE_OWNERSHIP,
335 RandomizedFunctor functor (kNoiseFactor, kRandomSeed);
336 functor.ExpectCostFunctionEvaluationIsNearlyCorrect(*cost_function);
339 TEST(NumericDiffCostFunction, RandomizedCostFunctionRidders) {
340 internal::scoped_ptr<CostFunction> cost_function;
341 NumericDiffOptions options;
342 // Larger initial step size is chosen to produce robust results in the
343 // presence of random noise.
344 options.ridders_relative_initial_step_size = 10.0;
347 new NumericDiffCostFunction<RandomizedCostFunction,
349 1, /* number of residuals */
351 new RandomizedCostFunction(kNoiseFactor, kRandomSeed),
352 TAKE_OWNERSHIP, 1, options));
353 RandomizedFunctor functor (kNoiseFactor, kRandomSeed);
354 functor.ExpectCostFunctionEvaluationIsNearlyCorrect(*cost_function);
357 struct OnlyFillsOneOutputFunctor {
358 bool operator()(const double* x, double* output) const {
364 TEST(NumericDiffCostFunction, PartiallyFilledResidualShouldFailEvaluation) {
365 double parameter = 1.0;
368 double* parameters[] = {¶meter};
369 double* jacobians[] = {jacobian};
371 scoped_ptr<CostFunction> cost_function(
372 new NumericDiffCostFunction<OnlyFillsOneOutputFunctor, CENTRAL, 2, 1>(
373 new OnlyFillsOneOutputFunctor));
374 InvalidateArray(2, jacobian);
375 InvalidateArray(2, residuals);
376 EXPECT_TRUE(cost_function->Evaluate(parameters, residuals, jacobians));
377 EXPECT_FALSE(IsArrayValid(2, residuals));
378 InvalidateArray(2, residuals);
379 EXPECT_TRUE(cost_function->Evaluate(parameters, residuals, NULL));
380 // We are only testing residuals here, because the Jacobians are
381 // computed using finite differencing from the residuals, so unless
382 // we introduce a validation step after every evaluation of
383 // residuals inside NumericDiffCostFunction, there is no way of
384 // ensuring that the Jacobian array is invalid.
385 EXPECT_FALSE(IsArrayValid(2, residuals));
388 } // namespace internal