diff --git a/.cproject b/.cproject
index 5719b0da0..ff704cea8 100644
--- a/.cproject
+++ b/.cproject
@@ -526,6 +526,14 @@
true
true
+
+ make
+ -j4
+ testEvent.run
+ true
+ true
+ true
+
make
-j2
@@ -840,6 +848,14 @@
true
true
+
+ make
+ -j4
+ testTOAFactor.run
+ true
+ true
+ true
+
make
-j5
diff --git a/examples/Pose2SLAMExampleExpressions.cpp b/examples/Pose2SLAMExampleExpressions.cpp
index e9ccbb2cb..92f94c3f3 100644
--- a/examples/Pose2SLAMExampleExpressions.cpp
+++ b/examples/Pose2SLAMExampleExpressions.cpp
@@ -19,7 +19,7 @@
// The two new headers that allow using our Automatic Differentiation Expression framework
#include
-#include
+#include
// Header order is close to far
#include
@@ -35,28 +35,26 @@ using namespace gtsam;
int main(int argc, char** argv) {
// 1. Create a factor graph container and add factors to it
- NonlinearFactorGraph graph;
+ ExpressionFactorGraph graph;
// Create Expressions for unknowns
Pose2_ x1(1), x2(2), x3(3), x4(4), x5(5);
// 2a. Add a prior on the first pose, setting it to the origin
noiseModel::Diagonal::shared_ptr priorNoise = noiseModel::Diagonal::Sigmas(Vector3(0.3, 0.3, 0.1));
- graph.push_back(ExpressionFactor(priorNoise, Pose2(0, 0, 0), x1));
+ graph.addExpressionFactor(x1, Pose2(0, 0, 0), priorNoise);
// For simplicity, we will use the same noise model for odometry and loop closures
noiseModel::Diagonal::shared_ptr model = noiseModel::Diagonal::Sigmas(Vector3(0.2, 0.2, 0.1));
// 2b. Add odometry factors
- BinaryExpression::Function f = traits::Between;
- Expression(traits::Between, x1, x2);
- graph.push_back(ExpressionFactor(model, Pose2(2, 0, 0 ), between(x1,x2)));
- graph.push_back(ExpressionFactor(model, Pose2(2, 0, M_PI_2), between(x2,x3)));
- graph.push_back(ExpressionFactor(model, Pose2(2, 0, M_PI_2), between(x3,x4)));
- graph.push_back(ExpressionFactor(model, Pose2(2, 0, M_PI_2), between(x4,x5)));
+ graph.addExpressionFactor(between(x1,x2), Pose2(2, 0, 0 ), model);
+ graph.addExpressionFactor(between(x2,x3), Pose2(2, 0, M_PI_2), model);
+ graph.addExpressionFactor(between(x3,x4), Pose2(2, 0, M_PI_2), model);
+ graph.addExpressionFactor(between(x4,x5), Pose2(2, 0, M_PI_2), model);
// 2c. Add the loop closure constraint
- graph.push_back(ExpressionFactor(model, Pose2(2, 0, M_PI_2), between(x5,x2)));
+ graph.addExpressionFactor(between(x5,x2), Pose2(2, 0, M_PI_2), model);
graph.print("\nFactor Graph:\n"); // print
// 3. Create the data structure to hold the initialEstimate estimate to the solution
diff --git a/examples/SFMExampleExpressions.cpp b/examples/SFMExampleExpressions.cpp
index 0c750c81c..e9c9e920d 100644
--- a/examples/SFMExampleExpressions.cpp
+++ b/examples/SFMExampleExpressions.cpp
@@ -24,14 +24,11 @@
// The two new headers that allow using our Automatic Differentiation Expression framework
#include
-#include
+#include
// Header order is close to far
#include
-#include
-#include
#include
-#include
#include
#include
#include
@@ -40,27 +37,29 @@
using namespace std;
using namespace gtsam;
+using namespace noiseModel;
/* ************************************************************************* */
int main(int argc, char* argv[]) {
Cal3_S2 K(50.0, 50.0, 0.0, 50.0, 50.0);
- noiseModel::Isotropic::shared_ptr measurementNoise = noiseModel::Isotropic::Sigma(2, 1.0); // one pixel in u and v
+ Isotropic::shared_ptr measurementNoise = Isotropic::Sigma(2, 1.0); // one pixel in u and v
// Create the set of ground-truth landmarks and poses
vector points = createPoints();
vector poses = createPoses();
// Create a factor graph
- NonlinearFactorGraph graph;
+ ExpressionFactorGraph graph;
// Specify uncertainty on first pose prior
- noiseModel::Diagonal::shared_ptr poseNoise = noiseModel::Diagonal::Sigmas((Vector(6) << Vector3::Constant(0.3), Vector3::Constant(0.1)).finished());
+ Vector6 sigmas; sigmas << Vector3(0.3,0.3,0.3), Vector3(0.1,0.1,0.1);
+ Diagonal::shared_ptr poseNoise = Diagonal::Sigmas(sigmas);
// Here we don't use a PriorFactor but directly the ExpressionFactor class
- // The object x0 is an Expression, and we create a factor wanting it to be equal to poses[0]
+ // x0 is an Expression, and we create a factor wanting it to be equal to poses[0]
Pose3_ x0('x',0);
- graph.push_back(ExpressionFactor(poseNoise, poses[0], x0));
+ graph.addExpressionFactor(x0, poses[0], poseNoise);
// We create a constant Expression for the calibration here
Cal3_S2_ cK(K);
@@ -74,25 +73,26 @@ int main(int argc, char* argv[]) {
// Below an expression for the prediction of the measurement:
Point3_ p('l', j);
Point2_ prediction = uncalibrate(cK, project(transform_to(x, p)));
- // Again, here we use a ExpressionFactor
- graph.push_back(ExpressionFactor(measurementNoise, measurement, prediction));
+ // Again, here we use an ExpressionFactor
+ graph.addExpressionFactor(prediction, measurement, measurementNoise);
}
}
// Add prior on first point to constrain scale, again with ExpressionFactor
- noiseModel::Isotropic::shared_ptr pointNoise = noiseModel::Isotropic::Sigma(3, 0.1);
- graph.push_back(ExpressionFactor(pointNoise, points[0], Point3_('l', 0)));
+ Isotropic::shared_ptr pointNoise = Isotropic::Sigma(3, 0.1);
+ graph.addExpressionFactor(Point3_('l', 0), points[0], pointNoise);
// Create perturbed initial
- Values initialEstimate;
+ Values initial;
+ Pose3 delta(Rot3::rodriguez(-0.1, 0.2, 0.25), Point3(0.05, -0.10, 0.20));
for (size_t i = 0; i < poses.size(); ++i)
- initialEstimate.insert(Symbol('x', i), poses[i].compose(Pose3(Rot3::rodriguez(-0.1, 0.2, 0.25), Point3(0.05, -0.10, 0.20))));
+ initial.insert(Symbol('x', i), poses[i].compose(delta));
for (size_t j = 0; j < points.size(); ++j)
- initialEstimate.insert(Symbol('l', j), points[j].compose(Point3(-0.25, 0.20, 0.15)));
- cout << "initial error = " << graph.error(initialEstimate) << endl;
+ initial.insert(Symbol('l', j), points[j].compose(Point3(-0.25, 0.20, 0.15)));
+ cout << "initial error = " << graph.error(initial) << endl;
/* Optimize the graph and print results */
- Values result = DoglegOptimizer(graph, initialEstimate).optimize();
+ Values result = DoglegOptimizer(graph, initial).optimize();
cout << "final error = " << graph.error(result) << endl;
return 0;
diff --git a/gtsam/base/Lie.h b/gtsam/base/Lie.h
index 9c410ac25..bf2056cc8 100644
--- a/gtsam/base/Lie.h
+++ b/gtsam/base/Lie.h
@@ -110,7 +110,7 @@ struct LieGroup {
Class retract(const TangentVector& v, //
ChartJacobian H1, ChartJacobian H2 = boost::none) const {
Jacobian D_g_v;
- Class g = Class::ChartAtOrigin::Retract(v,D_g_v);
+ Class g = Class::ChartAtOrigin::Retract(v,H2 ? &D_g_v : 0);
Class h = compose(g,H1,H2);
if (H2) *H2 = (*H2) * D_g_v;
return h;
@@ -120,7 +120,7 @@ struct LieGroup {
ChartJacobian H1, ChartJacobian H2 = boost::none) const {
Class h = between(g,H1,H2);
Jacobian D_v_h;
- TangentVector v = Class::ChartAtOrigin::Local(h, D_v_h);
+ TangentVector v = Class::ChartAtOrigin::Local(h, (H1 || H2) ? &D_v_h : 0);
if (H1) *H1 = D_v_h * (*H1);
if (H2) *H2 = D_v_h * (*H2);
return v;
diff --git a/gtsam/base/numericalDerivative.h b/gtsam/base/numericalDerivative.h
index e5cfbdd3b..a7dc37d55 100644
--- a/gtsam/base/numericalDerivative.h
+++ b/gtsam/base/numericalDerivative.h
@@ -296,6 +296,48 @@ inline typename internal::FixedSizeMatrix::type numericalDerivative33(Y (*
x2, x3, delta);
}
+/**
+ * Compute numerical derivative in argument 1 of 4-argument function
+ * @param h ternary function yielding m-vector
+ * @param x1 n-dimensional first argument value
+ * @param x2 second argument value
+ * @param x3 third argument value
+ * @param x4 fourth argument value
+ * @param delta increment for numerical derivative
+ * @return m*n Jacobian computed via central differencing
+ */
+template
+typename internal::FixedSizeMatrix::type numericalDerivative41(
+ boost::function h, const X1& x1,
+ const X2& x2, const X3& x3, const X4& x4, double delta = 1e-5) {
+ BOOST_STATIC_ASSERT_MSG( (boost::is_base_of::structure_category>::value),
+ "Template argument Y must be a manifold type.");
+ BOOST_STATIC_ASSERT_MSG( (boost::is_base_of::structure_category>::value),
+ "Template argument X1 must be a manifold type.");
+ return numericalDerivative11(boost::bind(h, _1, x2, x3, x4), x1, delta);
+}
+
+/**
+ * Compute numerical derivative in argument 2 of 4-argument function
+ * @param h ternary function yielding m-vector
+ * @param x1 n-dimensional first argument value
+ * @param x2 second argument value
+ * @param x3 third argument value
+ * @param x4 fourth argument value
+ * @param delta increment for numerical derivative
+ * @return m*n Jacobian computed via central differencing
+ */
+template
+typename internal::FixedSizeMatrix::type numericalDerivative42(
+ boost::function h, const X1& x1,
+ const X2& x2, const X3& x3, const X4& x4, double delta = 1e-5) {
+ BOOST_STATIC_ASSERT_MSG( (boost::is_base_of::structure_category>::value),
+ "Template argument Y must be a manifold type.");
+ BOOST_STATIC_ASSERT_MSG( (boost::is_base_of::structure_category>::value),
+ "Template argument X1 must be a manifold type.");
+ return numericalDerivative11(boost::bind(h, x1, _1, x3, x4), x2, delta);
+}
+
/**
* Compute numerical Hessian matrix. Requires a single-argument Lie->scalar
* function. This is implemented simply as the derivative of the gradient.
diff --git a/gtsam/base/testLie.h b/gtsam/base/testLie.h
index 4bbca85ca..791d5c04d 100644
--- a/gtsam/base/testLie.h
+++ b/gtsam/base/testLie.h
@@ -34,23 +34,25 @@ void testLieGroupDerivatives(TestResult& result_, const std::string& name_,
Matrix H1, H2;
typedef traits T;
+ typedef OptionalJacobian OJ;
// Inverse
+ OJ none;
EXPECT(assert_equal(t1.inverse(),T::Inverse(t1, H1)));
- EXPECT(assert_equal(numericalDerivative11(T::Inverse, t1),H1));
+ EXPECT(assert_equal(numericalDerivative21(T::Inverse, t1, none),H1));
EXPECT(assert_equal(t2.inverse(),T::Inverse(t2, H1)));
- EXPECT(assert_equal(numericalDerivative11(T::Inverse, t2),H1));
+ EXPECT(assert_equal(numericalDerivative21(T::Inverse, t2, none),H1));
// Compose
EXPECT(assert_equal(t1 * t2,T::Compose(t1, t2, H1, H2)));
- EXPECT(assert_equal(numericalDerivative21(T::Compose, t1, t2), H1));
- EXPECT(assert_equal(numericalDerivative22(T::Compose, t1, t2), H2));
+ EXPECT(assert_equal(numericalDerivative41(T::Compose, t1, t2, none, none), H1));
+ EXPECT(assert_equal(numericalDerivative42(T::Compose, t1, t2, none, none), H2));
// Between
EXPECT(assert_equal(t1.inverse() * t2,T::Between(t1, t2, H1, H2)));
- EXPECT(assert_equal(numericalDerivative21(T::Between, t1, t2), H1));
- EXPECT(assert_equal(numericalDerivative22(T::Between, t1, t2), H2));
+ EXPECT(assert_equal(numericalDerivative41(T::Between, t1, t2, none, none), H1));
+ EXPECT(assert_equal(numericalDerivative42(T::Between, t1, t2, none, none), H2));
}
// Do a comprehensive test of Lie Group Chart derivatives
template
@@ -59,17 +61,20 @@ void testChartDerivatives(TestResult& result_, const std::string& name_,
Matrix H1, H2;
typedef traits T;
+ typedef typename G::TangentVector V;
+ typedef OptionalJacobian OJ;
// Retract
- typename G::TangentVector w12 = T::Local(t1, t2);
+ OJ none;
+ V w12 = T::Local(t1, t2);
EXPECT(assert_equal(t2, T::Retract(t1,w12, H1, H2)));
- EXPECT(assert_equal(numericalDerivative21(T::Retract, t1, w12), H1));
- EXPECT(assert_equal(numericalDerivative22(T::Retract, t1, w12), H2));
+ EXPECT(assert_equal(numericalDerivative41(T::Retract, t1, w12, none, none), H1));
+ EXPECT(assert_equal(numericalDerivative42(T::Retract, t1, w12, none, none), H2));
// Local
EXPECT(assert_equal(w12, t1.localCoordinates(t2, H1, H2)));
- EXPECT(assert_equal(numericalDerivative21(T::Local, t1, t2), H1));
- EXPECT(assert_equal(numericalDerivative22(T::Local, t1, t2), H2));
+ EXPECT(assert_equal(numericalDerivative41(T::Local, t1, t2, none, none), H1));
+ EXPECT(assert_equal(numericalDerivative42(T::Local, t1, t2, none, none), H2));
}
} // namespace gtsam
diff --git a/gtsam/geometry/Point2.h b/gtsam/geometry/Point2.h
index 01a6d6052..6f4f93cf9 100644
--- a/gtsam/geometry/Point2.h
+++ b/gtsam/geometry/Point2.h
@@ -165,12 +165,12 @@ public:
/// @{
inline void operator += (const Point2& q) {x_+=q.x_;y_+=q.y_;}
inline void operator *= (double s) {x_*=s;y_*=s;}
- Point2 inverse() { return -(*this);}
- Point2 compose(const Point2& q) { return (*this)+q;}
- Point2 between(const Point2& q) { return q-(*this);}
- Vector2 localCoordinates(const Point2& q) { return between(q).vector();}
- Point2 retract(const Vector2& v) {return compose(Point2(v));}
- static Vector2 Logmap(const Point2& p) {return p.vector();}
+ Point2 inverse() const { return -(*this);}
+ Point2 compose(const Point2& q) const { return (*this)+q;}
+ Point2 between(const Point2& q) const { return q-(*this);}
+ Vector2 localCoordinates(const Point2& q) const { return between(q).vector();}
+ Point2 retract(const Vector2& v) const { return compose(Point2(v));}
+ static Vector2 Logmap(const Point2& p) { return p.vector();}
static Point2 Expmap(const Vector2& v) { return Point2(v);}
/// @}
diff --git a/gtsam/geometry/Point3.h b/gtsam/geometry/Point3.h
index 5b133dc60..c9dee9003 100644
--- a/gtsam/geometry/Point3.h
+++ b/gtsam/geometry/Point3.h
@@ -164,12 +164,12 @@ namespace gtsam {
/// @name Deprecated
/// @{
- Point3 inverse() { return -(*this);}
- Point3 compose(const Point3& q) { return (*this)+q;}
- Point3 between(const Point3& q) { return q-(*this);}
- Vector3 localCoordinates(const Point3& q) { return between(q).vector();}
- Point3 retract(const Vector3& v) {return compose(Point3(v));}
- static Vector3 Logmap(const Point3& p) {return p.vector();}
+ Point3 inverse() const { return -(*this);}
+ Point3 compose(const Point3& q) const { return (*this)+q;}
+ Point3 between(const Point3& q) const { return q-(*this);}
+ Vector3 localCoordinates(const Point3& q) const { return between(q).vector();}
+ Point3 retract(const Vector3& v) const { return compose(Point3(v));}
+ static Vector3 Logmap(const Point3& p) { return p.vector();}
static Point3 Expmap(const Vector3& v) { return Point3(v);}
/// @}
diff --git a/gtsam/geometry/tests/testSO3.cpp b/gtsam/geometry/tests/testSO3.cpp
index 3d8e41af5..0fe699116 100644
--- a/gtsam/geometry/tests/testSO3.cpp
+++ b/gtsam/geometry/tests/testSO3.cpp
@@ -55,46 +55,6 @@ TEST(SO3 , Retract) {
EXPECT(actual.isApprox(R2));
}
-//******************************************************************************
-TEST(SO3 , Compose) {
- SO3 expected = R1 * R2;
- Matrix actualH1, actualH2;
- SO3 actual = traits::Compose(R1, R2, actualH1, actualH2);
- EXPECT(traits::Equals(expected,actual));
-
- Matrix numericalH1 = numericalDerivative21(traits::Compose, R1, R2);
- EXPECT(assert_equal(numericalH1,actualH1));
-
- Matrix numericalH2 = numericalDerivative22(traits::Compose, R1, R2);
- EXPECT(assert_equal(numericalH2,actualH2));
-}
-
-//******************************************************************************
-TEST(SO3 , Between) {
- SO3 expected = R1.inverse() * R2;
- Matrix actualH1, actualH2;
- SO3 actual = traits::Between(R1, R2, actualH1, actualH2);
- EXPECT(traits::Equals(expected,actual));
-
- Matrix numericalH1 = numericalDerivative21(traits::Between, R1, R2);
- EXPECT(assert_equal(numericalH1,actualH1));
-
- Matrix numericalH2 = numericalDerivative22(traits::Between, R1, R2);
- EXPECT(assert_equal(numericalH2,actualH2));
-}
-
-//******************************************************************************
-TEST(SO3 , Inverse) {
- SO3 expected(Eigen::AngleAxisd(-0.1, z_axis));
-
- Matrix actualH;
- SO3 actual = traits::Inverse(R1, actualH);
- EXPECT(traits::Equals(expected,actual));
-
- Matrix numericalH = numericalDerivative11(traits::Inverse, R1);
- EXPECT(assert_equal(numericalH,actualH));
-}
-
//******************************************************************************
TEST(SO3 , Invariants) {
check_group_invariants(id,id);
diff --git a/gtsam/nonlinear/Expression-inl.h b/gtsam/nonlinear/Expression-inl.h
index 0b3dea645..a86e7312a 100644
--- a/gtsam/nonlinear/Expression-inl.h
+++ b/gtsam/nonlinear/Expression-inl.h
@@ -32,6 +32,7 @@
#include
namespace MPL = boost::mpl::placeholders;
+#include // operator typeid
#include