Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'extern/ceres/include/ceres/problem.h')
-rw-r--r--extern/ceres/include/ceres/problem.h235
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