mirror of
https://github.com/ceres-solver/ceres-solver.git
synced 2026-08-29 16:40:38 +08:00
Simplify instantiation of cost functions and their functors
If arguments are passed to a cost function that can be used to construct the functor, the latter will be instantiated by the cost function using std::make_unique to ensure exception safety. This not only avoids static analysis warnings caused by calling new but also spelling the cost functor type name multiple times. Also expand deduction guides for instantiating Dynamic(Auto|Numeric)DiffCostFunction from std::unique_ptr enabled constructor overloads. Finally, make CostFunction default move constructible and assignable but only through derived classes. This in turn allows derived classes to be movable without relying on custom implementations of corresponding operators. Change-Id: Idee8b9871d862bc9f9f8b5a8d0bedc52863e93c0
This commit is contained in:
@@ -37,9 +37,7 @@ implements an automatically differentiated ``CostFunction`` for `Rat43
|
||||
};
|
||||
|
||||
|
||||
CostFunction* cost_function =
|
||||
new AutoDiffCostFunction<Rat43CostFunctor, 1, 4>(
|
||||
new Rat43CostFunctor(x, y));
|
||||
auto* cost_function = new AutoDiffCostFunction<Rat43CostFunctor, 1, 4>(x, y);
|
||||
|
||||
Notice that compared to numeric differentiation, the only difference
|
||||
when defining the functor for use with automatic differentiation is
|
||||
|
||||
@@ -47,8 +47,7 @@ in Ceres.
|
||||
|
||||
static ceres::FirstOrderFunction* Create() {
|
||||
constexpr int kNumParameters = 2;
|
||||
return new ceres::AutoDiffFirstOrderFunction<Rosenbrock, kNumParameters>(
|
||||
new Rosenbrock);
|
||||
return new ceres::AutoDiffFirstOrderFunction<Rosenbrock, kNumParameters>();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -161,8 +160,7 @@ follows [#f2]_.
|
||||
constexpr int kNumParameters = 2;
|
||||
return new ceres::NumericDiffFirstOrderFunction<Rosenbrock,
|
||||
ceres::CENTRAL,
|
||||
kNumParameters>(
|
||||
new Rosenbrock);
|
||||
kNumParameters>();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -177,8 +175,6 @@ non-linear least squares problems [#f3]_.
|
||||
// f(x,y) = (1-x)^2 + 100(y - x^2)^2;
|
||||
class Rosenbrock final : public ceres::FirstOrderFunction {
|
||||
public:
|
||||
~Rosenbrock() override {}
|
||||
|
||||
bool Evaluate(const double* parameters,
|
||||
double* cost,
|
||||
double* gradient) const override {
|
||||
|
||||
@@ -118,12 +118,13 @@ An implementation of the above three steps looks as follows:
|
||||
y[0] = y_in[0];
|
||||
y[1] = y_in[1];
|
||||
|
||||
compute_distortion.reset(new ceres::CostFunctionToFunctor<1, 1>(
|
||||
new ceres::NumericDiffCostFunction<ComputeDistortionValueFunctor,
|
||||
ceres::CENTRAL,
|
||||
1,
|
||||
1>(
|
||||
new ComputeDistortionValueFunctor)));
|
||||
compute_distortion = std::make_unique<ceres::CostFunctionToFunctor<1, 1>>(
|
||||
std::make_unique<ceres::NumericDiffCostFunction<
|
||||
ComputeDistortionValueFunctor
|
||||
, ceres::CENTRAL, 1, 1
|
||||
>
|
||||
>()
|
||||
);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@@ -140,7 +141,7 @@ An implementation of the above three steps looks as follows:
|
||||
|
||||
double x[2];
|
||||
double y[2];
|
||||
std::unique_ptr<ceres::CostFunctionToFunctor<1, 1> > compute_distortion;
|
||||
std::unique_ptr<ceres::CostFunctionToFunctor<1, 1>> compute_distortion;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -181,12 +181,19 @@ the corresponding accessors. This information will be verified by the
|
||||
class AutoDiffCostFunction : public
|
||||
SizedCostFunction<kNumResiduals, Ns> {
|
||||
public:
|
||||
AutoDiffCostFunction(CostFunctor* functor, ownership = TAKE_OWNERSHIP);
|
||||
// Instantiate CostFunctor using the supplied arguments.
|
||||
template<class ...Args>
|
||||
explicit AutoDiffCostFunction(Args&& ...args);
|
||||
explicit AutoDiffCostFunction(std::unique_ptr<CostFunctor> functor);
|
||||
explicit AutoDiffCostFunction(CostFunctor* functor, ownership = TAKE_OWNERSHIP);
|
||||
|
||||
// Ignore the template parameter kNumResiduals and use
|
||||
// num_residuals instead.
|
||||
AutoDiffCostFunction(CostFunctor* functor,
|
||||
int num_residuals,
|
||||
ownership = TAKE_OWNERSHIP);
|
||||
AutoDiffCostFunction(std::unique_ptr<CostFunctor> functor,
|
||||
int num_residuals);
|
||||
};
|
||||
|
||||
To get an auto differentiated cost function, you must define a
|
||||
@@ -244,9 +251,9 @@ the corresponding accessors. This information will be verified by the
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
CostFunction* cost_function
|
||||
= new AutoDiffCostFunction<MyScalarCostFunctor, 1, 2, 2>(
|
||||
new MyScalarCostFunctor(1.0)); ^ ^ ^
|
||||
auto* cost_function
|
||||
= new AutoDiffCostFunction<MyScalarCostFunctor, 1, 2, 2>(1.0);
|
||||
^ ^ ^
|
||||
| | |
|
||||
Dimension of residual ------+ | |
|
||||
Dimension of x ----------------+ |
|
||||
@@ -272,7 +279,7 @@ the corresponding accessors. This information will be verified by the
|
||||
.. code-block:: c++
|
||||
|
||||
MyScalarCostFunctor functor(1.0)
|
||||
CostFunction* cost_function
|
||||
auto* cost_function
|
||||
= new AutoDiffCostFunction<MyScalarCostFunctor, 1, 2, 2>(
|
||||
&functor, DO_NOT_TAKE_OWNERSHIP);
|
||||
|
||||
@@ -281,9 +288,11 @@ the corresponding accessors. This information will be verified by the
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
CostFunction* cost_function
|
||||
= new AutoDiffCostFunction<MyScalarCostFunctor, DYNAMIC, 2, 2>(
|
||||
new CostFunctorWithDynamicNumResiduals(1.0), ^ ^ ^
|
||||
auto functor = std::make_unique<CostFunctorWithDynamicNumResiduals>(1.0);
|
||||
auto* cost_function
|
||||
= new AutoDiffCostFunction<CostFunctorWithDynamicNumResiduals,
|
||||
DYNAMIC, 2, 2>(
|
||||
std::move(functor), ^ ^ ^
|
||||
runtime_number_of_residuals); <----+ | | |
|
||||
| | | |
|
||||
| | | |
|
||||
@@ -336,9 +345,7 @@ the corresponding accessors. This information will be verified by the
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
DynamicAutoDiffCostFunction<MyCostFunctor, 4>* cost_function =
|
||||
new DynamicAutoDiffCostFunction<MyCostFunctor, 4>(
|
||||
new MyCostFunctor());
|
||||
auto* cost_function = new DynamicAutoDiffCostFunction<MyCostFunctor, 4>();
|
||||
cost_function->AddParameterBlock(5);
|
||||
cost_function->AddParameterBlock(10);
|
||||
cost_function->SetNumResiduals(21);
|
||||
@@ -443,9 +450,9 @@ the corresponding accessors. This information will be verified by the
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
CostFunction* cost_function
|
||||
= new NumericDiffCostFunction<MyScalarCostFunctor, CENTRAL, 1, 2, 2>(
|
||||
new MyScalarCostFunctor(1.0)); ^ ^ ^ ^
|
||||
auto* cost_function
|
||||
= new NumericDiffCostFunction<MyScalarCostFunctor, CENTRAL, 1, 2, 2>(1.0)
|
||||
^ ^ ^ ^
|
||||
| | | |
|
||||
Finite Differencing Scheme -+ | | |
|
||||
Dimension of residual ------------+ | |
|
||||
@@ -465,17 +472,18 @@ the corresponding accessors. This information will be verified by the
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
CostFunction* cost_function
|
||||
= new NumericDiffCostFunction<MyScalarCostFunctor, CENTRAL, DYNAMIC, 2, 2>(
|
||||
new CostFunctorWithDynamicNumResiduals(1.0), ^ ^ ^
|
||||
TAKE_OWNERSHIP, | | |
|
||||
runtime_number_of_residuals); <----+ | | |
|
||||
| | | |
|
||||
| | | |
|
||||
Actual number of residuals ------+ | | |
|
||||
Indicate dynamic number of residuals --------------------+ | |
|
||||
Dimension of x ------------------------------------------------+ |
|
||||
Dimension of y ---------------------------------------------------+
|
||||
auto functor = std::make_unique<CostFunctorWithDynamicNumResiduals>(1.0);
|
||||
auto* cost_function
|
||||
= new NumericDiffCostFunction<CostFunctorWithDynamicNumResiduals,
|
||||
CENTRAL, DYNAMIC, 2, 2>(
|
||||
std::move(functor), ^ ^ ^
|
||||
runtime_number_of_residuals); <----+ | | |
|
||||
| | | |
|
||||
| | | |
|
||||
Actual number of residuals ------+ | | |
|
||||
Indicate dynamic number of residuals --------+ | |
|
||||
Dimension of x ------------------------------------+ |
|
||||
Dimension of y ---------------------------------------+
|
||||
|
||||
|
||||
There are three available numeric differentiation schemes in ceres-solver:
|
||||
@@ -569,9 +577,8 @@ Numeric Differentiation & Manifolds
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
CostFunction* cost_function
|
||||
= new NumericDiffCostFunction<MyCostFunction, CENTRAL, 1, 4, 8>(
|
||||
new MyCostFunction(...), TAKE_OWNERSHIP);
|
||||
auto* cost_function
|
||||
= new NumericDiffCostFunction<MyCostFunction, CENTRAL, 1, 4, 8>(...);
|
||||
|
||||
where ``MyCostFunction`` has 1 residual and 2 parameter blocks with
|
||||
sizes 4 and 8 respectively. Look at the tests for a more detailed
|
||||
@@ -612,8 +619,7 @@ Numeric Differentiation & Manifolds
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
DynamicNumericDiffCostFunction<MyCostFunctor>* cost_function =
|
||||
new DynamicNumericDiffCostFunction<MyCostFunctor>(new MyCostFunctor);
|
||||
auto cost_function = std::make_unique<DynamicNumericDiffCostFunction<MyCostFunctor>>();
|
||||
cost_function->AddParameterBlock(5);
|
||||
cost_function->AddParameterBlock(10);
|
||||
cost_function->SetNumResiduals(21);
|
||||
@@ -672,8 +678,8 @@ Numeric Differentiation & Manifolds
|
||||
.. code-block:: c++
|
||||
|
||||
struct CameraProjection {
|
||||
CameraProjection(double* observation)
|
||||
: intrinsic_projection_(new IntrinsicProjection(observation)) {
|
||||
explicit CameraProjection(double* observation)
|
||||
: intrinsic_projection_(std::make_unique<IntrinsicProjection>(observation)) {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@@ -691,7 +697,7 @@ Numeric Differentiation & Manifolds
|
||||
}
|
||||
|
||||
private:
|
||||
CostFunctionToFunctor<2,5,3> intrinsic_projection_;
|
||||
CostFunctionToFunctor<2, 5, 3> intrinsic_projection_;
|
||||
};
|
||||
|
||||
Note that :class:`CostFunctionToFunctor` takes ownership of the
|
||||
@@ -733,10 +739,9 @@ Numeric Differentiation & Manifolds
|
||||
.. code-block:: c++
|
||||
|
||||
struct CameraProjection {
|
||||
CameraProjection(double* observation)
|
||||
explicit CameraProjection(double* observation)
|
||||
: intrinsic_projection_(
|
||||
new NumericDiffCostFunction<IntrinsicProjection, CENTRAL, 2, 5, 3>(
|
||||
new IntrinsicProjection(observation))) {}
|
||||
std::make_unique<NumericDiffCostFunction<IntrinsicProjection, CENTRAL, 2, 5, 3>>()) {}
|
||||
|
||||
template <typename T>
|
||||
bool operator()(const T* rotation,
|
||||
@@ -794,8 +799,8 @@ Numeric Differentiation & Manifolds
|
||||
.. code-block:: c++
|
||||
|
||||
struct CameraProjection {
|
||||
CameraProjection(double* observation)
|
||||
: intrinsic_projection_(new IntrinsicProjection(observation)) {
|
||||
explicit CameraProjection(double* observation)
|
||||
: intrinsic_projection_(std::make_unique<IntrinsicProjection>(observation)) {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@@ -1122,9 +1127,8 @@ their shape graphically. More details can be found in
|
||||
|
||||
// Add parameter blocks
|
||||
|
||||
CostFunction* cost_function =
|
||||
new AutoDiffCostFunction < UW_Camera_Mapper, 2, 9, 3>(
|
||||
new UW_Camera_Mapper(feature_x, feature_y));
|
||||
auto* cost_function =
|
||||
new AutoDiffCostFunction<UW_Camera_Mapper, 2, 9, 3>(feature_x, feature_y);
|
||||
|
||||
LossFunctionWrapper* loss_function(new HuberLoss(1.0), TAKE_OWNERSHIP);
|
||||
problem.AddResidualBlock(cost_function, loss_function, parameters);
|
||||
@@ -1556,8 +1560,8 @@ In advanced use cases, manifolds can be dynamically allocated and passed as (sma
|
||||
ProductManifold<std::unique_ptr<QuaternionManifold>, EuclideanManifold<3>> se3
|
||||
{std::make_unique<QuaternionManifold>(), EuclideanManifold<3>{}};
|
||||
|
||||
In C++17, the template parameters can be left out as they are automatically
|
||||
deduced making the initialization much simpler:
|
||||
The template parameters can also be left out as they are deduced automatically
|
||||
making the initialization much simpler:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
|
||||
@@ -112,7 +112,7 @@ Ceres solve it.
|
||||
// Set up the only cost function (also known as residual). This uses
|
||||
// auto-differentiation to obtain the derivative (jacobian).
|
||||
CostFunction* cost_function =
|
||||
new AutoDiffCostFunction<CostFunctor, 1, 1>(new CostFunctor);
|
||||
new AutoDiffCostFunction<CostFunctor, 1, 1>();
|
||||
problem.AddResidualBlock(cost_function, nullptr, &x);
|
||||
|
||||
// Run the solver!
|
||||
@@ -212,8 +212,7 @@ Which is added to the :class:`Problem` as:
|
||||
.. code-block:: c++
|
||||
|
||||
CostFunction* cost_function =
|
||||
new NumericDiffCostFunction<NumericDiffCostFunctor, ceres::CENTRAL, 1, 1>(
|
||||
new NumericDiffCostFunctor);
|
||||
new NumericDiffCostFunction<NumericDiffCostFunctor, ceres::CENTRAL, 1, 1>();
|
||||
problem.AddResidualBlock(cost_function, nullptr, &x);
|
||||
|
||||
Notice the parallel from when we were using automatic differentiation
|
||||
@@ -221,7 +220,7 @@ Notice the parallel from when we were using automatic differentiation
|
||||
.. code-block:: c++
|
||||
|
||||
CostFunction* cost_function =
|
||||
new AutoDiffCostFunction<CostFunctor, 1, 1>(new CostFunctor);
|
||||
new AutoDiffCostFunction<CostFunctor, 1, 1>();
|
||||
problem.AddResidualBlock(cost_function, nullptr, &x);
|
||||
|
||||
The construction looks almost identical to the one used for automatic
|
||||
@@ -360,13 +359,13 @@ respectively. Using these, the problem can be constructed as follows:
|
||||
// Add residual terms to the problem using the autodiff
|
||||
// wrapper to get the derivatives automatically.
|
||||
problem.AddResidualBlock(
|
||||
new AutoDiffCostFunction<F1, 1, 1, 1>(new F1), nullptr, &x1, &x2);
|
||||
new AutoDiffCostFunction<F1, 1, 1, 1>(), nullptr, &x1, &x2);
|
||||
problem.AddResidualBlock(
|
||||
new AutoDiffCostFunction<F2, 1, 1, 1>(new F2), nullptr, &x3, &x4);
|
||||
new AutoDiffCostFunction<F2, 1, 1, 1>(), nullptr, &x3, &x4);
|
||||
problem.AddResidualBlock(
|
||||
new AutoDiffCostFunction<F3, 1, 1, 1>(new F3), nullptr, &x2, &x3);
|
||||
new AutoDiffCostFunction<F3, 1, 1, 1>(), nullptr, &x2, &x3);
|
||||
problem.AddResidualBlock(
|
||||
new AutoDiffCostFunction<F4, 1, 1, 1>(new F4), nullptr, &x1, &x4);
|
||||
new AutoDiffCostFunction<F4, 1, 1, 1>(), nullptr, &x1, &x4);
|
||||
|
||||
|
||||
Note that each ``ResidualBlock`` only depends on the two parameters
|
||||
@@ -499,8 +498,8 @@ Assuming the observations are in a :math:`2n` sized array called
|
||||
Problem problem;
|
||||
for (int i = 0; i < kNumObservations; ++i) {
|
||||
CostFunction* cost_function =
|
||||
new AutoDiffCostFunction<ExponentialResidual, 1, 1, 1>(
|
||||
new ExponentialResidual(data[2 * i], data[2 * i + 1]));
|
||||
new AutoDiffCostFunction<ExponentialResidual, 1, 1, 1>
|
||||
(data[2 * i], data[2 * i + 1]);
|
||||
problem.AddResidualBlock(cost_function, nullptr, &m, &c);
|
||||
}
|
||||
|
||||
@@ -675,8 +674,8 @@ The details of this camera model can be found the `Bundler homepage
|
||||
// the client code.
|
||||
static ceres::CostFunction* Create(const double observed_x,
|
||||
const double observed_y) {
|
||||
return (new ceres::AutoDiffCostFunction<SnavelyReprojectionError, 2, 9, 3>(
|
||||
new SnavelyReprojectionError(observed_x, observed_y)));
|
||||
return new ceres::AutoDiffCostFunction<SnavelyReprojectionError, 2, 9, 3>
|
||||
(observed_x, observed_y);
|
||||
}
|
||||
|
||||
double observed_x;
|
||||
|
||||
@@ -61,8 +61,7 @@ Ceres Solver. This is done in two steps:
|
||||
}
|
||||
|
||||
CostFunction* cost_function =
|
||||
new NumericDiffCostFunction<Rat43CostFunctor, FORWARD, 1, 4>(
|
||||
new Rat43CostFunctor(x, y));
|
||||
new NumericDiffCostFunction<Rat43CostFunctor, FORWARD, 1, 4>(x, y);
|
||||
|
||||
This is about the minimum amount of work one can expect to do to
|
||||
define the cost function. The only thing that the user needs to do is
|
||||
|
||||
Reference in New Issue
Block a user