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

NoiseModelFactorN - fixed-number of variables >6 #947

Merged
merged 45 commits into from
Dec 23, 2022

Conversation

gchenfc
Copy link
Member

@gchenfc gchenfc commented Dec 1, 2021

Although this doesn't have an immediate use-case, I just wanted to work on this as a de-stressing exercise. Will not feel bad if it is rejected.

Currently there is NoiseModelFactor1, NoiseModelFactor2, ..., NoiseModelFactor6 but nothing higher, so if you want to implement n-way factors where n is known at compile time but greater than 6, you have to derive from NoiseModelFactor and implement unwhitenedError. This is fine, but I thought it'd be nice to have an n-way version that still has the convenient evaluateError syntax.

This might also be nice to use in place of existing NoiseModelFactor1-6 classes in the future since, if the number of arguments for a given factor ever changes, it requires fewer changes (N is figured out by the compiler rather than hard-coded).

@gchenfc gchenfc requested a review from dellaert December 1, 2021 21:15
@varunagrawal
Copy link
Collaborator

Dude, I love this!

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.

I love this. Is there a way to replace some of the earlier factors with a typedef to this new factor? has to be 100% compatible of course.

@gchenfc
Copy link
Member Author

gchenfc commented Dec 3, 2021

Thanks!

I love this. Is there a way to replace some of the earlier factors with a typedef to this new factor? has to be 100% compatible of course.

I did consider this but decided to wait what you thought first. Glad you feel similarly :)

I think the only extra things that wouldn't be possible with the typedef would be:

  1. inline Key key1() const { return keys_[0]; } etc.
  2. typedef VALUE1 X1; etc.

Because these have literal numbers in their names (and macros are processed before templates so we can't use macro magic to get these names).

After fixing the CI failure, I'll draft a potential solution and see what you think.

@dellaert
Copy link
Member

dellaert commented Dec 3, 2021

We can just add key1 to key6 and have it fail if N< less than six :-) There might even be template magic to only instantiate these methods up to N.

@gchenfc
Copy link
Member Author

gchenfc commented Dec 3, 2021

Oh true I forgot about that!

I implemented that - it's mostly done, except that the using syntax:

template <class VALUE1, class VALUE2, ...., class VALUE6>
using NoiseModelFactor6 = NoiseModelFactorN<VALUE1, VALUE2, VALUE3, VALUE4, VALUE5, VALUE6>;

is causing some serialization issues. Here's a MWE:
https://godbolt.org/z/WjrbfWMnT
It's totally expected that this doesn't work since BaseAlias is not a real type without specifying template arguments, but what is perplexing is that if you change using BaseAlias = Base<T>; to struct BaseAlias : Base<T> {}; it works, even though BaseAlias is still not a type without giving it template parameters. Or even if you use Base which is also templated (and how it is currently in GTSAM) it still works. Strange.

I'll think about this more later and maybe ask @ProfFan or @varunagrawal for help.

@dellaert
Copy link
Member

dellaert commented Dec 7, 2021

Ping @gchenfc - I prefer you ask help from someone not Varun or Fan - both racing to deadlines.

