manif icon indicating copy to clipboard operation
manif copied to clipboard

Implement left-Jacobians

Open joansola opened this issue 4 years ago • 7 comments

This is a low priority issue.

I am wondering: manif could have the option of providing the left-Jacobians instead of the right-Jacobians. This would give extra power to interface it with other tools that might be using left- logic. This means all implementations that regard uncertainties in the global reference.

As a reminder:

  • Local perturbations --> right plus and minus --> right Jacobians
  • Global perturbations --> left plus and minus --> left Jacobians

For example, Delaert and Drummond typically use left operations. Also Ceres uses left-plus in the local parametrizations they ship with the library.

So Manif could easily adapt to these cases.

The option should be global I guess, something like:

  • In the CMAKE step ---> ugly in my opinion
  • As a runtime function manif::options::setRightJacobians() or whatsoever
  • As a flag in the function calls, e.g. X.inverse(J, manif::LEFT_JAC) --> ugly in my opinion

joansola avatar Dec 04 '19 10:12 joansola

For reference:

image

joansola avatar Dec 04 '19 10:12 joansola

And also:

image

where the strange derivatives in the 3rd row are precisely and respectively the left- and right- Jacobians of Y=f(X)

joansola avatar Dec 04 '19 10:12 joansola

API-wise, another solution could be to rely on different types. In the futur I would like to introduce the Jacobian traits (on branch jacobian_traits) which allows for a semantically nicer notation e.g.:

manif::Jacobian<SE3, SE3> J_Y_X;          // == Eigen::Matrix<double, 6, 6>
manif::Jacobian<SE3, Vector3> J_X_v       // == Eigen::Matrix<double, 6, 3>
manif::Jacobian<Vector3, Vector3> J_vb_va // == Eigen::Matrix<double, 3, 3>

We could go all the way down and create a class Jacobian<LHS, RHS, Type> by inheriting from Eigen::Matrix. The template parameter Type here is an option to either specify left or right Jacobian with default to right. It would lead to something like

manif::Jacobian<SE3, SE3> right_J_inv_x;
manif::Jacobian<SE3, SE3, manif::Left> left_J_inv_x;
...
X.inverse(right_J_inv_x);
X.inverse(left_J_inv_x);

This implies some heavy modifications but after a quick look I would say it is feasible.

artivis avatar Feb 20 '20 22:02 artivis

Wow this looks neat!

However, I wonder if it is a good idea to have the left/right thing kind of hidden inside of the matrix template definition. I mean it can be confusing for example for finding bugs once the code is done, because the trace for left/right is perhaps up in some typedef or variable declaration, far from the actual function calls. What do you think?

joansola avatar Feb 21 '20 08:02 joansola

Late answer...
First I think that my last proposal is best in terms of design and overall 'look'. The alternatives are much less practical or plain ugly (as you pointed).
We could introduce some compile-time sanity checks such that the following would result in a compilation error:
right_J_inv_x * left_J_inv_x ==> Error: You are mixing right and left Jacobians.
Those checks could be in turned off with a compilation flag if someone wants to.

artivis avatar May 17 '20 14:05 artivis

Pasting from https://github.com/artivis/manif/issues/132#issuecomment-640804379

Left vs right Jacobians, #116. Thanks for bringing this up, this is indeed an important discussion. Personally, I have set the development of the control-toolbox set up such that it exclusively uses local perturbations, right plus and minus and right Jacobians. Our main argument why we go down that path is because we are using a family of solvers based on (local) sequential linear-quadratic programming, see e.g. here or here , which are expressed in a differential formulation in their most natural and wide-spread form. Personally, I have made a number of experiments where I compared "global" and "local" formulations. In practice, the "local" formulation does lead to a few advantages, which is why we have almost exculsively adopted that variant.

artivis avatar Jun 09 '20 13:06 artivis

@joansola I've been revisiting this topic and the conclusion is that the designed I proposed a while back (see below) is basically not doable without giving up the use of Eigen::Ref for jacobians arguments, which I believe is something we must keep.

Not doable:

manif::Jacobian<SE3, SE3> right_J_inv_x;
manif::Jacobian<SE3, SE3, manif::Left> left_J_inv_x;
...
X.inverse(right_J_inv_x);
X.inverse(left_J_inv_x);

So back to api design discussion... I really don't know what's best here;

  • In the CMAKE step
  • As a runtime function manif::options::setRightJacobians() or whatsoever
  • As a flag in the function calls, e.g. X.inverse(J, manif::LEFT_JAC)
  • other?

Unfortunately the most practical solution is likely the argument flag X.inverse(J, manif::LEFT_JAC).

artivis avatar Sep 28 '21 21:09 artivis