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 //         sameeragarwal (at) google.com (Sameer Agarwal)
     31 //
     32 // Create CostFunctions as needed by the least squares framework with jacobians
     33 // computed via numeric (a.k.a. finite) differentiation. For more details see
     34 // http://en.wikipedia.org/wiki/Numerical_differentiation.
     35 //
     36 // To get an numerically differentiated cost function, you must define
     37 // a class with a operator() (a functor) that computes the residuals.
     38 //
     39 // The function must write the computed value in the last argument
     40 // (the only non-const one) and return true to indicate success.
     41 // Please see cost_function.h for details on how the return value
     42 // maybe used to impose simple constraints on the parameter block.
     43 //
     44 // For example, consider a scalar error e = k - x'y, where both x and y are
     45 // two-dimensional column vector parameters, the prime sign indicates
     46 // transposition, and k is a constant. The form of this error, which is the
     47 // difference between a constant and an expression, is a common pattern in least
     48 // squares problems. For example, the value x'y might be the model expectation
     49 // for a series of measurements, where there is an instance of the cost function
     50 // for each measurement k.
     51 //
     52 // The actual cost added to the total problem is e^2, or (k - x'k)^2; however,
     53 // the squaring is implicitly done by the optimization framework.
     54 //
     55 // To write an numerically-differentiable cost function for the above model, first
     56 // define the object
     57 //
     58 //   class MyScalarCostFunctor {
     59 //     MyScalarCostFunctor(double k): k_(k) {}
     60 //
     61 //     bool operator()(const double* const x,
     62 //                     const double* const y,
     63 //                     double* residuals) const {
     64 //       residuals[0] = k_ - x[0] * y[0] + x[1] * y[1];
     65 //       return true;
     66 //     }
     67 //
     68 //    private:
     69 //     double k_;
     70 //   };
     71 //
     72 // Note that in the declaration of operator() the input parameters x
     73 // and y come first, and are passed as const pointers to arrays of
     74 // doubles. If there were three input parameters, then the third input
     75 // parameter would come after y. The output is always the last
     76 // parameter, and is also a pointer to an array. In the example above,
     77 // the residual is a scalar, so only residuals[0] is set.
     78 //
     79 // Then given this class definition, the numerically differentiated
     80 // cost function with central differences used for computing the
     81 // derivative can be constructed as follows.
     82 //
     83 //   CostFunction* cost_function
     84 //       = new NumericDiffCostFunction<MyScalarCostFunctor, CENTRAL, 1, 2, 2>(
     85 //           new MyScalarCostFunctor(1.0));                    ^     ^  ^  ^
     86 //                                                             |     |  |  |
     87 //                                 Finite Differencing Scheme -+     |  |  |
     88 //                                 Dimension of residual ------------+  |  |
     89 //                                 Dimension of x ----------------------+  |
     90 //                                 Dimension of y -------------------------+
     91 //
     92 // In this example, there is usually an instance for each measurement of k.
     93 //
     94 // In the instantiation above, the template parameters following
     95 // "MyScalarCostFunctor", "1, 2, 2", describe the functor as computing
     96 // a 1-dimensional output from two arguments, both 2-dimensional.
     97 //
     98 // The framework can currently accommodate cost functions of up to 10
     99 // independent variables, and there is no limit on the dimensionality
    100 // of each of them.
    101 //
    102 // The central difference method is considerably more accurate at the cost of
    103 // twice as many function evaluations than forward difference. Consider using
    104 // central differences begin with, and only after that works, trying forward
    105 // difference to improve performance.
    106 //
    107 // TODO(sameeragarwal): Add support for dynamic number of residuals.
    108 //
    109 // WARNING #1: A common beginner's error when first using
    110 // NumericDiffCostFunction is to get the sizing wrong. In particular,
    111 // there is a tendency to set the template parameters to (dimension of
    112 // residual, number of parameters) instead of passing a dimension
    113 // parameter for *every parameter*. In the example above, that would
    114 // be <MyScalarCostFunctor, 1, 2>, which is missing the last '2'
    115 // argument. Please be careful when setting the size parameters.
    116 //
    117 ////////////////////////////////////////////////////////////////////////////
    118 ////////////////////////////////////////////////////////////////////////////
    119 //
    120 // ALTERNATE INTERFACE
    121 //
    122 // For a variety of reason, including compatibility with legacy code,
    123 // NumericDiffCostFunction can also take CostFunction objects as
    124 // input. The following describes how.
    125 //
    126 // To get a numerically differentiated cost function, define a
    127 // subclass of CostFunction such that the Evaluate() function ignores
    128 // the jacobian parameter. The numeric differentiation wrapper will
    129 // fill in the jacobian parameter if necessary by repeatedly calling
    130 // the Evaluate() function with small changes to the appropriate
    131 // parameters, and computing the slope. For performance, the numeric
    132 // differentiation wrapper class is templated on the concrete cost
    133 // function, even though it could be implemented only in terms of the
    134 // virtual CostFunction interface.
    135 //
    136 // The numerically differentiated version of a cost function for a cost function
    137 // can be constructed as follows:
    138 //
    139 //   CostFunction* cost_function
    140 //       = new NumericDiffCostFunction<MyCostFunction, CENTRAL, 1, 4, 8>(
    141 //           new MyCostFunction(...), TAKE_OWNERSHIP);
    142 //
    143 // where MyCostFunction has 1 residual and 2 parameter blocks with sizes 4 and 8
    144 // respectively. Look at the tests for a more detailed example.
    145 //
    146 // TODO(keir): Characterize accuracy; mention pitfalls; provide alternatives.
    147 
    148 #ifndef CERES_PUBLIC_NUMERIC_DIFF_COST_FUNCTION_H_
    149 #define CERES_PUBLIC_NUMERIC_DIFF_COST_FUNCTION_H_
    150 
    151 #include "Eigen/Dense"
    152 #include "ceres/cost_function.h"
    153 #include "ceres/internal/numeric_diff.h"
    154 #include "ceres/internal/scoped_ptr.h"
    155 #include "ceres/sized_cost_function.h"
    156 #include "ceres/types.h"
    157 #include "glog/logging.h"
    158 
    159 namespace ceres {
    160 
    161 template <typename CostFunctor,
    162           NumericDiffMethod method = CENTRAL,
    163           int kNumResiduals = 0,  // Number of residuals, or ceres::DYNAMIC
    164           int N0 = 0,   // Number of parameters in block 0.
    165           int N1 = 0,   // Number of parameters in block 1.
    166           int N2 = 0,   // Number of parameters in block 2.
    167           int N3 = 0,   // Number of parameters in block 3.
    168           int N4 = 0,   // Number of parameters in block 4.
    169           int N5 = 0,   // Number of parameters in block 5.
    170           int N6 = 0,   // Number of parameters in block 6.
    171           int N7 = 0,   // Number of parameters in block 7.
    172           int N8 = 0,   // Number of parameters in block 8.
    173           int N9 = 0>   // Number of parameters in block 9.
    174 class NumericDiffCostFunction
    175     : public SizedCostFunction<kNumResiduals,
    176                                N0, N1, N2, N3, N4,
    177                                N5, N6, N7, N8, N9> {
    178  public:
    179   NumericDiffCostFunction(CostFunctor* functor,
    180                           const double relative_step_size = 1e-6)
    181       :functor_(functor),
    182        ownership_(TAKE_OWNERSHIP),
    183        relative_step_size_(relative_step_size) {}
    184 
    185   NumericDiffCostFunction(CostFunctor* functor,
    186                           Ownership ownership,
    187                           const double relative_step_size = 1e-6)
    188       : functor_(functor),
    189         ownership_(ownership),
    190         relative_step_size_(relative_step_size) {}
    191 
    192   ~NumericDiffCostFunction() {
    193     if (ownership_ != TAKE_OWNERSHIP) {
    194       functor_.release();
    195     }
    196   }
    197 
    198   virtual bool Evaluate(double const* const* parameters,
    199                         double* residuals,
    200                         double** jacobians) const {
    201     using internal::FixedArray;
    202     using internal::NumericDiff;
    203 
    204     const int kNumParameters = N0 + N1 + N2 + N3 + N4 + N5 + N6 + N7 + N8 + N9;
    205     const int kNumParameterBlocks =
    206         (N0 > 0) + (N1 > 0) + (N2 > 0) + (N3 > 0) + (N4 > 0) +
    207         (N5 > 0) + (N6 > 0) + (N7 > 0) + (N8 > 0) + (N9 > 0);
    208 
    209     // Get the function value (residuals) at the the point to evaluate.
    210     if (!internal::EvaluateImpl<CostFunctor,
    211                                 N0, N1, N2, N3, N4, N5, N6, N7, N8, N9>(
    212                                     functor_.get(),
    213                                     parameters,
    214                                     residuals,
    215                                     functor_.get())) {
    216       return false;
    217     }
    218 
    219     if (!jacobians) {
    220       return true;
    221     }
    222 
    223     // Create a copy of the parameters which will get mutated.
    224     FixedArray<double> parameters_copy(kNumParameters);
    225     FixedArray<double*> parameters_reference_copy(kNumParameterBlocks);
    226 
    227     parameters_reference_copy[0] = parameters_copy.get();
    228     if (N1) parameters_reference_copy[1] = parameters_reference_copy[0] + N0;
    229     if (N2) parameters_reference_copy[2] = parameters_reference_copy[1] + N1;
    230     if (N3) parameters_reference_copy[3] = parameters_reference_copy[2] + N2;
    231     if (N4) parameters_reference_copy[4] = parameters_reference_copy[3] + N3;
    232     if (N5) parameters_reference_copy[5] = parameters_reference_copy[4] + N4;
    233     if (N6) parameters_reference_copy[6] = parameters_reference_copy[5] + N5;
    234     if (N7) parameters_reference_copy[7] = parameters_reference_copy[6] + N6;
    235     if (N8) parameters_reference_copy[8] = parameters_reference_copy[7] + N7;
    236     if (N9) parameters_reference_copy[9] = parameters_reference_copy[8] + N8;
    237 
    238 #define COPY_PARAMETER_BLOCK(block)                                     \
    239   if (N ## block) memcpy(parameters_reference_copy[block],              \
    240                          parameters[block],                             \
    241                          sizeof(double) * N ## block);  // NOLINT
    242 
    243     COPY_PARAMETER_BLOCK(0);
    244     COPY_PARAMETER_BLOCK(1);
    245     COPY_PARAMETER_BLOCK(2);
    246     COPY_PARAMETER_BLOCK(3);
    247     COPY_PARAMETER_BLOCK(4);
    248     COPY_PARAMETER_BLOCK(5);
    249     COPY_PARAMETER_BLOCK(6);
    250     COPY_PARAMETER_BLOCK(7);
    251     COPY_PARAMETER_BLOCK(8);
    252     COPY_PARAMETER_BLOCK(9);
    253 
    254 #undef COPY_PARAMETER_BLOCK
    255 
    256 #define EVALUATE_JACOBIAN_FOR_BLOCK(block)                              \
    257     if (N ## block && jacobians[block] != NULL) {                       \
    258       if (!NumericDiff<CostFunctor,                                     \
    259                        method,                                          \
    260                        kNumResiduals,                                   \
    261                        N0, N1, N2, N3, N4, N5, N6, N7, N8, N9,          \
    262                        block,                                           \
    263                        N ## block >::EvaluateJacobianForParameterBlock( \
    264                            functor_.get(),                              \
    265                            residuals,                                   \
    266                            relative_step_size_,                         \
    267                            parameters_reference_copy.get(),             \
    268                            jacobians[block])) {                         \
    269         return false;                                                   \
    270       }                                                                 \
    271     }
    272 
    273     EVALUATE_JACOBIAN_FOR_BLOCK(0);
    274     EVALUATE_JACOBIAN_FOR_BLOCK(1);
    275     EVALUATE_JACOBIAN_FOR_BLOCK(2);
    276     EVALUATE_JACOBIAN_FOR_BLOCK(3);
    277     EVALUATE_JACOBIAN_FOR_BLOCK(4);
    278     EVALUATE_JACOBIAN_FOR_BLOCK(5);
    279     EVALUATE_JACOBIAN_FOR_BLOCK(6);
    280     EVALUATE_JACOBIAN_FOR_BLOCK(7);
    281     EVALUATE_JACOBIAN_FOR_BLOCK(8);
    282     EVALUATE_JACOBIAN_FOR_BLOCK(9);
    283 
    284 #undef EVALUATE_JACOBIAN_FOR_BLOCK
    285 
    286     return true;
    287   }
    288 
    289  private:
    290   internal::scoped_ptr<CostFunctor> functor_;
    291   Ownership ownership_;
    292   const double relative_step_size_;
    293 };
    294 
    295 }  // namespace ceres
    296 
    297 #endif  // CERES_PUBLIC_NUMERIC_DIFF_COST_FUNCTION_H_
    298