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// 290ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Author: wjr@google.com (William Rucklidge) 300ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// 310ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// This file contains tests for the GradientChecker class. 320ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 330ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include "ceres/gradient_checker.h" 340ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 350ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include <cmath> 360ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include <cstdlib> 370ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include <vector> 380ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 390ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include "ceres/cost_function.h" 400ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include "ceres/random.h" 411d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling#include "glog/logging.h" 420ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include "gtest/gtest.h" 430ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 440ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kongnamespace ceres { 450ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kongnamespace internal { 460ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 470ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// We pick a (non-quadratic) function whose derivative are easy: 480ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// 490ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// f = exp(- a' x). 500ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// df = - f a. 510ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// 520ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// where 'a' is a vector of the same size as 'x'. In the block 530ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// version, they are both block vectors, of course. 540ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kongclass GoodTestTerm : public CostFunction { 550ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong public: 560ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong GoodTestTerm(int arity, int const *dim) : arity_(arity) { 570ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // Make 'arity' random vectors. 580ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong a_.resize(arity_); 590ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int j = 0; j < arity_; ++j) { 600ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong a_[j].resize(dim[j]); 610ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int u = 0; u < dim[j]; ++u) { 620ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong a_[j][u] = 2.0 * RandDouble() - 1.0; 630ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 640ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 650ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 660ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int i = 0; i < arity_; i++) { 670ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong mutable_parameter_block_sizes()->push_back(dim[i]); 680ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 690ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong set_num_residuals(1); 700ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 710ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 720ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong bool Evaluate(double const* const* parameters, 730ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double* residuals, 740ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double** jacobians) const { 750ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // Compute a . x. 760ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double ax = 0; 770ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int j = 0; j < arity_; ++j) { 780ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int u = 0; u < parameter_block_sizes()[j]; ++u) { 790ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong ax += a_[j][u] * parameters[j][u]; 800ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 810ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 820ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 830ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // This is the cost, but also appears as a factor 840ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // in the derivatives. 850ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double f = *residuals = exp(-ax); 860ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 870ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // Accumulate 1st order derivatives. 880ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong if (jacobians) { 890ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int j = 0; j < arity_; ++j) { 900ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong if (jacobians[j]) { 910ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int u = 0; u < parameter_block_sizes()[j]; ++u) { 920ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // See comments before class. 930ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong jacobians[j][u] = - f * a_[j][u]; 940ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 950ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 960ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 970ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 980ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 990ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong return true; 1000ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 1010ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 1020ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong private: 1030ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong int arity_; 1040ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong vector<vector<double> > a_; // our vectors. 1050ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong}; 1060ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 1070ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kongclass BadTestTerm : public CostFunction { 1080ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong public: 1090ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong BadTestTerm(int arity, int const *dim) : arity_(arity) { 1100ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // Make 'arity' random vectors. 1110ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong a_.resize(arity_); 1120ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int j = 0; j < arity_; ++j) { 1130ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong a_[j].resize(dim[j]); 1140ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int u = 0; u < dim[j]; ++u) { 1150ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong a_[j][u] = 2.0 * RandDouble() - 1.0; 1160ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 1170ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 1180ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 1190ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int i = 0; i < arity_; i++) { 1200ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong mutable_parameter_block_sizes()->push_back(dim[i]); 1210ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 1220ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong set_num_residuals(1); 1230ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 1240ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 1250ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong bool Evaluate(double const* const* parameters, 1260ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double* residuals, 1270ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double** jacobians) const { 1280ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // Compute a . x. 1290ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double ax = 0; 1300ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int j = 0; j < arity_; ++j) { 1310ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int u = 0; u < parameter_block_sizes()[j]; ++u) { 1320ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong ax += a_[j][u] * parameters[j][u]; 1330ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 1340ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 1350ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 1360ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // This is the cost, but also appears as a factor 1370ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // in the derivatives. 1380ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double f = *residuals = exp(-ax); 1390ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 1400ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // Accumulate 1st order derivatives. 1410ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong if (jacobians) { 1420ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int j = 0; j < arity_; ++j) { 1430ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong if (jacobians[j]) { 1440ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int u = 0; u < parameter_block_sizes()[j]; ++u) { 1450ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // See comments before class. 1460ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong jacobians[j][u] = - f * a_[j][u] + 0.001; 1470ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 1480ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 1490ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 1500ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 1510ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 1520ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong return true; 1530ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 1540ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 1550ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong private: 1560ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong int arity_; 1570ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong vector<vector<double> > a_; // our vectors. 1580ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong}; 1590ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 1600ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus KongTEST(GradientChecker, SmokeTest) { 1610ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong srand(5); 1620ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 1630ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // Test with 3 blocks of size 2, 3 and 4. 1640ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong int const arity = 3; 1650ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong int const dim[arity] = { 2, 3, 4 }; 1660ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 1670ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // Make a random set of blocks. 1680ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong FixedArray<double*> parameters(arity); 1690ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int j = 0; j < arity; ++j) { 1700ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong parameters[j] = new double[dim[j]]; 1710ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int u = 0; u < dim[j]; ++u) { 1720ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong parameters[j][u] = 2.0 * RandDouble() - 1.0; 1730ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 1740ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 1750ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 1760ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // Make a term and probe it. 1770ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong GoodTestTerm good_term(arity, dim); 1780ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong typedef GradientChecker<GoodTestTerm, 1, 2, 3, 4> GoodTermGradientChecker; 1790ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong EXPECT_TRUE(GoodTermGradientChecker::Probe( 1800ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong parameters.get(), 1e-6, &good_term, NULL)); 1810ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 1820ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong BadTestTerm bad_term(arity, dim); 1830ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong typedef GradientChecker<BadTestTerm, 1, 2, 3, 4> BadTermGradientChecker; 1840ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong EXPECT_FALSE(BadTermGradientChecker::Probe( 1850ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong parameters.get(), 1e-6, &bad_term, NULL)); 1860ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 1870ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int j = 0; j < arity; j++) { 1880ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong delete[] parameters[j]; 1890ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 1900ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong} 1910ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 1920ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong} // namespace internal 1930ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong} // namespace ceres 194