@gchenfc gchenfc requested a review from dellaert December 9, 2021 05:56
gtsam/nonlinear/NonlinearFactor.h Outdated Show resolved Hide resolved
gtsam/nonlinear/NonlinearFactor.h Outdated Show resolved Hide resolved
gtsam/nonlinear/NonlinearFactor.h Outdated Show resolved Hide resolved
@@ -272,503 +307,306 @@ class GTSAM_EXPORT NoiseModelFactor: public NonlinearFactor {


/* ************************************************************************* */
/* We need some helper structs to help us with NoiseModelFactorN - specifically
Copy link
Member

Choose a reason for hiding this comment

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

A great exercise in meta-programming which I’d love to see disappear, see comment below :-)

gtsam/nonlinear/NonlinearFactor.h Outdated Show resolved Hide resolved
gtsam/mainpage.dox Outdated Show resolved Hide resolved
gtsam/nonlinear/NonlinearFactor.h Outdated Show resolved Hide resolved
@jlblancoc
Copy link
Member

Might be doable with the typename... Args with clearer syntax? See e.g. #444
Just a first guess, perhaps it's not possible in this case for some reason.

@gchenfc
Copy link
Member Author

gchenfc commented Dec 9, 2021

Might be doable with the typename... Args with clearer syntax? See e.g. #444 Just a first guess, perhaps it's not possible in this case for some reason.

Thanks so much for the tip @jlblancoc! Would you mind clarifying which aspects you were thinking to include this? It's currently being used quite a bit here, e.g.

template <class... VALUES>
class NoiseModelFactorN
: public NoiseModelFactor,

virtual Vector evaluateError(const VALUES&... x,
optional_matrix_type<VALUES>... H) const = 0;

but I'm hung up on all the "custom" additions for backwards compatibility, e.g. Key key1 const { return keys_[0]; } and typedef X2 VALUE2 which are the majority of what is making this so ugly at the moment - would absolutely love any ideas/suggestions for alternatives if you have any!

@jlblancoc
Copy link
Member

jlblancoc commented Dec 9, 2021

@gchenfc Ah, very good job then, IMO you are on the right track! 👍

but I'm hung up on all the "custom" additions for backwards compatibility, e.g. Key key1 const { return keys_[0]; }

I'm afraid gtsam is so used, it needs that backwards compatibility, so it should be kept despite the "ugliness" ;-)

PS: I can't think of any "elegant" way to circumvent it, neither...

@gchenfc
Copy link
Member Author

gchenfc commented Dec 9, 2021

@jlblancoc Cool, thanks for sharing + advice! much appreciated :)

@varunagrawal varunagrawal requested review from mattking-smith and removed request for dellaert November 10, 2022 19:38
Copy link
Collaborator

@varunagrawal varunagrawal left a comment

Choose a reason for hiding this comment

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

@gchenfc this looks great except for some nitpicks. Can you please make the modifications and we can land this?

gtsam/nonlinear/NonlinearFactor.h Outdated Show resolved Hide resolved
gtsam/nonlinear/NonlinearFactor.h Outdated Show resolved Hide resolved
gtsam/nonlinear/NonlinearFactor.h Outdated Show resolved Hide resolved
gtsam/nonlinear/NonlinearFactor.h Outdated Show resolved Hide resolved
gtsam/nonlinear/NonlinearFactor.h Outdated Show resolved Hide resolved
gtsam/nonlinear/NonlinearFactor.h Outdated Show resolved Hide resolved
gtsam/nonlinear/NonlinearFactor.h Outdated Show resolved Hide resolved
gtsam/nonlinear/NonlinearFactor.h Outdated Show resolved Hide resolved
@gchenfc
Copy link
Member Author

gchenfc commented Nov 16, 2022

Thanks @varunagrawal for the review! I'll go through and add DEPRECATED - I think you created that after I had originally made this PR so I'm glad you reminded me of this! Can you also confirm the other 2 items and, if you still want those changes, I'll add those changes too.

@gchenfc Will I be able to test this NoiseModelFactorN in Matlab? What is holding up the merge on this PR? I know me and my lab mate have both needed this in the past.

I don't think this can directly be used in Matlab since NoiseModelFactorN is templated and you need to supply the types of all the variables during compile-time. Actually, now that I think of it, I forget how e.g. NoiseModelFactor2 is even used in Matlab, since you can't define custom factors? Because NoiseModelFactor1, ..., NoiseModelFactorN are primarily used as base classes for defining custom factors. But it would be easier (less copy-paste) to define e.g. NoiseModelFactor8<T1, T2, ..., T8> if hypothetically you wanted it. If it's just for linear, we can do that in a different PR. If it's for nonlinear, I'm not sure how this would help in Matlab since custom factors need to be defined in C++ anyway (unless using Fan's CustomFactor class).
And I think the PR was previously just waiting for review, so thanks varun again :)

@varunagrawal
Copy link
Collaborator

GTSAM_DEPRECATED was already present even before I started working with GTSAM. @dellaert and I have been deprecating stuff as we revisit components for hybrid estimation (e.g. EliminateForMPE) which is how I know about it, so passing that knowledge on. :)

@mattking-smith we'll be able to write a C++ class with 8+ variables (which isn't doable in current develop) and then we can wrap that class. We can talk about it offline (especially since now that I better understand what you're doing).

@gchenfc
Copy link
Member Author

gchenfc commented Nov 16, 2022

Thanks! Will merge once CI completes, assuming that github lets me; we may still need an approval from @dellaert since he previously requested changes (that have since been fixed I think).

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.

Some comments. This PR is a year old now :-) Could we meet and put a pin in it ? I really like the idea and want to have it in 4.2.

gtsam/nonlinear/NonlinearFactor.h Outdated Show resolved Hide resolved
gtsam/nonlinear/NonlinearFactor.h Outdated Show resolved Hide resolved
gtsam/nonlinear/NonlinearFactor.h Outdated Show resolved Hide resolved
gtsam/nonlinear/NonlinearFactor.h Outdated Show resolved Hide resolved
@dellaert
Copy link
Member

@gchenfc

This is a byproduct of the overload resolution problem when N=1, then it can be hard to differentiate between:
NoiseModelFactorN(noise, key)
NoiseModelFactorN(noise, {key})
@dellaert
Copy link
Member

PS, re-reading some above, we definitely need to check that both wrappers (python and matlab) still work. @mattking-smith might be able to help with latter...

@gchenfc
Copy link
Member Author

gchenfc commented Dec 23, 2022

PS, re-reading some above, we definitely need to check that both wrappers (python and matlab) still work. @mattking-smith might be able to help with latter...

Tested both and all pass!

Python is tested by CI and I also ran on my machine, all pass.

Matlab I tested on my machine and all pass, after needing to change some instances of symbol -> Symbol due to my computer having case insensitive filenames.


Also, I put the "changing gtsam pre-made factors to inherit from NoiseModelN instead" into a new PR to keep things separate.

@gchenfc gchenfc requested review from dellaert and removed request for dellaert December 23, 2022 07:03
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.

This is an amazing piece of work, Gerry! Will merge so it’s ready to go into 4.2 :-)

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.

5 participants