Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unit tests for Jacobian of PartialPriorFactor<Pose3> #721

Merged
merged 11 commits into from
Mar 29, 2021

Conversation

miloknowles
Copy link
Contributor

Adds unit tests for PartialPriorFactor<Pose3> to show that the Jacobians for this factor are incorrect. Specifically, the factor precomputes a Jacobian that is correct for an identity pose, but doesn't take into account the rotation/translation at the current linearization point. See /gtsam_unstable/slam/tests/testPartialPriorFactor.cpp for the relevant tests (the identity case succeeds while the others fail). This is addressing the post here on the Google group.

Haven't contributed to GTSAM before so apologies if I'm missing a part of the workflow. I thought I'd open the issue now, and start working on a fix in the meantime.

@miloknowles miloknowles changed the title Three examples of failing PartialPriorFactor<Pose3> Jacobians Unit tests for Jacobian of PartialPriorFactor<Pose3> Mar 20, 2021
@dellaert
Copy link
Member

Nice. I would put the fix in this same PR, as we can’t merge failing tests :-) do you know how to fix it?

@miloknowles
Copy link
Contributor Author

I think so - the evaluateError function already calls LieGroup::logmapto get the tangent vector, so getting the Jacobian from logmap and then selecting the relevant row(s) seems like an easy solution.

Unrelated, but I'd also like to rename the "mask" argument in the factor to something else, since it's a list of tangent vector indices rather than a binary mask (I found this slightly confusing at first).

@miloknowles
Copy link
Contributor Author

miloknowles commented Mar 21, 2021

One question: should I prefer localCoordinates or logmap?

@dellaert
Copy link
Member

I think so - the evaluateError function already calls LieGroup::logmapto get the tangent vector, so getting the Jacobian from logmap and then selecting the relevant row(s) seems like an easy solution.

Unrelated, but I'd also like to rename the "mask" argument in the factor to something else, since it's a list of tangent vector indices rather than a binary mask (I found this slightly confusing at first).

Ah, unrelated PRs are unrelated :-) Let's keep this one easy to review? If you've already don it no issue.

localcoordinates is indeed preferred as that will allow any manifold type as well.

@miloknowles
Copy link
Contributor Author

Already made the change, apologies - I'll keep my PRs minimal in the future though! :)

Switched to localCoordinates, although I only get the correct Jacobians when I use p.localCoordinates(T::identity()) instead of the other way around, for reasons I don't quite understand...

Based on PoseRotationPrior and PoseTranslationPrior, it seems like the correct way to compute error is prior_.localCoordinates(p). However, since we only store part of the prior tangent vector in this factor, we would have to assume values for the other parameters to follow this pattern. I'm not sure how to do that except for by assuming the identity, in which case we may as well use Logmap or LocalCoordinates. Let me know what you think would be best.

@dellaert
Copy link
Member

Interesting. I propose you try something that you think is right, but do it in a very test-driven way. Definitely test away from zero, and for non-trivial manifolds, e.g. Pose3.

CI seems to be failing now, BTW

@miloknowles
Copy link
Contributor Author

@dellaert I decided to use T::Logmap since I think most GTSAM users will be using this factor with Lie groups anyways. I've added unit tests for PartialPriorFactor<Pose2/Pose3> at a variety of different linearization points and am pretty confident the Jacobians are correct now. Interestingly, it looks like PR #724 is fixing the exact same Jacobian problem in the UnaryFactor tutorial. Will deal with the CI failures now.

@dellaert
Copy link
Member

@dellaert I decided to use T::Logmap since I think most GTSAM users will be using this factor with Lie groups anyways. I've added unit tests for PartialPriorFactor<Pose2/Pose3> at a variety of different linearization points and am pretty confident the Jacobians are correct now. Interestingly, it looks like PR #724 is fixing the exact same Jacobian problem in the UnaryFactor tutorial. Will deal with the CI failures now.

Hmmm. What's the problem using T::LocalCoordinates? It seems Logmap is artificially constraining the usefulness. Maybe I don't see the problem.

@miloknowles
Copy link
Contributor Author

miloknowles commented Mar 26, 2021

@dellaert I decided to use T::Logmap since I think most GTSAM users will be using this factor with Lie groups anyways. I've added unit tests for PartialPriorFactor<Pose2/Pose3> at a variety of different linearization points and am pretty confident the Jacobians are correct now. Interestingly, it looks like PR #724 is fixing the exact same Jacobian problem in the UnaryFactor tutorial. Will deal with the CI failures now.

Hmmm. What's the problem using T::LocalCoordinates? It seems Logmap is artificially constraining the usefulness. Maybe I don't see the problem.

I forgot to mention - PoseRTV does not implement LocalCoordinates, only Logmap, which is why I had ended up using Logmap. There are some some partial prior factors in DynamicsPriors.h that are templated on the PoseRTV type.

Would you like me to add LocalCoordinates in PoseRTV or stick with Logmap?

