blob: 3ec8056a02d9cc7f3311d066bf854eaac3ce1feb [file] [log] [blame]
Sameer Agarwal747845f2012-11-07 18:14:54 -08001// 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// Copyright 2007 Google Inc. All Rights Reserved.
29//
30// Author: wjr@google.com (William Rucklidge)
31//
32// This file contains a class that exercises a cost function, to make sure
33// that it is computing reasonable derivatives. It compares the Jacobians
34// computed by the cost function with those obtained by finite
35// differences.
36
37#ifndef CERES_PUBLIC_GRADIENT_CHECKER_H_
38#define CERES_PUBLIC_GRADIENT_CHECKER_H_
39
Sameer Agarwal747845f2012-11-07 18:14:54 -080040#include <cstddef>
Sameer Agarwal509f68c2013-02-20 01:39:03 -080041#include <algorithm>
Sameer Agarwal747845f2012-11-07 18:14:54 -080042#include <vector>
43
Sameer Agarwal747845f2012-11-07 18:14:54 -080044#include "ceres/internal/eigen.h"
45#include "ceres/internal/fixed_array.h"
46#include "ceres/internal/macros.h"
47#include "ceres/internal/scoped_ptr.h"
48#include "ceres/numeric_diff_cost_function.h"
Sameer Agarwal509f68c2013-02-20 01:39:03 -080049#include "glog/logging.h"
Sameer Agarwal747845f2012-11-07 18:14:54 -080050
51namespace ceres {
52
53// An object that exercises a cost function, to compare the answers that it
54// gives with derivatives estimated using finite differencing.
55//
56// The only likely usage of this is for testing.
57//
58// How to use: Fill in an array of pointers to parameter blocks for your
59// CostFunction, and then call Probe(). Check that the return value is
60// 'true'. See prober_test.cc for an example.
61//
62// This is templated similarly to NumericDiffCostFunction, as it internally
63// uses that.
64template <typename CostFunctionToProbe,
65 int M = 0, int N0 = 0, int N1 = 0, int N2 = 0, int N3 = 0, int N4 = 0>
66class GradientChecker {
67 public:
68 // Here we stash some results from the probe, for later
69 // inspection.
70 struct GradientCheckResults {
71 // Computed cost.
72 Vector cost;
73
74 // The sizes of these matrices are dictated by the cost function's
75 // parameter and residual block sizes. Each vector's length will
76 // term->parameter_block_sizes().size(), and each matrix is the
77 // Jacobian of the residual with respect to the corresponding parameter
78 // block.
79
80 // Derivatives as computed by the cost function.
81 vector<Matrix> term_jacobians;
82
83 // Derivatives as computed by finite differencing.
84 vector<Matrix> finite_difference_jacobians;
85
86 // Infinity-norm of term_jacobians - finite_difference_jacobians.
87 double error_jacobians;
88 };
89
90 // Checks the Jacobian computed by a cost function.
91 //
92 // probe_point: The parameter values at which to probe.
93 // error_tolerance: A threshold for the infinity-norm difference
94 // between the Jacobians. If the Jacobians differ by more than
95 // this amount, then the probe fails.
96 //
97 // term: The cost function to test. Not retained after this call returns.
98 //
99 // results: On return, the two Jacobians (and other information)
100 // will be stored here. May be NULL.
101 //
102 // Returns true if no problems are detected and the difference between the
103 // Jacobians is less than error_tolerance.
104 static bool Probe(double const* const* probe_point,
105 double error_tolerance,
106 CostFunctionToProbe *term,
107 GradientCheckResults* results) {
108 CHECK_NOTNULL(probe_point);
109 CHECK_NOTNULL(term);
110 LOG(INFO) << "-------------------- Starting Probe() --------------------";
111
112 // We need a GradientCheckeresults, whether or not they supplied one.
113 internal::scoped_ptr<GradientCheckResults> owned_results;
114 if (results == NULL) {
115 owned_results.reset(new GradientCheckResults);
116 results = owned_results.get();
117 }
118
119 // Do a consistency check between the term and the template parameters.
120 CHECK_EQ(M, term->num_residuals());
121 const int num_residuals = M;
122 const vector<int16>& block_sizes = term->parameter_block_sizes();
123 const int num_blocks = block_sizes.size();
124
125 CHECK_LE(num_blocks, 5) << "Unable to test functions that take more "
126 << "than 5 parameter blocks";
127 if (N0) {
128 CHECK_EQ(N0, block_sizes[0]);
129 CHECK_GE(num_blocks, 1);
130 } else {
131 CHECK_LT(num_blocks, 1);
132 }
133 if (N1) {
134 CHECK_EQ(N1, block_sizes[1]);
135 CHECK_GE(num_blocks, 2);
136 } else {
137 CHECK_LT(num_blocks, 2);
138 }
139 if (N2) {
140 CHECK_EQ(N2, block_sizes[2]);
141 CHECK_GE(num_blocks, 3);
142 } else {
143 CHECK_LT(num_blocks, 3);
144 }
145 if (N3) {
146 CHECK_EQ(N3, block_sizes[3]);
147 CHECK_GE(num_blocks, 4);
148 } else {
149 CHECK_LT(num_blocks, 4);
150 }
151 if (N4) {
152 CHECK_EQ(N4, block_sizes[4]);
153 CHECK_GE(num_blocks, 5);
154 } else {
155 CHECK_LT(num_blocks, 5);
156 }
157
158 results->term_jacobians.clear();
159 results->term_jacobians.resize(num_blocks);
160 results->finite_difference_jacobians.clear();
161 results->finite_difference_jacobians.resize(num_blocks);
162
163 internal::FixedArray<double*> term_jacobian_pointers(num_blocks);
Sameer Agarwal509f68c2013-02-20 01:39:03 -0800164 internal::FixedArray<double*>
165 finite_difference_jacobian_pointers(num_blocks);
Sameer Agarwal747845f2012-11-07 18:14:54 -0800166 for (int i = 0; i < num_blocks; i++) {
167 results->term_jacobians[i].resize(num_residuals, block_sizes[i]);
168 term_jacobian_pointers[i] = results->term_jacobians[i].data();
169 results->finite_difference_jacobians[i].resize(
170 num_residuals, block_sizes[i]);
171 finite_difference_jacobian_pointers[i] =
172 results->finite_difference_jacobians[i].data();
173 }
174 results->cost.resize(num_residuals, 1);
175
176 CHECK(term->Evaluate(probe_point, results->cost.data(),
177 term_jacobian_pointers.get()));
178 NumericDiffCostFunction<CostFunctionToProbe, CENTRAL, M, N0, N1, N2, N3, N4>
179 numeric_term(term, DO_NOT_TAKE_OWNERSHIP);
180 CHECK(numeric_term.Evaluate(probe_point, results->cost.data(),
181 finite_difference_jacobian_pointers.get()));
182
183 results->error_jacobians = 0;
184 for (int i = 0; i < num_blocks; i++) {
185 Matrix jacobian_difference = results->term_jacobians[i] -
186 results->finite_difference_jacobians[i];
187 results->error_jacobians =
188 std::max(results->error_jacobians,
189 jacobian_difference.lpNorm<Eigen::Infinity>());
190 }
191
192 LOG(INFO) << "========== term-computed derivatives ==========";
193 for (int i = 0; i < num_blocks; i++) {
194 LOG(INFO) << "term_computed block " << i;
195 LOG(INFO) << "\n" << results->term_jacobians[i];
196 }
197
198 LOG(INFO) << "========== finite-difference derivatives ==========";
199 for (int i = 0; i < num_blocks; i++) {
200 LOG(INFO) << "finite_difference block " << i;
201 LOG(INFO) << "\n" << results->finite_difference_jacobians[i];
202 }
203
204 LOG(INFO) << "========== difference ==========";
205 for (int i = 0; i < num_blocks; i++) {
206 LOG(INFO) << "difference block " << i;
207 LOG(INFO) << (results->term_jacobians[i] -
208 results->finite_difference_jacobians[i]);
209 }
210
211 LOG(INFO) << "||difference|| = " << results->error_jacobians;
212
213 return results->error_jacobians < error_tolerance;
214 }
215
216 private:
217 CERES_DISALLOW_IMPLICIT_CONSTRUCTORS(GradientChecker);
218};
219
220} // namespace ceres
221
222#endif // CERES_PUBLIC_GRADIENT_CHECKER_H_