Home | History | Annotate | Download | only in ceres
      1 // 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 //
     29 // Author: keir (at) google.com (Keir Mierle)
     30 //
     31 // Based on the tests in numeric_diff_cost_function.cc.
     32 //
     33 // TODO(keir): See about code duplication.
     34 
     35 #include "ceres/runtime_numeric_diff_cost_function.h"
     36 
     37 #include <algorithm>
     38 #include <cmath>
     39 #include <string>
     40 #include <vector>
     41 #include "ceres/cost_function.h"
     42 #include "ceres/internal/macros.h"
     43 #include "ceres/internal/scoped_ptr.h"
     44 #include "ceres/stringprintf.h"
     45 #include "ceres/test_util.h"
     46 #include "glog/logging.h"
     47 #include "gtest/gtest.h"
     48 
     49 namespace ceres {
     50 namespace internal {
     51 
     52 const double kRelativeEps = 1e-6;
     53 
     54 // y1 = x1'x2      -> dy1/dx1 = x2,               dy1/dx2 = x1
     55 // y2 = (x1'x2)^2  -> dy2/dx1 = 2 * x2 * (x1'x2), dy2/dx2 = 2 * x1 * (x1'x2)
     56 // y3 = x2'x2      -> dy3/dx1 = 0,                dy3/dx2 = 2 * x2
     57 class TestCostFunction : public CostFunction {
     58  public:
     59   TestCostFunction() {
     60     set_num_residuals(3);
     61     mutable_parameter_block_sizes()->push_back(5);  // x1.
     62     mutable_parameter_block_sizes()->push_back(5);  // x2.
     63   }
     64   virtual bool Evaluate(double const* const* parameters,
     65                         double* residuals,
     66                         double** jacobians) const {
     67     (void) jacobians;  // Ignored.
     68 
     69     residuals[0] = residuals[1] = residuals[2] = 0;
     70     for (int i = 0; i < 5; ++i) {
     71       residuals[0] += parameters[0][i] * parameters[1][i];
     72       residuals[2] += parameters[1][i] * parameters[1][i];
     73     }
     74     residuals[1] = residuals[0] * residuals[0];
     75     return true;
     76   }
     77 };
     78 
     79 TEST(NumericDiffCostFunction, EasyCase) {
     80   // Try both central and forward difference.
     81   TestCostFunction term;
     82   scoped_ptr<CostFunction> cfs[2];
     83   cfs[0].reset(
     84       CreateRuntimeNumericDiffCostFunction(&term, CENTRAL, kRelativeEps));
     85 
     86   cfs[1].reset(
     87       CreateRuntimeNumericDiffCostFunction(&term, FORWARD, kRelativeEps));
     88 
     89 
     90   for (int c = 0; c < 2; ++c) {
     91     CostFunction *cost_function = cfs[c].get();
     92 
     93     double x1[] = { 1.0, 2.0, 3.0, 4.0, 5.0 };
     94     double x2[] = { 9.0, 9.0, 5.0, 5.0, 1.0 };
     95     double *parameters[] = { &x1[0], &x2[0] };
     96 
     97     double dydx1[15];  // 3 x 5, row major.
     98     double dydx2[15];  // 3 x 5, row major.
     99     double *jacobians[2] = { &dydx1[0], &dydx2[0] };
    100 
    101     double residuals[3] = {-1e-100, -2e-100, -3e-100 };
    102 
    103     ASSERT_TRUE(cost_function->Evaluate(&parameters[0],
    104                                         &residuals[0],
    105                                         &jacobians[0]));
    106 
    107     EXPECT_EQ(residuals[0], 67);
    108     EXPECT_EQ(residuals[1], 4489);
    109     EXPECT_EQ(residuals[2], 213);
    110 
    111     for (int i = 0; i < 5; ++i) {
    112       LOG(INFO) << "c = " << c << " i = " << i;
    113       const double kEps = c == 0 ? /* central */ 3e-9 : /* forward */ 2e-5;
    114 
    115       ExpectClose(x2[i],                    dydx1[5 * 0 + i], kEps);  // y1
    116       ExpectClose(x1[i],                    dydx2[5 * 0 + i], kEps);
    117       ExpectClose(2 * x2[i] * residuals[0], dydx1[5 * 1 + i], kEps);  // y2
    118       ExpectClose(2 * x1[i] * residuals[0], dydx2[5 * 1 + i], kEps);
    119       ExpectClose(0.0,                      dydx1[5 * 2 + i], kEps);  // y3
    120       ExpectClose(2 * x2[i],                dydx2[5 * 2 + i], kEps);
    121     }
    122   }
    123 }
    124 
    125 // y1 = sin(x1'x2)
    126 // y2 = exp(-x1'x2 / 10)
    127 //
    128 // dy1/dx1 =  x2 * cos(x1'x2),            dy1/dx2 =  x1 * cos(x1'x2)
    129 // dy2/dx1 = -x2 * exp(-x1'x2 / 10) / 10, dy2/dx2 = -x2 * exp(-x1'x2 / 10) / 10
    130 class TranscendentalTestCostFunction : public CostFunction {
    131  public:
    132   TranscendentalTestCostFunction() {
    133     set_num_residuals(2);
    134     mutable_parameter_block_sizes()->push_back(5);  // x1.
    135     mutable_parameter_block_sizes()->push_back(5);  // x2.
    136   }
    137   virtual bool Evaluate(double const* const* parameters,
    138                         double* residuals,
    139                         double** jacobians) const {
    140     (void) jacobians;  // Ignored.
    141 
    142     double x1x2 = 0;
    143     for (int i = 0; i < 5; ++i) {
    144       x1x2 += parameters[0][i] * parameters[1][i];
    145     }
    146     residuals[0] = sin(x1x2);
    147     residuals[1] = exp(-x1x2 / 10);
    148     return true;
    149   }
    150 };
    151 
    152 TEST(NumericDiffCostFunction, TransendentalOperationsInCostFunction) {
    153   // Try both central and forward difference.
    154   TranscendentalTestCostFunction term;
    155   scoped_ptr<CostFunction> cfs[2];
    156   cfs[0].reset(
    157       CreateRuntimeNumericDiffCostFunction(&term, CENTRAL, kRelativeEps));
    158 
    159   cfs[1].reset(
    160       CreateRuntimeNumericDiffCostFunction(&term, FORWARD, kRelativeEps));
    161 
    162   for (int c = 0; c < 2; ++c) {
    163     CostFunction *cost_function = cfs[c].get();
    164 
    165     struct {
    166       double x1[5];
    167       double x2[5];
    168     } kTests[] = {
    169       { { 1.0, 2.0, 3.0, 4.0, 5.0 },  // No zeros.
    170         { 9.0, 9.0, 5.0, 5.0, 1.0 },
    171       },
    172       { { 0.0, 2.0, 3.0, 0.0, 5.0 },  // Some zeros x1.
    173         { 9.0, 9.0, 5.0, 5.0, 1.0 },
    174       },
    175       { { 1.0, 2.0, 3.0, 1.0, 5.0 },  // Some zeros x2.
    176         { 0.0, 9.0, 0.0, 5.0, 0.0 },
    177       },
    178       { { 0.0, 0.0, 0.0, 0.0, 0.0 },  // All zeros x1.
    179         { 9.0, 9.0, 5.0, 5.0, 1.0 },
    180       },
    181       { { 1.0, 2.0, 3.0, 4.0, 5.0 },  // All zeros x2.
    182         { 0.0, 0.0, 0.0, 0.0, 0.0 },
    183       },
    184       { { 0.0, 0.0, 0.0, 0.0, 0.0 },  // All zeros.
    185         { 0.0, 0.0, 0.0, 0.0, 0.0 },
    186       },
    187     };
    188     for (int k = 0; k < CERES_ARRAYSIZE(kTests); ++k) {
    189       double *x1 = &(kTests[k].x1[0]);
    190       double *x2 = &(kTests[k].x2[0]);
    191       double *parameters[] = { x1, x2 };
    192 
    193       double dydx1[10];
    194       double dydx2[10];
    195       double *jacobians[2] = { &dydx1[0], &dydx2[0] };
    196 
    197       double residuals[2];
    198 
    199       ASSERT_TRUE(cost_function->Evaluate(&parameters[0],
    200                                           &residuals[0],
    201                                           &jacobians[0]));
    202       LOG(INFO) << "Ran evaluate for test k=" << k << " c=" << c;
    203 
    204       double x1x2 = 0;
    205       for (int i = 0; i < 5; ++i) {
    206         x1x2 += x1[i] * x2[i];
    207       }
    208 
    209       for (int i = 0; i < 5; ++i) {
    210         const double kEps = (c == 0 ? /* central */ 3e-9 : /* forward */ 2e-5);
    211 
    212         ExpectClose( x2[i] * cos(x1x2),              dydx1[5 * 0 + i], kEps);  // NOLINT
    213         ExpectClose( x1[i] * cos(x1x2),              dydx2[5 * 0 + i], kEps);  // NOLINT
    214         ExpectClose(-x2[i] * exp(-x1x2 / 10.) / 10., dydx1[5 * 1 + i], kEps);
    215         ExpectClose(-x1[i] * exp(-x1x2 / 10.) / 10., dydx2[5 * 1 + i], kEps);
    216       }
    217     }
    218   }
    219 }
    220 
    221 }  // namespace internal
    222 }  // namespace ceres
    223