From 12290dc7b2de0d5d8712497e034777d963fe7429 Mon Sep 17 00:00:00 2001 From: Alex Cunningham Date: Mon, 27 Aug 2012 01:11:37 +0000 Subject: [PATCH] Added linearization points to LinearContainerFactor. Fixed bug with localCoordinates() in Values --- .cproject | 332 +++++++++--------- gtsam/nonlinear/Values.cpp | 10 +- gtsam/nonlinear/Values.h | 2 +- gtsam/nonlinear/tests/testValues.cpp | 18 + .../nonlinear/LinearContainerFactor.cpp | 123 +++++-- .../nonlinear/LinearContainerFactor.h | 26 +- .../tests/testLinearContainerFactor.cpp | 43 +++ 7 files changed, 352 insertions(+), 202 deletions(-) diff --git a/.cproject b/.cproject index 7f13b1809..80a7c399e 100644 --- a/.cproject +++ b/.cproject @@ -309,14 +309,6 @@ true true - - make - -j2 - testGaussianFactor.run - true - true - true - make -j2 @@ -343,6 +335,7 @@ make + tests/testBayesTree.run true false @@ -350,6 +343,7 @@ make + testBinaryBayesNet.run true false @@ -397,6 +391,7 @@ make + testSymbolicBayesNet.run true false @@ -404,6 +399,7 @@ make + tests/testSymbolicFactor.run true false @@ -411,6 +407,7 @@ make + testSymbolicFactorGraph.run true false @@ -426,11 +423,20 @@ make + tests/testBayesTree true false true + + make + -j2 + testGaussianFactor.run + true + true + true + make -j5 @@ -519,22 +525,6 @@ false true - - make - -j2 - all - true - true - true - - - make - -j2 - clean - true - true - true - make -j2 @@ -551,6 +541,22 @@ true true + + make + -j2 + all + true + true + true + + + make + -j2 + clean + true + true + true + make -j2 @@ -575,26 +581,26 @@ true true - + make - -j5 - testValues.run + -j2 + all true true true - + make - -j5 - testOrdering.run + -j2 + check true true true - + make - -j5 - testKey.run + -j2 + clean true true true @@ -679,26 +685,26 @@ true true - + make - -j2 - all + -j5 + testValues.run true true true - + make - -j2 - check + -j5 + testOrdering.run true true true - + make - -j2 - clean + -j5 + testKey.run true true true @@ -977,6 +983,7 @@ make + testGraph.run true false @@ -984,6 +991,7 @@ make + testJunctionTree.run true false @@ -991,6 +999,7 @@ make + testSymbolicBayesNetB.run true false @@ -1126,6 +1135,7 @@ make + testErrors.run true false @@ -1171,10 +1181,10 @@ true true - + make - -j2 - testGaussianFactor.run + -j5 + testLinearContainerFactor.run true true true @@ -1259,6 +1269,14 @@ true true + + make + -j2 + testGaussianFactor.run + true + true + true + make -j2 @@ -1589,7 +1607,6 @@ make - testSimulated2DOriented.run true false @@ -1629,7 +1646,6 @@ make - testSimulated2D.run true false @@ -1637,7 +1653,6 @@ make - testSimulated3D.run true false @@ -1829,7 +1844,6 @@ make - tests/testGaussianISAM2 true false @@ -1851,102 +1865,6 @@ true true - - make - -j2 - testRot3.run - true - true - true - - - make - -j2 - testRot2.run - true - true - true - - - make - -j2 - testPose3.run - true - true - true - - - make - -j2 - timeRot3.run - true - true - true - - - make - -j2 - testPose2.run - true - true - true - - - make - -j2 - testCal3_S2.run - true - true - true - - - make - -j2 - testSimpleCamera.run - true - true - true - - - make - -j2 - testHomography2.run - true - true - true - - - make - -j2 - testCalibratedCamera.run - true - true - true - - - make - -j2 - check - true - true - true - - - make - -j2 - clean - true - true - true - - - make - -j2 - testPoint2.run - true - true - true - make -j1 @@ -2148,6 +2066,7 @@ cpack + -G DEB true false @@ -2155,6 +2074,7 @@ cpack + -G RPM true false @@ -2162,6 +2082,7 @@ cpack + -G TGZ true false @@ -2169,6 +2090,7 @@ cpack + --config CPackSourceConfig.cmake true false @@ -2302,34 +2224,98 @@ true true - + make - -j5 - testSpirit.run + -j2 + testRot3.run true true true - + make - -j5 - testWrap.run + -j2 + testRot2.run true true true - + make - -j5 - check.wrap + -j2 + testPose3.run true true true - + make - -j5 - wrap + -j2 + timeRot3.run + true + true + true + + + make + -j2 + testPose2.run + true + true + true + + + make + -j2 + testCal3_S2.run + true + true + true + + + make + -j2 + testSimpleCamera.run + true + true + true + + + make + -j2 + testHomography2.run + true + true + true + + + make + -j2 + testCalibratedCamera.run + true + true + true + + + make + -j2 + check + true + true + true + + + make + -j2 + clean + true + true + true + + + make + -j2 + testPoint2.run true true true @@ -2373,6 +2359,38 @@ false true + + make + -j5 + testSpirit.run + true + true + true + + + make + -j5 + testWrap.run + true + true + true + + + make + -j5 + check.wrap + true + true + true + + + make + -j5 + wrap + true + true + true + diff --git a/gtsam/nonlinear/Values.cpp b/gtsam/nonlinear/Values.cpp index 636c87c73..eab37ff17 100644 --- a/gtsam/nonlinear/Values.cpp +++ b/gtsam/nonlinear/Values.cpp @@ -90,7 +90,15 @@ namespace gtsam { /* ************************************************************************* */ VectorValues Values::localCoordinates(const Values& cp, const Ordering& ordering) const { VectorValues result(this->dims(ordering)); - localCoordinates(cp, ordering, result); + if(this->size() != cp.size()) + throw DynamicValuesMismatched(); + for(const_iterator it1=this->begin(), it2=cp.begin(); it1!=this->end(); ++it1, ++it2) { + if(it1->key != it2->key) + throw DynamicValuesMismatched(); // If keys do not match + // Will throw a dynamic_cast exception if types do not match + // NOTE: this is separate from localCoordinates(cp, ordering, result) due to at() vs. insert + result.at(ordering[it1->key]) = it1->value.localCoordinates_(it2->value); + } return result; } diff --git a/gtsam/nonlinear/Values.h b/gtsam/nonlinear/Values.h index c96831f05..25bd3dc2e 100644 --- a/gtsam/nonlinear/Values.h +++ b/gtsam/nonlinear/Values.h @@ -212,7 +212,7 @@ namespace gtsam { /** Get a delta config about a linearization point c0 (*this) */ VectorValues localCoordinates(const Values& cp, const Ordering& ordering) const; - /** Get a delta config about a linearization point c0 (*this) */ + /** Get a delta config about a linearization point c0 (*this) - assumes uninitialized delta */ void localCoordinates(const Values& cp, const Ordering& ordering, VectorValues& delta) const; ///@} diff --git a/gtsam/nonlinear/tests/testValues.cpp b/gtsam/nonlinear/tests/testValues.cpp index 5242fef1c..ffef740a6 100644 --- a/gtsam/nonlinear/tests/testValues.cpp +++ b/gtsam/nonlinear/tests/testValues.cpp @@ -234,6 +234,24 @@ TEST(Values, expmap_d) CHECK(config0.equals(config0)); } +/* ************************************************************************* */ +TEST(Values, localCoordinates) +{ + Values valuesA; + valuesA.insert(key1, LieVector(3, 1.0, 2.0, 3.0)); + valuesA.insert(key2, LieVector(3, 5.0, 6.0, 7.0)); + + Ordering ordering = *valuesA.orderingArbitrary(); + + VectorValues expDelta = valuesA.zeroVectors(ordering); +// expDelta.at(ordering[key1]) = Vector_(3, 0.1, 0.2, 0.3); +// expDelta.at(ordering[key2]) = Vector_(3, 0.4, 0.5, 0.6); + + Values valuesB = valuesA.retract(expDelta, ordering); + + EXPECT(assert_equal(expDelta, valuesA.localCoordinates(valuesB, ordering))); +} + /* ************************************************************************* */ TEST(Values, extract_keys) { diff --git a/gtsam_unstable/nonlinear/LinearContainerFactor.cpp b/gtsam_unstable/nonlinear/LinearContainerFactor.cpp index ea324704b..048f4a0c4 100644 --- a/gtsam_unstable/nonlinear/LinearContainerFactor.cpp +++ b/gtsam_unstable/nonlinear/LinearContainerFactor.cpp @@ -27,56 +27,82 @@ void LinearContainerFactor::rekeyFactor(const Ordering::InvertedMap& invOrdering } /* ************************************************************************* */ -LinearContainerFactor::LinearContainerFactor( - const JacobianFactor& factor, const Ordering& ordering) -: factor_(factor.clone()) { - rekeyFactor(ordering); +void LinearContainerFactor::initializeLinearizationPoint(const Values& linearizationPoint) { + if (!linearizationPoint.empty()) { + linearizationPoint_ = Values(); + BOOST_FOREACH(const gtsam::Key& key, this->keys()) { + linearizationPoint_->insert(key, linearizationPoint.at(key)); + } + } else { + linearizationPoint_ = boost::none; + } } /* ************************************************************************* */ LinearContainerFactor::LinearContainerFactor( - const HessianFactor& factor, const Ordering& ordering) + const JacobianFactor& factor, const Ordering& ordering, + const Values& linearizationPoint) : factor_(factor.clone()) { rekeyFactor(ordering); + initializeLinearizationPoint(linearizationPoint); } /* ************************************************************************* */ LinearContainerFactor::LinearContainerFactor( - const GaussianFactor::shared_ptr& factor, const Ordering& ordering) + const HessianFactor& factor, const Ordering& ordering, + const Values& linearizationPoint) +: factor_(factor.clone()) { + rekeyFactor(ordering); + initializeLinearizationPoint(linearizationPoint); +} + +/* ************************************************************************* */ +LinearContainerFactor::LinearContainerFactor( + const GaussianFactor::shared_ptr& factor, const Ordering& ordering, + const Values& linearizationPoint) : factor_(factor->clone()) { rekeyFactor(ordering); -} - -/* ************************************************************************* */ -LinearContainerFactor::LinearContainerFactor( - const GaussianFactor::shared_ptr& factor) -: factor_(factor->clone()) -{ - // Extract keys stashed in linear factor - BOOST_FOREACH(const Index& idx, factor_->keys()) - keys_.push_back(idx); -} - -/* ************************************************************************* */ -LinearContainerFactor::LinearContainerFactor(const JacobianFactor& factor, - const Ordering::InvertedMap& inverted_ordering) -: factor_(factor.clone()) { - rekeyFactor(inverted_ordering); -} - -/* ************************************************************************* */ -LinearContainerFactor::LinearContainerFactor(const HessianFactor& factor, - const Ordering::InvertedMap& inverted_ordering) -: factor_(factor.clone()) { - rekeyFactor(inverted_ordering); + initializeLinearizationPoint(linearizationPoint); } /* ************************************************************************* */ LinearContainerFactor::LinearContainerFactor( const GaussianFactor::shared_ptr& factor, - const Ordering::InvertedMap& ordering) + const Values& linearizationPoint) +: factor_(factor->clone()) +{ + // Extract keys stashed in linear factor + BOOST_FOREACH(const Index& idx, factor_->keys()) + keys_.push_back(idx); + initializeLinearizationPoint(linearizationPoint); +} + +/* ************************************************************************* */ +LinearContainerFactor::LinearContainerFactor(const JacobianFactor& factor, + const Ordering::InvertedMap& inverted_ordering, + const Values& linearizationPoint) +: factor_(factor.clone()) { + rekeyFactor(inverted_ordering); + initializeLinearizationPoint(linearizationPoint); +} + +/* ************************************************************************* */ +LinearContainerFactor::LinearContainerFactor(const HessianFactor& factor, + const Ordering::InvertedMap& inverted_ordering, + const Values& linearizationPoint) +: factor_(factor.clone()) { + rekeyFactor(inverted_ordering); + initializeLinearizationPoint(linearizationPoint); +} + +/* ************************************************************************* */ +LinearContainerFactor::LinearContainerFactor( + const GaussianFactor::shared_ptr& factor, + const Ordering::InvertedMap& ordering, + const Values& linearizationPoint) : factor_(factor->clone()) { rekeyFactor(ordering); + initializeLinearizationPoint(linearizationPoint); } /* ************************************************************************* */ @@ -84,20 +110,45 @@ void LinearContainerFactor::print(const std::string& s, const KeyFormatter& keyF Base::print(s+"LinearContainerFactor", keyFormatter); if (factor_) factor_->print(" Stored Factor", keyFormatter); + if (linearizationPoint_) + linearizationPoint_->print(" LinearizationPoint", keyFormatter); } /* ************************************************************************* */ bool LinearContainerFactor::equals(const NonlinearFactor& f, double tol) const { const LinearContainerFactor* jcf = dynamic_cast(&f); - return jcf && factor_->equals(*jcf->factor_, tol) && NonlinearFactor::equals(f); + if (!jcf || factor_->equals(*jcf->factor_, tol) || NonlinearFactor::equals(f)) + return false; + if (!linearizationPoint_ && !jcf->linearizationPoint_) + return true; + return jcf->linearizationPoint_ && linearizationPoint_->equals(*jcf->linearizationPoint_, tol); } /* ************************************************************************* */ double LinearContainerFactor::error(const Values& c) const { - // VectorValues vecvalues; - // // FIXME: add values correctly here - // return factor_.error(vecvalues); - return 0; // FIXME: placeholder + if (!linearizationPoint_) + return 0; + + // Extract subset of values for comparision + Values csub; + BOOST_FOREACH(const gtsam::Key& key, keys()) + csub.insert(key, c.at(key)); + + // create dummy ordering for evaluation + Ordering ordering = *csub.orderingArbitrary(); + VectorValues delta = linearizationPoint_->localCoordinates(csub, ordering); + + // Change keys on stored factor + BOOST_FOREACH(gtsam::Index& index, factor_->keys()) + index = ordering[index]; + + // compute error + double error = factor_->error(delta); + + // change keys back + factor_->keys() = keys(); + + return error; } /* ************************************************************************* */ diff --git a/gtsam_unstable/nonlinear/LinearContainerFactor.h b/gtsam_unstable/nonlinear/LinearContainerFactor.h index 25a1ed98b..9affcc29e 100644 --- a/gtsam_unstable/nonlinear/LinearContainerFactor.h +++ b/gtsam_unstable/nonlinear/LinearContainerFactor.h @@ -21,32 +21,40 @@ class LinearContainerFactor : public NonlinearFactor { protected: GaussianFactor::shared_ptr factor_; + boost::optional linearizationPoint_; public: /** Primary constructor: store a linear factor and decode the ordering */ - LinearContainerFactor(const JacobianFactor& factor, const Ordering& ordering); + LinearContainerFactor(const JacobianFactor& factor, const Ordering& ordering, + const Values& linearizationPoint = Values()); /** Primary constructor: store a linear factor and decode the ordering */ - LinearContainerFactor(const HessianFactor& factor, const Ordering& ordering); + LinearContainerFactor(const HessianFactor& factor, const Ordering& ordering, + const Values& linearizationPoint = Values()); /** Constructor from shared_ptr */ - LinearContainerFactor(const GaussianFactor::shared_ptr& factor, const Ordering& ordering); + LinearContainerFactor(const GaussianFactor::shared_ptr& factor, const Ordering& ordering, + const Values& linearizationPoint = Values()); /** Constructor from re-keyed factor: all indices assumed replaced with Key */ - LinearContainerFactor(const GaussianFactor::shared_ptr& factor); + LinearContainerFactor(const GaussianFactor::shared_ptr& factor, + const Values& linearizationPoint = Values()); /** Alternate constructor: store a linear factor and decode keys with inverted ordering*/ LinearContainerFactor(const JacobianFactor& factor, - const Ordering::InvertedMap& inverted_ordering); + const Ordering::InvertedMap& inverted_ordering, + const Values& linearizationPoint = Values()); /** Alternate constructor: store a linear factor and decode keys with inverted ordering*/ LinearContainerFactor(const HessianFactor& factor, - const Ordering::InvertedMap& inverted_ordering); + const Ordering::InvertedMap& inverted_ordering, + const Values& linearizationPoint = Values()); /** Constructor from shared_ptr with inverted ordering*/ LinearContainerFactor(const GaussianFactor::shared_ptr& factor, - const Ordering::InvertedMap& ordering); + const Ordering::InvertedMap& ordering, + const Values& linearizationPoint = Values()); // Access @@ -70,6 +78,9 @@ public: /** get the dimension of the factor: rows of linear factor */ size_t dim() const; + /** Extract the linearization point used in recalculating error */ + const boost::optional& linearizationPoint() const { return linearizationPoint_; } + /** Apply the ordering to a graph - same as linearize(), but without needing a linearization point */ GaussianFactor::shared_ptr order(const Ordering& ordering) const; @@ -125,6 +136,7 @@ public: protected: void rekeyFactor(const Ordering& ordering); void rekeyFactor(const Ordering::InvertedMap& invOrdering); + void initializeLinearizationPoint(const Values& linearizationPoint); }; // \class LinearContainerFactor diff --git a/gtsam_unstable/nonlinear/tests/testLinearContainerFactor.cpp b/gtsam_unstable/nonlinear/tests/testLinearContainerFactor.cpp index e85b880e8..1bce66ce3 100644 --- a/gtsam_unstable/nonlinear/tests/testLinearContainerFactor.cpp +++ b/gtsam_unstable/nonlinear/tests/testLinearContainerFactor.cpp @@ -70,6 +70,49 @@ TEST( testLinearContainerFactor, generic_jacobian_factor ) { EXPECT(assert_equal(*expLinFactor2.clone(), *actLinearizationB, tol)); } +/* ************************************************************************* */ +TEST( testLinearContainerFactor, jacobian_factor_withlinpoints ) { + + Ordering ordering; ordering += x1, x2, l1, l2; + + JacobianFactor expLinFactor( + ordering[l1], + Matrix_(2,2, + 2.74222, -0.0067457, + 0.0, 2.63624), + ordering[l2], + Matrix_(2,2, + -0.0455167, -0.0443573, + -0.0222154, -0.102489), + Vector_(2, 0.0277052, + -0.0533393), + diag_model2); + + Values values; + values.insert(l1, landmark1); + values.insert(l2, landmark2); + values.insert(x1, poseA1); + values.insert(x2, poseA2); + + LinearContainerFactor actFactor(expLinFactor, ordering, values); + + // Check contents + Values expLinPoint; + expLinPoint.insert(l1, landmark1); + expLinPoint.insert(l2, landmark2); + CHECK(actFactor.linearizationPoint()); + EXPECT(assert_equal(expLinPoint, *actFactor.linearizationPoint())); + + // Check error evaluation + VectorValues delta = values.zeroVectors(ordering); + delta.at(ordering[l1]) = Vector_(2, 1.0, 2.0); + delta.at(ordering[l2]) = Vector_(2, 3.0, 4.0); + Values noisyValues = values.retract(delta, ordering); + double expError = expLinFactor.error(delta); + EXPECT_DOUBLES_EQUAL(expError, actFactor.error(noisyValues), tol); + EXPECT_DOUBLES_EQUAL(expLinFactor.error(values.zeroVectors(ordering)), actFactor.error(values), tol); +} + /* ************************************************************************* */ TEST( testLinearContainerFactor, generic_hessian_factor ) { Matrix G11 = Matrix_(1,1, 1.0);