@dellaert
Copy link
Member

@dellaert I decided to use T::Logmap since I think most GTSAM users will be using this factor with Lie groups anyways. I've added unit tests for PartialPriorFactor<Pose2/Pose3> at a variety of different linearization points and am pretty confident the Jacobians are correct now. Interestingly, it looks like PR #724 is fixing the exact same Jacobian problem in the UnaryFactor tutorial. Will deal with the CI failures now.

Hmmm. What's the problem using T::LocalCoordinates? It seems Logmap is artificially constraining the usefulness. Maybe I don't see the problem.

I forgot to mention - PoseRTV does not implement LocalCoordinates, only Logmap, which is why I had ended up using Logmap. There are some some partial prior factors in DynamicsPriors.h that are templated on the PoseRTV type.

So, PoseRTV is superseded by NavState, but that's a different PR :-)

But the problem with LocalCoordinates might be easily solved. It might simply be a missing entry at line 78 in PoseRTV.h ?

  /// @name Manifold
  /// @{
  using Base::dimension;
  using Base::dim;
  using Base::Dim;
  using Base::retract;
  using Base::localCoordinates;
  /// @}

@miloknowles
Copy link
Contributor Author

@dellaert I decided to use T::Logmap since I think most GTSAM users will be using this factor with Lie groups anyways. I've added unit tests for PartialPriorFactor<Pose2/Pose3> at a variety of different linearization points and am pretty confident the Jacobians are correct now. Interestingly, it looks like PR #724 is fixing the exact same Jacobian problem in the UnaryFactor tutorial. Will deal with the CI failures now.

Hmmm. What's the problem using T::LocalCoordinates? It seems Logmap is artificially constraining the usefulness. Maybe I don't see the problem.

I forgot to mention - PoseRTV does not implement LocalCoordinates, only Logmap, which is why I had ended up using Logmap. There are some some partial prior factors in DynamicsPriors.h that are templated on the PoseRTV type.

So, PoseRTV is superseded by NavState, but that's a different PR :-)

But the problem with LocalCoordinates might be easily solved. It might simply be a missing entry at line 78 in PoseRTV.h ?

  /// @name Manifold
  /// @{
  using Base::dimension;
  using Base::dim;
  using Base::Dim;
  using Base::retract;
  using Base::localCoordinates;
  /// @}

I think because ProductLieGroup doesn't implement LocalCoordinates (just Logmap), we can't use the simple fix :(
Maybe that's a different PR too?

@dellaert
Copy link
Member

I think because ProductLieGroup doesn't implement LocalCoordinates (just Logmap), we can't use the simple fix :(
Maybe that's a different PR too?

No, I think that's an oversight and we could put that in this PR. OR switch to a different type for testing this PR. Adding PoseRTV code is probably a mistake, so maybe just switch to NavState which should have all the manifold goodness.

@miloknowles
Copy link
Contributor Author

I think because ProductLieGroup doesn't implement LocalCoordinates (just Logmap), we can't use the simple fix :(
Maybe that's a different PR too?

No, I think that's an oversight and we could put that in this PR. OR switch to a different type for testing this PR. Adding PoseRTV code is probably a mistake, so maybe just switch to NavState which should have all the manifold goodness.

Sorry for all the back and forth - I opted to just add LocalCoordinates to ProductLieGroup so that we get it in PoseRTV. Unfortunately NavState doesn't have LocalCoordinates either, unless I'm missing some kind of manifold inheritance. Also, replacing PoseRTV with NavState would require a lot of changes in DynamicsPriors and dynamics/tests/testIMUSystem.cpp, and I didn't want to make the review any more involved.

Copy link
Member

@dellaert dellaert left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good! A few more comments re modern Jacobian style. Re-request review if CI succeeds and I'll approve (or Brice can).

gtsam/base/ProductLieGroup.h Show resolved Hide resolved
gtsam_unstable/slam/PartialPriorFactor.h Outdated Show resolved Hide resolved
gtsam_unstable/slam/PartialPriorFactor.h Outdated Show resolved Hide resolved

// If the Rot3 Cayley map is used, Rot3::LocalCoordinates will throw a runtime error
// when asked to compute the Jacobian matrix (see Rot3M.cpp).
#ifdef GTSAM_ROT3_EXPMAP
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, but why would we do this for every possible T?
But I'll let this slip, as (a) the fix is not straightforward, (b) this is not an often used factor, and (c) GTSAM_ROT3_EXPMAP is the default...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I'm not sure I follow. Do you mean we just shouldn't use this factor if GTSAM_ROT3_EXPMAP is turned off?

@dellaert dellaert merged commit 8ffad01 into borglab:develop Mar 29, 2021
@dellaert
Copy link
Member

Thanks @miloknowles !!!!

@miloknowles miloknowles deleted the milo/partial_prior_factor branch March 29, 2021 13:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants