-
Notifications
You must be signed in to change notification settings - Fork 777
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
Custom Factors in Python #767
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You have to document this. You are the only one* who will do this. It has to also show up in some markdown file, dson't know which one. This is probably worth thinking about re the "readthedocs" change.
gtsam/nonlinear/CustomFactor.cpp
Outdated
Vector CustomFactor::unwhitenedError(const Values& x, boost::optional<std::vector<Matrix>&> H) const { | ||
if(this->active(x)) { | ||
if(H) { | ||
return this->errorFunction(*this, x, H.get_ptr()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Document what the mechanism is by which python can access. I expect you'll talk about pybind, types, how it appears in python, what python function should do.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
gtsam/nonlinear/CustomFactor.cpp
Outdated
return this->errorFunction(*this, x, H.get_ptr()); | ||
} else { | ||
JacobianVector dummy; | ||
return this->errorFunction(*this, x, &dummy); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Document what happens in this case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool!
See (minor) comments
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good overall, some comments and needs formatting. Awesome job @ProfFan!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some more stuff I noticed and should have added in my last review.
@ProfFan can you please re-request a review after you make the changes? Overall it looks great but I want to do a thorough review again so I can start using this ASAP. |
I am thinking about adding an optional constructor param that allows one to specify the name of the custom factor (stored as a string), so people can distinguish different |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
MArkdown?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool ! Starting to get there.
I have addressed all comments @dellaert @varunagrawal |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After design review, need to expand example to trajopt, and think about autodiff (after that).
Changes:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great improvement. Not approving yet because we need to talk about sendable
* Should the factor be evaluated in the same thread as the caller | ||
* This is to enable factors that has shared states (like the Python GIL lock) | ||
*/ | ||
virtual bool sendable() const { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don’t understand the name sendable
. Since this is a change to the nonlinear factor graph, let’s think about a name that makes sense locally, without the “outside” python context.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I shamelessly borrowed this concept from Rust (here). Basically it indicates whether an object can be shared with another thread. Maybe shareable
is a better name?
|
||
## Example | ||
|
||
The following is a simple `BetweenFactor` implemented in Python. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Either it’s a betweenfactor or it’s not. Pose to compare with still seems to be zero? I thought we had discussed a better, more representative example, but I don’t recall what.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not zero now, if you look at the last unit test.
@@ -0,0 +1,154 @@ | |||
import gtsam |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doc block missing...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
from typing import List, Optional | ||
from functools import partial | ||
|
||
# Simulate a car for one second |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Make a function for this that you call below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
:param this: gtsam.CustomFactor handle | ||
:param values: gtsam.Values | ||
:param jacobians: Optional list of Jacobians | ||
:param measurement: GPS measurement, to be filled with `partial` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you put measurement first? That makes it like “currying” in functionali languages.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
return error | ||
|
||
|
||
for k in range(5): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Document what’s happening here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, formatting?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Finally, maybe assign factor to a variable
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
for k in range(5): | ||
factor_graph.add(gtsam.CustomFactor(gps_model, [unknown[k]], partial(error_gps, measurement=np.array([g[k]])))) | ||
|
||
v = gtsam.Values() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove new line at end and Document block
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
|
||
result = optimizer.optimize() | ||
|
||
error = np.array([(result.atVector(unknown[k]) - x[k])[0] for k in range(5)]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What’s happening??? Document
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
:param this: gtsam.CustomFactor handle | ||
:param values: gtsam.Values | ||
:param jacobians: Optional list of Jacobians | ||
:param measurement: Odometry measurement, to be filled with `partial` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Measurement first?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
Merged! 🤯 |
Per #748 and #764, this is a factor that allow one to create the evaluateError function in Python.
The unit tests document the usage.
It also contains a fix for the proper binding of
Point3Pairs
. @johnwlambert