diff options
Diffstat (limited to 'extern/ceres/include/ceres/problem.h')
-rw-r--r-- | extern/ceres/include/ceres/problem.h | 235 |
1 files changed, 143 insertions, 92 deletions
diff --git a/extern/ceres/include/ceres/problem.h b/extern/ceres/include/ceres/problem.h index 27ed4ef15da..88f99663f65 100644 --- a/extern/ceres/include/ceres/problem.h +++ b/extern/ceres/include/ceres/problem.h @@ -34,22 +34,23 @@ #ifndef CERES_PUBLIC_PROBLEM_H_ #define CERES_PUBLIC_PROBLEM_H_ +#include <array> #include <cstddef> #include <map> +#include <memory> #include <set> #include <vector> -#include "glog/logging.h" -#include "ceres/internal/macros.h" +#include "ceres/context.h" +#include "ceres/internal/disable_warnings.h" #include "ceres/internal/port.h" -#include "ceres/internal/scoped_ptr.h" #include "ceres/types.h" -#include "ceres/internal/disable_warnings.h" - +#include "glog/logging.h" namespace ceres { class CostFunction; +class EvaluationCallback; class LossFunction; class LocalParameterization; class Solver; @@ -114,20 +115,13 @@ typedef internal::ResidualBlock* ResidualBlockId; // // Problem problem; // -// problem.AddResidualBlock(new MyUnaryCostFunction(...), x1); -// problem.AddResidualBlock(new MyBinaryCostFunction(...), x2, x3); +// problem.AddResidualBlock(new MyUnaryCostFunction(...), nullptr, x1); +// problem.AddResidualBlock(new MyBinaryCostFunction(...), nullptr, x2, x3); // // Please see cost_function.h for details of the CostFunction object. class CERES_EXPORT Problem { public: struct CERES_EXPORT Options { - Options() - : cost_function_ownership(TAKE_OWNERSHIP), - loss_function_ownership(TAKE_OWNERSHIP), - local_parameterization_ownership(TAKE_OWNERSHIP), - enable_fast_removal(false), - disable_all_safety_checks(false) {} - // These flags control whether the Problem object owns the cost // functions, loss functions, and parameterizations passed into // the Problem. If set to TAKE_OWNERSHIP, then the problem object @@ -135,25 +129,25 @@ class CERES_EXPORT Problem { // destruction. The destructor is careful to delete the pointers // only once, since sharing cost/loss/parameterizations is // allowed. - Ownership cost_function_ownership; - Ownership loss_function_ownership; - Ownership local_parameterization_ownership; + Ownership cost_function_ownership = TAKE_OWNERSHIP; + Ownership loss_function_ownership = TAKE_OWNERSHIP; + Ownership local_parameterization_ownership = TAKE_OWNERSHIP; // If true, trades memory for faster RemoveResidualBlock() and // RemoveParameterBlock() operations. // // By default, RemoveParameterBlock() and RemoveResidualBlock() take time // proportional to the size of the entire problem. If you only ever remove - // parameters or residuals from the problem occassionally, this might be + // parameters or residuals from the problem occasionally, this might be // acceptable. However, if you have memory to spare, enable this option to // make RemoveParameterBlock() take time proportional to the number of // residual blocks that depend on it, and RemoveResidualBlock() take (on // average) constant time. // - // The increase in memory usage is twofold: an additonal hash set per + // The increase in memory usage is twofold: an additional hash set per // parameter block containing all the residuals that depend on the parameter // block; and a hash set in the problem containing all residuals. - bool enable_fast_removal; + bool enable_fast_removal = false; // By default, Ceres performs a variety of safety checks when constructing // the problem. There is a small but measurable performance penalty to @@ -164,22 +158,51 @@ class CERES_EXPORT Problem { // // WARNING: Do not set this to true, unless you are absolutely sure of what // you are doing. - bool disable_all_safety_checks; + bool disable_all_safety_checks = false; + + // A Ceres global context to use for solving this problem. This may help to + // reduce computation time as Ceres can reuse expensive objects to create. + // The context object can be nullptr, in which case Ceres may create one. + // + // Ceres does NOT take ownership of the pointer. + Context* context = nullptr; + + // Using this callback interface, Ceres can notify you when it is + // about to evaluate the residuals or jacobians. With the + // callback, you can share computation between residual blocks by + // doing the shared computation in + // EvaluationCallback::PrepareForEvaluation() before Ceres calls + // CostFunction::Evaluate(). It also enables caching results + // between a pure residual evaluation and a residual & jacobian + // evaluation. + // + // Problem DOES NOT take ownership of the callback. + // + // NOTE: Evaluation callbacks are incompatible with inner + // iterations. So calling Solve with + // Solver::Options::use_inner_iterations = true on a Problem with + // a non-null evaluation callback is an error. + EvaluationCallback* evaluation_callback = nullptr; }; // The default constructor is equivalent to the // invocation Problem(Problem::Options()). Problem(); explicit Problem(const Options& options); + Problem(Problem&&); + Problem& operator=(Problem&&); + + Problem(const Problem&) = delete; + Problem& operator=(const Problem&) = delete; ~Problem(); // Add a residual block to the overall cost function. The cost - // function carries with it information about the sizes of the + // function carries with its information about the sizes of the // parameter blocks it expects. The function checks that these match // the sizes of the parameter blocks listed in parameter_blocks. The // program aborts if a mismatch is detected. loss_function can be - // NULL, in which case the cost of the term is just the squared norm + // nullptr, in which case the cost of the term is just the squared norm // of the residuals. // // The user has the option of explicitly adding the parameter blocks @@ -208,59 +231,35 @@ class CERES_EXPORT Problem { // // Problem problem; // - // problem.AddResidualBlock(new MyUnaryCostFunction(...), NULL, x1); - // problem.AddResidualBlock(new MyBinaryCostFunction(...), NULL, x2, x1); + // problem.AddResidualBlock(new MyUnaryCostFunction(...), nullptr, x1); + // problem.AddResidualBlock(new MyBinaryCostFunction(...), nullptr, x2, x1); // + // Add a residual block by listing the parameter block pointers + // directly instead of wapping them in a container. + template <typename... Ts> + ResidualBlockId AddResidualBlock(CostFunction* cost_function, + LossFunction* loss_function, + double* x0, + Ts*... xs) { + const std::array<double*, sizeof...(Ts) + 1> parameter_blocks{{x0, xs...}}; + return AddResidualBlock(cost_function, + loss_function, + parameter_blocks.data(), + static_cast<int>(parameter_blocks.size())); + } + + // Add a residual block by providing a vector of parameter blocks. ResidualBlockId AddResidualBlock( CostFunction* cost_function, LossFunction* loss_function, const std::vector<double*>& parameter_blocks); - // Convenience methods for adding residuals with a small number of - // parameters. This is the common case. Instead of specifying the - // parameter block arguments as a vector, list them as pointers. - ResidualBlockId AddResidualBlock(CostFunction* cost_function, - LossFunction* loss_function, - double* x0); - ResidualBlockId AddResidualBlock(CostFunction* cost_function, - LossFunction* loss_function, - double* x0, double* x1); + // Add a residual block by providing a pointer to the parameter block array + // and the number of parameter blocks. ResidualBlockId AddResidualBlock(CostFunction* cost_function, LossFunction* loss_function, - double* x0, double* x1, double* x2); - ResidualBlockId AddResidualBlock(CostFunction* cost_function, - LossFunction* loss_function, - double* x0, double* x1, double* x2, - double* x3); - ResidualBlockId AddResidualBlock(CostFunction* cost_function, - LossFunction* loss_function, - double* x0, double* x1, double* x2, - double* x3, double* x4); - ResidualBlockId AddResidualBlock(CostFunction* cost_function, - LossFunction* loss_function, - double* x0, double* x1, double* x2, - double* x3, double* x4, double* x5); - ResidualBlockId AddResidualBlock(CostFunction* cost_function, - LossFunction* loss_function, - double* x0, double* x1, double* x2, - double* x3, double* x4, double* x5, - double* x6); - ResidualBlockId AddResidualBlock(CostFunction* cost_function, - LossFunction* loss_function, - double* x0, double* x1, double* x2, - double* x3, double* x4, double* x5, - double* x6, double* x7); - ResidualBlockId AddResidualBlock(CostFunction* cost_function, - LossFunction* loss_function, - double* x0, double* x1, double* x2, - double* x3, double* x4, double* x5, - double* x6, double* x7, double* x8); - ResidualBlockId AddResidualBlock(CostFunction* cost_function, - LossFunction* loss_function, - double* x0, double* x1, double* x2, - double* x3, double* x4, double* x5, - double* x6, double* x7, double* x8, - double* x9); + double* const* const parameter_blocks, + int num_parameter_blocks); // Add a parameter block with appropriate size to the problem. // Repeated calls with the same arguments are ignored. Repeated @@ -290,7 +289,7 @@ class CERES_EXPORT Problem { // ordering, rendering the jacobian or residuals returned from the solver // uninterpretable. If you depend on the evaluated jacobian, do not use // remove! This may change in a future release. - void RemoveParameterBlock(double* values); + void RemoveParameterBlock(const double* values); // Remove a residual block from the problem. Any parameters that the residual // block depends on are not removed. The cost and loss functions for the @@ -304,32 +303,43 @@ class CERES_EXPORT Problem { void RemoveResidualBlock(ResidualBlockId residual_block); // Hold the indicated parameter block constant during optimization. - void SetParameterBlockConstant(double* values); + void SetParameterBlockConstant(const double* values); // Allow the indicated parameter block to vary during optimization. void SetParameterBlockVariable(double* values); - // Returns true if a parameter block is set constant, and false otherwise. - bool IsParameterBlockConstant(double* values) const; + // Returns true if a parameter block is set constant, and false + // otherwise. A parameter block may be set constant in two ways: + // either by calling SetParameterBlockConstant or by associating a + // LocalParameterization with a zero dimensional tangent space with + // it. + bool IsParameterBlockConstant(const double* values) const; // Set the local parameterization for one of the parameter blocks. // The local_parameterization is owned by the Problem by default. It // is acceptable to set the same parameterization for multiple // parameters; the destructor is careful to delete local - // parameterizations only once. The local parameterization can only - // be set once per parameter, and cannot be changed once set. + // parameterizations only once. Calling SetParameterization with + // nullptr will clear any previously set parameterization. void SetParameterization(double* values, LocalParameterization* local_parameterization); // Get the local parameterization object associated with this // parameter block. If there is no parameterization object - // associated then NULL is returned. - const LocalParameterization* GetParameterization(double* values) const; + // associated then nullptr is returned. + const LocalParameterization* GetParameterization(const double* values) const; - // Set the lower/upper bound for the parameter with position "index". + // Set the lower/upper bound for the parameter at position "index". void SetParameterLowerBound(double* values, int index, double lower_bound); void SetParameterUpperBound(double* values, int index, double upper_bound); + // Get the lower/upper bound for the parameter at position + // "index". If the parameter is not bounded by the user, then its + // lower bound is -std::numeric_limits<double>::max() and upper + // bound is std::numeric_limits<double>::max(). + double GetParameterLowerBound(const double* values, int index) const; + double GetParameterUpperBound(const double* values, int index) const; + // Number of parameter blocks in the problem. Always equals // parameter_blocks().size() and parameter_block_sizes().size(). int NumParameterBlocks() const; @@ -376,7 +386,7 @@ class CERES_EXPORT Problem { const CostFunction* GetCostFunctionForResidualBlock( const ResidualBlockId residual_block) const; - // Get the LossFunction for the given residual block. Returns NULL + // Get the LossFunction for the given residual block. Returns nullptr // if no loss function is associated with this residual block. const LossFunction* GetLossFunctionForResidualBlock( const ResidualBlockId residual_block) const; @@ -393,11 +403,6 @@ class CERES_EXPORT Problem { // Options struct to control Problem::Evaluate. struct EvaluateOptions { - EvaluateOptions() - : apply_loss_function(true), - num_threads(1) { - } - // The set of parameter blocks for which evaluation should be // performed. This vector determines the order that parameter // blocks occur in the gradient vector and in the columns of the @@ -430,12 +435,12 @@ class CERES_EXPORT Problem { // function. This is of use for example if the user wishes to // analyse the solution quality by studying the distribution of // residuals before and after the solve. - bool apply_loss_function; + bool apply_loss_function = true; - int num_threads; + int num_threads = 1; }; - // Evaluate Problem. Any of the output pointers can be NULL. Which + // Evaluate Problem. Any of the output pointers can be nullptr. Which // residual blocks and parameter blocks are used is controlled by // the EvaluateOptions struct above. // @@ -445,16 +450,16 @@ class CERES_EXPORT Problem { // // Problem problem; // double x = 1; - // problem.AddResidualBlock(new MyCostFunction, NULL, &x); + // problem.AddResidualBlock(new MyCostFunction, nullptr, &x); // // double cost = 0.0; - // problem.Evaluate(Problem::EvaluateOptions(), &cost, NULL, NULL, NULL); + // problem.Evaluate(Problem::EvaluateOptions(), &cost, nullptr, nullptr, nullptr); // // The cost is evaluated at x = 1. If you wish to evaluate the // problem at x = 2, then // - // x = 2; - // problem.Evaluate(Problem::EvaluateOptions(), &cost, NULL, NULL, NULL); + // x = 2; + // problem.Evaluate(Problem::EvaluateOptions(), &cost, nullptr, nullptr, nullptr); // // is the way to do so. // @@ -468,17 +473,63 @@ class CERES_EXPORT Problem { // Note 3: This function cannot be called while the problem is being // solved, for example it cannot be called from an IterationCallback // at the end of an iteration during a solve. + // + // Note 4: If an EvaluationCallback is associated with the problem, + // then its PrepareForEvaluation method will be called everytime + // this method is called with new_point = true. bool Evaluate(const EvaluateOptions& options, double* cost, std::vector<double>* residuals, std::vector<double>* gradient, CRSMatrix* jacobian); + // Evaluates the residual block, storing the scalar cost in *cost, + // the residual components in *residuals, and the jacobians between + // the parameters and residuals in jacobians[i], in row-major order. + // + // If residuals is nullptr, the residuals are not computed. + // + // If jacobians is nullptr, no Jacobians are computed. If + // jacobians[i] is nullptr, then the Jacobian for that parameter + // block is not computed. + // + // It is not okay to request the Jacobian w.r.t a parameter block + // that is constant. + // + // The return value indicates the success or failure. Even if the + // function returns false, the caller should expect the output + // memory locations to have been modified. + // + // The returned cost and jacobians have had robustification and + // local parameterizations applied already; for example, the + // jacobian for a 4-dimensional quaternion parameter using the + // "QuaternionParameterization" is num_residuals by 3 instead of + // num_residuals by 4. + // + // apply_loss_function as the name implies allows the user to switch + // the application of the loss function on and off. + // + // WARNING: If an EvaluationCallback is associated with the problem + // then it is the user's responsibility to call it before calling + // this method. + // + // This is because, if the user calls this method multiple times, we + // cannot tell if the underlying parameter blocks have changed + // between calls or not. So if EvaluateResidualBlock was responsible + // for calling the EvaluationCallback, it will have to do it + // everytime it is called. Which makes the common case where the + // parameter blocks do not change, inefficient. So we leave it to + // the user to call the EvaluationCallback as needed. + bool EvaluateResidualBlock(ResidualBlockId residual_block_id, + bool apply_loss_function, + double* cost, + double* residuals, + double** jacobians) const; + private: friend class Solver; friend class Covariance; - internal::scoped_ptr<internal::ProblemImpl> problem_impl_; - CERES_DISALLOW_COPY_AND_ASSIGN(Problem); + std::unique_ptr<internal::ProblemImpl> impl_; }; } // namespace ceres |