10ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Ceres Solver - A fast non-linear least squares minimizer
20ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
30ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// http://code.google.com/p/ceres-solver/
40ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong//
50ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Redistribution and use in source and binary forms, with or without
60ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// modification, are permitted provided that the following conditions are met:
70ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong//
80ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// * Redistributions of source code must retain the above copyright notice,
90ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong//   this list of conditions and the following disclaimer.
100ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// * Redistributions in binary form must reproduce the above copyright notice,
110ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong//   this list of conditions and the following disclaimer in the documentation
120ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong//   and/or other materials provided with the distribution.
130ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// * Neither the name of Google Inc. nor the names of its contributors may be
140ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong//   used to endorse or promote products derived from this software without
150ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong//   specific prior written permission.
160ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong//
170ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
180ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
190ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
200ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
210ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
220ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
230ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
240ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
250ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
260ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
270ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// POSSIBILITY OF SUCH DAMAGE.
280ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Copyright 2007 Google Inc. All Rights Reserved.
290ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong//
300ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Author: wjr@google.com (William Rucklidge)
310ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong//
320ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// This file contains a class that exercises a cost function, to make sure
330ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// that it is computing reasonable derivatives. It compares the Jacobians
340ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// computed by the cost function with those obtained by finite
350ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// differences.
360ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
370ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#ifndef CERES_PUBLIC_GRADIENT_CHECKER_H_
380ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#define CERES_PUBLIC_GRADIENT_CHECKER_H_
390ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
400ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include <cstddef>
411d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling#include <algorithm>
420ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include <vector>
430ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
440ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include "ceres/internal/eigen.h"
450ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include "ceres/internal/fixed_array.h"
460ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include "ceres/internal/macros.h"
470ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include "ceres/internal/scoped_ptr.h"
480ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include "ceres/numeric_diff_cost_function.h"
491d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling#include "glog/logging.h"
500ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
510ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kongnamespace ceres {
520ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
530ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// An object that exercises a cost function, to compare the answers that it
540ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// gives with derivatives estimated using finite differencing.
550ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong//
560ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// The only likely usage of this is for testing.
570ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong//
580ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// How to use: Fill in an array of pointers to parameter blocks for your
590ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// CostFunction, and then call Probe(). Check that the return value is
600ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// 'true'. See prober_test.cc for an example.
610ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong//
620ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// This is templated similarly to NumericDiffCostFunction, as it internally
630ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// uses that.
640ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kongtemplate <typename CostFunctionToProbe,
650ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong          int M = 0, int N0 = 0, int N1 = 0, int N2 = 0, int N3 = 0, int N4 = 0>
660ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kongclass GradientChecker {
670ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong public:
680ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  // Here we stash some results from the probe, for later
690ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  // inspection.
700ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  struct GradientCheckResults {
710ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    // Computed cost.
720ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    Vector cost;
730ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
740ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    // The sizes of these matrices are dictated by the cost function's
750ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    // parameter and residual block sizes. Each vector's length will
760ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    // term->parameter_block_sizes().size(), and each matrix is the
770ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    // Jacobian of the residual with respect to the corresponding parameter
780ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    // block.
790ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
800ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    // Derivatives as computed by the cost function.
810ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    vector<Matrix> term_jacobians;
820ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
830ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    // Derivatives as computed by finite differencing.
840ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    vector<Matrix> finite_difference_jacobians;
850ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
860ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    // Infinity-norm of term_jacobians - finite_difference_jacobians.
870ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    double error_jacobians;
880ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  };
890ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
900ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  // Checks the Jacobian computed by a cost function.
910ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  //
920ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  // probe_point: The parameter values at which to probe.
930ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  // error_tolerance: A threshold for the infinity-norm difference
940ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  // between the Jacobians. If the Jacobians differ by more than
950ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  // this amount, then the probe fails.
960ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  //
970ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  // term: The cost function to test. Not retained after this call returns.
980ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  //
990ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  // results: On return, the two Jacobians (and other information)
1000ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  // will be stored here.  May be NULL.
1010ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  //
1020ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  // Returns true if no problems are detected and the difference between the
1030ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  // Jacobians is less than error_tolerance.
1040ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  static bool Probe(double const* const* probe_point,
1050ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong                    double error_tolerance,
1060ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong                    CostFunctionToProbe *term,
1070ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong                    GradientCheckResults* results) {
1080ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    CHECK_NOTNULL(probe_point);
1090ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    CHECK_NOTNULL(term);
1100ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    LOG(INFO) << "-------------------- Starting Probe() --------------------";
1110ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
1120ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    // We need a GradientCheckeresults, whether or not they supplied one.
1130ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    internal::scoped_ptr<GradientCheckResults> owned_results;
1140ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    if (results == NULL) {
1150ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      owned_results.reset(new GradientCheckResults);
1160ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      results = owned_results.get();
1170ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    }
1180ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
1190ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    // Do a consistency check between the term and the template parameters.
1200ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    CHECK_EQ(M, term->num_residuals());
1210ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    const int num_residuals = M;
12279397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez    const vector<int32>& block_sizes = term->parameter_block_sizes();
1230ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    const int num_blocks = block_sizes.size();
1240ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
1250ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    CHECK_LE(num_blocks, 5) << "Unable to test functions that take more "
1260ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong                            << "than 5 parameter blocks";
1270ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    if (N0) {
1280ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      CHECK_EQ(N0, block_sizes[0]);
1290ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      CHECK_GE(num_blocks, 1);
1300ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    } else {
1310ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      CHECK_LT(num_blocks, 1);
1320ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    }
1330ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    if (N1) {
1340ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      CHECK_EQ(N1, block_sizes[1]);
1350ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      CHECK_GE(num_blocks, 2);
1360ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    } else {
1370ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      CHECK_LT(num_blocks, 2);
1380ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    }
1390ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    if (N2) {
1400ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      CHECK_EQ(N2, block_sizes[2]);
1410ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      CHECK_GE(num_blocks, 3);
1420ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    } else {
1430ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      CHECK_LT(num_blocks, 3);
1440ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    }
1450ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    if (N3) {
1460ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      CHECK_EQ(N3, block_sizes[3]);
1470ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      CHECK_GE(num_blocks, 4);
1480ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    } else {
1490ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      CHECK_LT(num_blocks, 4);
1500ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    }
1510ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    if (N4) {
1520ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      CHECK_EQ(N4, block_sizes[4]);
1530ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      CHECK_GE(num_blocks, 5);
1540ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    } else {
1550ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      CHECK_LT(num_blocks, 5);
1560ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    }
1570ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
1580ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    results->term_jacobians.clear();
1590ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    results->term_jacobians.resize(num_blocks);
1600ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    results->finite_difference_jacobians.clear();
1610ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    results->finite_difference_jacobians.resize(num_blocks);
1620ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
1630ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    internal::FixedArray<double*> term_jacobian_pointers(num_blocks);
1641d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling    internal::FixedArray<double*>
1651d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling        finite_difference_jacobian_pointers(num_blocks);
1660ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    for (int i = 0; i < num_blocks; i++) {
1670ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      results->term_jacobians[i].resize(num_residuals, block_sizes[i]);
1680ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      term_jacobian_pointers[i] = results->term_jacobians[i].data();
1690ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      results->finite_difference_jacobians[i].resize(
1700ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong          num_residuals, block_sizes[i]);
1710ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      finite_difference_jacobian_pointers[i] =
1720ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong          results->finite_difference_jacobians[i].data();
1730ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    }
1740ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    results->cost.resize(num_residuals, 1);
1750ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
1760ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    CHECK(term->Evaluate(probe_point, results->cost.data(),
1770ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong                         term_jacobian_pointers.get()));
1780ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    NumericDiffCostFunction<CostFunctionToProbe, CENTRAL, M, N0, N1, N2, N3, N4>
1790ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong        numeric_term(term, DO_NOT_TAKE_OWNERSHIP);
1800ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    CHECK(numeric_term.Evaluate(probe_point, results->cost.data(),
1810ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong                                finite_difference_jacobian_pointers.get()));
1820ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
1830ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    results->error_jacobians = 0;
1840ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    for (int i = 0; i < num_blocks; i++) {
1850ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      Matrix jacobian_difference = results->term_jacobians[i] -
1860ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong          results->finite_difference_jacobians[i];
1870ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      results->error_jacobians =
1880ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong          std::max(results->error_jacobians,
1890ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong                   jacobian_difference.lpNorm<Eigen::Infinity>());
1900ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    }
1910ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
1920ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    LOG(INFO) << "========== term-computed derivatives ==========";
1930ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    for (int i = 0; i < num_blocks; i++) {
1940ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      LOG(INFO) << "term_computed block " << i;
1950ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      LOG(INFO) << "\n" << results->term_jacobians[i];
1960ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    }
1970ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
1980ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    LOG(INFO) << "========== finite-difference derivatives ==========";
1990ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    for (int i = 0; i < num_blocks; i++) {
2000ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      LOG(INFO) << "finite_difference block " << i;
2010ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      LOG(INFO) << "\n" << results->finite_difference_jacobians[i];
2020ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    }
2030ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
2040ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    LOG(INFO) << "========== difference ==========";
2050ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    for (int i = 0; i < num_blocks; i++) {
2060ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      LOG(INFO) << "difference block " << i;
2070ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      LOG(INFO) << (results->term_jacobians[i] -
2080ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong                    results->finite_difference_jacobians[i]);
2090ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    }
2100ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
2110ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    LOG(INFO) << "||difference|| = " << results->error_jacobians;
2120ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
2130ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    return results->error_jacobians < error_tolerance;
2140ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  }
2150ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
2160ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong private:
2170ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  CERES_DISALLOW_IMPLICIT_CONSTRUCTORS(GradientChecker);
2180ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong};
2190ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
2200ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong}  // namespace ceres
2210ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
2220ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#endif  // CERES_PUBLIC_GRADIENT_CHECKER_H_
223