|
Packit |
ea1746 |
.. _chapter-modeling_faqs:
|
|
Packit |
ea1746 |
|
|
Packit |
ea1746 |
.. default-domain:: cpp
|
|
Packit |
ea1746 |
|
|
Packit |
ea1746 |
.. cpp:namespace:: ceres
|
|
Packit |
ea1746 |
|
|
Packit |
ea1746 |
========
|
|
Packit |
ea1746 |
Modeling
|
|
Packit |
ea1746 |
========
|
|
Packit |
ea1746 |
|
|
Packit |
ea1746 |
#. Use analytical/automatic derivatives.
|
|
Packit |
ea1746 |
|
|
Packit |
ea1746 |
This is the single most important piece of advice we can give to
|
|
Packit |
ea1746 |
you. It is tempting to take the easy way out and use numeric
|
|
Packit |
ea1746 |
differentiation. This is a bad idea. Numeric differentiation is
|
|
Packit |
ea1746 |
slow, ill-behaved, hard to get right, and results in poor
|
|
Packit |
ea1746 |
convergence behaviour.
|
|
Packit |
ea1746 |
|
|
Packit |
ea1746 |
Ceres allows the user to define templated functors which will
|
|
Packit |
ea1746 |
be automatically differentiated. For most situations this is enough
|
|
Packit |
ea1746 |
and we recommend using this facility. In some cases the derivatives
|
|
Packit |
ea1746 |
are simple enough or the performance considerations are such that
|
|
Packit |
ea1746 |
the overhead of automatic differentiation is too much. In such
|
|
Packit |
ea1746 |
cases, analytic derivatives are recommended.
|
|
Packit |
ea1746 |
|
|
Packit |
ea1746 |
The use of numerical derivatives should be a measure of last
|
|
Packit |
ea1746 |
resort, where it is simply not possible to write a templated
|
|
Packit |
ea1746 |
implementation of the cost function.
|
|
Packit |
ea1746 |
|
|
Packit |
ea1746 |
In many cases it is not possible to do analytic or automatic
|
|
Packit |
ea1746 |
differentiation of the entire cost function, but it is generally
|
|
Packit |
ea1746 |
the case that it is possible to decompose the cost function into
|
|
Packit |
ea1746 |
parts that need to be numerically differentiated and parts that can
|
|
Packit |
ea1746 |
be automatically or analytically differentiated.
|
|
Packit |
ea1746 |
|
|
Packit |
ea1746 |
To this end, Ceres has extensive support for mixing analytic,
|
|
Packit |
ea1746 |
automatic and numeric differentiation. See
|
|
Packit |
ea1746 |
:class:`CostFunctionToFunctor`.
|
|
Packit |
ea1746 |
|
|
Packit |
ea1746 |
#. When using Quaternions, consider using :class:`QuaternionParameterization`.
|
|
Packit |
ea1746 |
|
|
Packit |
ea1746 |
`Quaternions <https://en.wikipedia.org/wiki/Quaternion>`_ are a
|
|
Packit |
ea1746 |
four dimensional parameterization of the space of three dimensional
|
|
Packit |
ea1746 |
rotations :math:`SO(3)`. However, the :math:`SO(3)` is a three
|
|
Packit |
ea1746 |
dimensional set, and so is the tangent space of a
|
|
Packit |
ea1746 |
Quaternion. Therefore, it is sometimes (not always) benefecial to
|
|
Packit |
ea1746 |
associate a local parameterization with parameter blocks
|
|
Packit |
ea1746 |
representing a Quaternion. Assuming that the order of entries in
|
|
Packit |
ea1746 |
your parameter block is :math:`w,x,y,z`, you can use
|
|
Packit |
ea1746 |
:class:`QuaternionParameterization`.
|
|
Packit |
ea1746 |
|
|
Packit |
ea1746 |
.. NOTE::
|
|
Packit |
ea1746 |
|
|
Packit |
ea1746 |
If you are using `Eigen's Quaternion
|
|
Packit |
ea1746 |
<http://eigen.tuxfamily.org/dox/classEigen_1_1Quaternion.html>`_
|
|
Packit |
ea1746 |
object, whose layout is :math:`x,y,z,w`, then you should use
|
|
Packit |
ea1746 |
:class:`EigenQuaternionParameterization`.
|
|
Packit |
ea1746 |
|
|
Packit |
ea1746 |
|
|
Packit |
ea1746 |
#. How do I solve problems with general linear & non-linear
|
|
Packit |
ea1746 |
**inequality** constraints with Ceres Solver?
|
|
Packit |
ea1746 |
|
|
Packit |
ea1746 |
Currently, Ceres Solver only supports upper and lower bounds
|
|
Packit |
ea1746 |
constraints on the parameter blocks.
|
|
Packit |
ea1746 |
|
|
Packit |
ea1746 |
A crude way of dealing with inequality constraints is have one or
|
|
Packit |
ea1746 |
more of your cost functions check if the inequalities you are
|
|
Packit |
ea1746 |
interested in are satisfied, and if not return false instead of
|
|
Packit |
ea1746 |
true. This will prevent the solver from ever stepping into an
|
|
Packit |
ea1746 |
infeasible region.
|
|
Packit |
ea1746 |
|
|
Packit |
ea1746 |
This requires that the starting point for the optimization be a
|
|
Packit |
ea1746 |
feasible point. You also risk pre-mature convergence using this
|
|
Packit |
ea1746 |
method.
|
|
Packit |
ea1746 |
|
|
Packit |
ea1746 |
#. How do I solve problems with general linear & non-linear **equality**
|
|
Packit |
ea1746 |
constraints with Ceres Solver?
|
|
Packit |
ea1746 |
|
|
Packit |
ea1746 |
There is no built in support in ceres for solving problems with
|
|
Packit |
ea1746 |
equality constraints. Currently, Ceres Solver only supports upper
|
|
Packit |
ea1746 |
and lower bounds constraints on the parameter blocks.
|
|
Packit |
ea1746 |
|
|
Packit |
ea1746 |
The trick described above for dealing with inequality
|
|
Packit |
ea1746 |
constraints will **not** work for equality constraints.
|
|
Packit |
ea1746 |
|
|
Packit |
ea1746 |
#. How do I set one or more components of a parameter block constant?
|
|
Packit |
ea1746 |
|
|
Packit |
ea1746 |
Using :class:`SubsetParameterization`.
|
|
Packit |
ea1746 |
|
|
Packit |
ea1746 |
#. Putting `Inverse Function Theorem
|
|
Packit |
ea1746 |
<http://en.wikipedia.org/wiki/Inverse_function_theorem>`_ to use.
|
|
Packit |
ea1746 |
|
|
Packit |
ea1746 |
Every now and then we have to deal with functions which cannot be
|
|
Packit |
ea1746 |
evaluated analytically. Computing the Jacobian in such cases is
|
|
Packit |
ea1746 |
tricky. A particularly interesting case is where the inverse of the
|
|
Packit |
ea1746 |
function is easy to compute analytically. An example of such a
|
|
Packit |
ea1746 |
function is the Coordinate transformation between the `ECEF
|
|
Packit |
ea1746 |
<http://en.wikipedia.org/wiki/ECEF>`_ and the `WGS84
|
|
Packit |
ea1746 |
<http://en.wikipedia.org/wiki/World_Geodetic_System>`_ where the
|
|
Packit |
ea1746 |
conversion from WGS84 to ECEF is analytic, but the conversion
|
|
Packit |
ea1746 |
back to WGS84 uses an iterative algorithm. So how do you compute the
|
|
Packit |
ea1746 |
derivative of the ECEF to WGS84 transformation?
|
|
Packit |
ea1746 |
|
|
Packit |
ea1746 |
One obvious approach would be to numerically
|
|
Packit |
ea1746 |
differentiate the conversion function. This is not a good idea. For
|
|
Packit |
ea1746 |
one, it will be slow, but it will also be numerically quite
|
|
Packit |
ea1746 |
bad.
|
|
Packit |
ea1746 |
|
|
Packit |
ea1746 |
Turns out you can use the `Inverse Function Theorem
|
|
Packit |
ea1746 |
<http://en.wikipedia.org/wiki/Inverse_function_theorem>`_ in this
|
|
Packit |
ea1746 |
case to compute the derivatives more or less analytically.
|
|
Packit |
ea1746 |
|
|
Packit |
ea1746 |
The key result here is. If :math:`x = f^{-1}(y)`, and :math:`Df(x)`
|
|
Packit |
ea1746 |
is the invertible Jacobian of :math:`f` at :math:`x`. Then the
|
|
Packit |
ea1746 |
Jacobian :math:`Df^{-1}(y) = [Df(x)]^{-1}`, i.e., the Jacobian of
|
|
Packit |
ea1746 |
the :math:`f^{-1}` is the inverse of the Jacobian of :math:`f`.
|
|
Packit |
ea1746 |
|
|
Packit |
ea1746 |
Algorithmically this means that given :math:`y`, compute :math:`x =
|
|
Packit |
ea1746 |
f^{-1}(y)` by whatever means you can. Evaluate the Jacobian of
|
|
Packit |
ea1746 |
:math:`f` at :math:`x`. If the Jacobian matrix is invertible, then
|
|
Packit |
ea1746 |
its inverse is the Jacobian of :math:`f^{-1}(y)` at :math:`y`.
|
|
Packit |
ea1746 |
|
|
Packit |
ea1746 |
One can put this into practice with the following code fragment.
|
|
Packit |
ea1746 |
|
|
Packit |
ea1746 |
.. code-block:: c++
|
|
Packit |
ea1746 |
|
|
Packit |
ea1746 |
Eigen::Vector3d ecef; // Fill some values
|
|
Packit |
ea1746 |
// Iterative computation.
|
|
Packit |
ea1746 |
Eigen::Vector3d lla = ECEFToLLA(ecef);
|
|
Packit |
ea1746 |
// Analytic derivatives
|
|
Packit |
ea1746 |
Eigen::Matrix3d lla_to_ecef_jacobian = LLAToECEFJacobian(lla);
|
|
Packit |
ea1746 |
bool invertible;
|
|
Packit |
ea1746 |
Eigen::Matrix3d ecef_to_lla_jacobian;
|
|
Packit |
ea1746 |
lla_to_ecef_jacobian.computeInverseWithCheck(ecef_to_lla_jacobian, invertible);
|