blob: 6786ac908ba4e89f1aff9b04344d33343a1185b0 [file] [log] [blame]
Sameer Agarwal2f0d7242013-01-18 13:11:32 -08001#include "ceres/numeric_diff_test_utils.h"
2
3#include <algorithm>
4#include <cmath>
5#include "ceres/cost_function.h"
6#include "ceres/internal/macros.h"
7#include "ceres/test_util.h"
8#include "ceres/types.h"
9#include "gtest/gtest.h"
10
11
12namespace ceres {
13namespace internal {
14
15bool EasyFunctor::operator()(const double* x1,
16 const double* x2,
17 double* residuals) const {
18 residuals[0] = residuals[1] = residuals[2] = 0;
19 for (int i = 0; i < 5; ++i) {
20 residuals[0] += x1[i] * x2[i];
21 residuals[2] += x2[i] * x2[i];
22 }
23 residuals[1] = residuals[0] * residuals[0];
24 return true;
25}
26
27void EasyFunctor::ExpectCostFunctionEvaluationIsNearlyCorrect(
28 const CostFunction& cost_function,
29 NumericDiffMethod method) const {
30 double x1[] = { 1.0, 2.0, 3.0, 4.0, 5.0 };
31 double x2[] = { 9.0, 9.0, 5.0, 5.0, 1.0 };
32 double *parameters[] = { &x1[0], &x2[0] };
33
34 double dydx1[15]; // 3 x 5, row major.
35 double dydx2[15]; // 3 x 5, row major.
36 double *jacobians[2] = { &dydx1[0], &dydx2[0] };
37
38 double residuals[3] = {-1e-100, -2e-100, -3e-100 };
39
40 ASSERT_TRUE(cost_function.Evaluate(&parameters[0],
41 &residuals[0],
42 &jacobians[0]));
43
44 EXPECT_EQ(residuals[0], 67);
45 EXPECT_EQ(residuals[1], 4489);
46 EXPECT_EQ(residuals[2], 213);
47
48 const double tolerance = (method == CENTRAL)? 3e-9 : 2e-5;
49
50 for (int i = 0; i < 5; ++i) {
51 ExpectClose(x2[i], dydx1[5 * 0 + i], tolerance); // y1
52 ExpectClose(x1[i], dydx2[5 * 0 + i], tolerance);
53 ExpectClose(2 * x2[i] * residuals[0], dydx1[5 * 1 + i], tolerance); // y2
54 ExpectClose(2 * x1[i] * residuals[0], dydx2[5 * 1 + i], tolerance);
55 ExpectClose(0.0, dydx1[5 * 2 + i], tolerance); // y3
56 ExpectClose(2 * x2[i], dydx2[5 * 2 + i], tolerance);
57 }
58}
59
60bool TranscendentalFunctor::operator()(const double* x1,
61 const double* x2,
62 double* residuals) const {
63 double x1x2 = 0;
64 for (int i = 0; i < 5; ++i) {
65 x1x2 += x1[i] * x2[i];
66 }
67 residuals[0] = sin(x1x2);
68 residuals[1] = exp(-x1x2 / 10);
69 return true;
70}
71
72void TranscendentalFunctor::ExpectCostFunctionEvaluationIsNearlyCorrect(
73 const CostFunction& cost_function,
74 NumericDiffMethod method) const {
75 struct {
76 double x1[5];
77 double x2[5];
78 } kTests[] = {
79 { { 1.0, 2.0, 3.0, 4.0, 5.0 }, // No zeros.
80 { 9.0, 9.0, 5.0, 5.0, 1.0 },
81 },
82 { { 0.0, 2.0, 3.0, 0.0, 5.0 }, // Some zeros x1.
83 { 9.0, 9.0, 5.0, 5.0, 1.0 },
84 },
85 { { 1.0, 2.0, 3.0, 1.0, 5.0 }, // Some zeros x2.
86 { 0.0, 9.0, 0.0, 5.0, 0.0 },
87 },
88 { { 0.0, 0.0, 0.0, 0.0, 0.0 }, // All zeros x1.
89 { 9.0, 9.0, 5.0, 5.0, 1.0 },
90 },
91 { { 1.0, 2.0, 3.0, 4.0, 5.0 }, // All zeros x2.
92 { 0.0, 0.0, 0.0, 0.0, 0.0 },
93 },
94 { { 0.0, 0.0, 0.0, 0.0, 0.0 }, // All zeros.
95 { 0.0, 0.0, 0.0, 0.0, 0.0 },
96 },
97 };
98
99 for (int k = 0; k < CERES_ARRAYSIZE(kTests); ++k) {
100 double *x1 = &(kTests[k].x1[0]);
101 double *x2 = &(kTests[k].x2[0]);
102 double *parameters[] = { x1, x2 };
103
104 double dydx1[10];
105 double dydx2[10];
106 double *jacobians[2] = { &dydx1[0], &dydx2[0] };
107
108 double residuals[2];
109
110 ASSERT_TRUE(cost_function.Evaluate(&parameters[0],
111 &residuals[0],
112 &jacobians[0]));
113 double x1x2 = 0;
114 for (int i = 0; i < 5; ++i) {
115 x1x2 += x1[i] * x2[i];
116 }
117
118 const double tolerance = (method == CENTRAL)? 3e-9 : 2e-5;
119
120 for (int i = 0; i < 5; ++i) {
121 ExpectClose( x2[i] * cos(x1x2), dydx1[5 * 0 + i], tolerance);
122 ExpectClose( x1[i] * cos(x1x2), dydx2[5 * 0 + i], tolerance);
123 ExpectClose(-x2[i] * exp(-x1x2 / 10.) / 10., dydx1[5 * 1 + i], tolerance);
124 ExpectClose(-x1[i] * exp(-x1x2 / 10.) / 10., dydx2[5 * 1 + i], tolerance);
125 }
126 }
127}
128
129} // namespace internal
130} // namespace ceres