-
Notifications
You must be signed in to change notification settings - Fork 28
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
implemented new evaluate() and evaluateAndJacobians() #30
Conversation
Thanks for your comments Mike! The type of chainRule was changed to Eigen::MatrixXd. I understand that using unordered_map might not be the most efficient. The change to use vectors instead should not be much work. Before we do the changes, does someone disagree to use std::vector as the containers for coefficients and jacobian pointers which are passed to the evaluator eval() function? @gawela @furgalep |
Are we sure that using an unordered map is too heavy? At some point we have to map a coefficient's Jacobian to some place in the Before implementing, can someone explain how it would work with a vector? |
@mikebosse, here is the function that we have to overload when making a factor: /**
* Error function *without* the NoiseModel, \f$ z-h(x) \f$.
* Override this method to finish implementing an N-way factor.
* If any of the optional Matrix reference arguments are specified, it should compute
* both the function evaluation and its derivative(s) in X1 (and/or X2, X3...).
*/
virtual Vector unwhitenedError(const Values& x, boost::optional< std::vector< Matrix > &> H = boost::none) const = 0; The Jacobians go out in a std::vector. The ordering of this vector is specified by the factor. See the factor header here: Values is something like an unordered map:
// Internally we store a boost ptr_map, with a ValueCloneAllocator (defined
// below) to clone and deallocate the Value objects, and a boost
// fast_pool_allocator to allocate map nodes. In this way, all memory is
// allocated in a boost memory pool.
typedef boost::ptr_map<
Key,
Value,
std::less<Key>,
ValueCloneAllocator,
boost::fast_pool_allocator<std::pair<const Key, void*> > > KeyValueMap; For the first argument of the evaluator, we could make an adapter that wraps the But somehow we have to compute these Jacobians (even if there are duplicates) and apply the chain rule and then put the Jacobians back in this standard vector. For the key-->index mapping, isn't a map the right data structure? Why do we think maps are heavy or slow? |
|
||
virtual ValueType evaluateAndJacobians(const boost::unordered_map<Key, Coefficient>& keyCoefficient, | ||
const boost::unordered_map<Key, Eigen::MatrixXd*>& keyJacobian, | ||
const Eigen::MatrixXd& chainRule) const = 0; |
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.
Put keyJacobian last as it is an output variable.
@furgalep @mikebosse Thanks to you guys for the comments and help. We are learning a lot while having fun! |
I think that using a map just to pass matrices from the evaluator to the On Mon, Sep 15, 2014 at 6:30 PM, Paul Furgale notifications@github.com
|
Can you give some pseudocode for what this would look like? Let's have, as an example, a factor with two evaluators where the evaluators could have some of the same keys. |
Here is some really rough pseudo code for constructor and unwhitened error: RelativePoseFactor::RelativePoseFactor( curve, timeA, timeB) {
evalA = curve.getEvaluator(timeA);
evalB = curve.getEvaluator(timeB);
vector<int> JacOrderA, JacOrderB;
map<key, index> unique_keys;
for i and each key in evalA {
if( !unique_keys.has(key)) {
unique_keys[key] = unique_keys.size();
}
JacOrderA[i] = unique_keys[key];
// repeat same for EvalB ....
for i and each key in evalB {
if(!unique_keys.has(key)){
unique_keys[key] = unique_keys.size();
}
JacOrderB[i] = unique_keys[key];
}
}
RelativePoseFactor::UnwhitenedError(Values, JacobianVec) {
Matrix chainRuleMat = Jacobian for A
vector<Matrix *> jacobianPtrs;
for each i in JacOrderA.size() {
jacobianPtrs[i] = &JacobianVec[JacOrderA[i]];
}
poseA = evalA.eval(Values,chainRuleMat,jacobianPtrs);
Matrix chainRuleMat = Jacobian for B;
jacobianPtrs.clear();
for each i in JacOrderB.size() {
jacobianPtrs.push_back(&JacobianVec[JacOrderB[i]]);
}
poseB = evalA.eval(Values,chainRuleMat,jacobianPtrs);
return error of (poseB-poseA);
} |
@mikebosse, Yes, that is a nice approach. Some small things: we shouldn't use Cool! Let's do it like that. |
Cool! Looks clean! This will be done today. |
…rgs of evaluate functions
This last commits integrate the use of std::vector for passing the coefficients and jacobians. Profiling results of an example with 1000 coefficients and 100000 relative factor are found in the trajectory maintainer repo for both vector and unordered_maps approaches. See: https://github.com/ethz-asl/continuous-trajectory-scanmatching/tree/master/profiling Thanks! |
Hi Renaud, |
Thank, lesson learned! Will try to remove them. |
it looks like almost half the time is being spent in the eigeny matrix |
No idea. |
Okay, make this compile and you are good to merge |
@rdube , do you know how to remove the pdf from the history - so not only commit a delete? Otherwise I can show you. It is better to have that removed from the pull request before merge, to keep the mess small.. |
Oh, I thought the PDFs were in the PR but they are in the master of https://github.com/ethz-asl/continuous-trajectory-scanmatching. Hm, shall we still remove the PDFs from the history? I guess not many people have that branch tracked, yet. |
Can you try? |
Yes of course, the problem is not removing the files - the problem is for the people that have this branch locally. They might have to reset or rebase at the latest before they push next time (exactly when they have this commit already in a local branch). So I guess only @rdube , @gawela and @mikebosse could be in that situation. So are you okay with me rewriting the master's history? I can quickly come by to whoever is unsure how to deal with that on his machine.. |
Hi Renaud, http://129.132.38.183:8080/job/curves/32/ And now the master doesn't compile: http://129.132.38.183:8080/job/curves/33/ Can you make a new branch and try to fix this? |
Ok it builds fine on my computer but I will check to fix this. |
That was a unrelated jenkins issue. Something wired with updating catkin_simple (it got conflicts by pulling - I'm on it). I reset that rep and it is fine now : http://129.132.38.183:8080/job/curves/36/. |
Ah, and the profiling PDFs in https://github.com/ethz-asl/continuous-trajectory-scanmatching are in the "never committed" state, as they should be ;). |
Regarding the Jenkins issue, the general rule is: don't merge until you
It is true that sometimes this is a Jenkins issue, but in that case, do your best to debug, then escalate to one of the admins (hannes, me, simon, mike). OK, thanks for all of your hard work! Thanks @HannesSommer for sorting that all out! |
Implemented new functions for making real adaptive factors (no switch case). The rest of the solution will be in AdaptiveOdometryFactor::unwhitenedError() on the trajectory_maintainer gitrepo :
https://github.com/ethz-asl/continuous-trajectory-scanmatching
The old evaluate() and evaluateAndJacobians() were kept until the adaptive factor architecture is validated.
Thanks for commenting.